Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Import from Sourceforge.net

  • Loading branch information...
commit 75ac2e33f49ecf8ae30cfe52c906314043c4f543 0 parents
@jfmoy authored
Showing with 26,498 additions and 0 deletions.
  1. +28 −0 Classes/NSImage+Smultron.h
  2. +110 −0 Classes/NSImage+Smultron.m
  3. +26 −0 Classes/NSString+Smultron.h
  4. +111 −0 Classes/NSString+Smultron.m
  5. +25 −0 Classes/NSToolbarItem+Smultron.h
  6. +87 −0 Classes/NSToolbarItem+Smultron.m
  7. +66 −0 Classes/SMLAdvancedFindController.h
  8. +693 −0 Classes/SMLAdvancedFindController.m
  9. +22 −0 Classes/SMLAdvancedFindPanel.h
  10. +32 −0 Classes/SMLAdvancedFindPanel.m
  11. +27 −0 Classes/SMLApplication.h
  12. +249 −0 Classes/SMLApplication.m
  13. +48 −0 Classes/SMLApplicationDelegate.h
  14. +456 −0 Classes/SMLApplicationDelegate.m
  15. +24 −0 Classes/SMLApplicationMenuController.h
  16. +29 −0 Classes/SMLApplicationMenuController.m
  17. +29 −0 Classes/SMLAuthenticationController.h
  18. +185 −0 Classes/SMLAuthenticationController.m
  19. +42 −0 Classes/SMLBasicPerformer.h
  20. +261 −0 Classes/SMLBasicPerformer.m
  21. +22 −0 Classes/SMLCommandCollectionManagedObject.h
  22. +45 −0 Classes/SMLCommandCollectionManagedObject.m
  23. +22 −0 Classes/SMLCommandManagedObject.h
  24. +56 −0 Classes/SMLCommandManagedObject.m
  25. +79 −0 Classes/SMLCommandsController.h
  26. +511 −0 Classes/SMLCommandsController.m
  27. +22 −0 Classes/SMLDocumentManagedObject.h
  28. +46 −0 Classes/SMLDocumentManagedObject.m
  29. +29 −0 Classes/SMLDocumentsListCell.h
  30. +118 −0 Classes/SMLDocumentsListCell.m
  31. +28 −0 Classes/SMLDocumentsMenuController.h
  32. +151 −0 Classes/SMLDocumentsMenuController.m
  33. +30 −0 Classes/SMLDragAndDropController.h
  34. +413 −0 Classes/SMLDragAndDropController.m
  35. +33 −0 Classes/SMLDummyView.h
  36. +84 −0 Classes/SMLDummyView.m
  37. +32 −0 Classes/SMLEditMenuController.h
  38. +126 −0 Classes/SMLEditMenuController.m
  39. +22 −0 Classes/SMLEncodingManagedObject.h
  40. +49 −0 Classes/SMLEncodingManagedObject.m
  41. +72 −0 Classes/SMLExtraInterfaceController.h
  42. +237 −0 Classes/SMLExtraInterfaceController.m
  43. +46 −0 Classes/SMLFileMenuController.h
  44. +410 −0 Classes/SMLFileMenuController.m
  45. +22 −0 Classes/SMLFontTransformer.h
  46. +40 −0 Classes/SMLFontTransformer.m
  47. +27 −0 Classes/SMLFullScreenWindow.h
  48. +87 −0 Classes/SMLFullScreenWindow.m
  49. +23 −0 Classes/SMLGradientBackgroundView.h
  50. +47 −0 Classes/SMLGradientBackgroundView.m
  51. +22 −0 Classes/SMLGutterTextView.h
  52. +84 −0 Classes/SMLGutterTextView.m
  53. +24 −0 Classes/SMLHelpMenuController.h
  54. +63 −0 Classes/SMLHelpMenuController.m
  55. +52 −0 Classes/SMLInfoController.h
  56. +194 −0 Classes/SMLInfoController.m
  57. +73 −0 Classes/SMLInterfacePerformer.h
  58. +710 −0 Classes/SMLInterfacePerformer.m
  59. +37 −0 Classes/SMLLayoutManager.h
  60. +92 −0 Classes/SMLLayoutManager.m
  61. +59 −0 Classes/SMLLineNumbers.h
  62. +184 −0 Classes/SMLLineNumbers.m
  63. +40 −0 Classes/SMLMainController.h
  64. +144 −0 Classes/SMLMainController.m
  65. +39 −0 Classes/SMLOpenSavePerformer.h
  66. +606 −0 Classes/SMLOpenSavePerformer.m
  67. +73 −0 Classes/SMLPreferencesController.h
  68. +621 −0 Classes/SMLPreferencesController.m
  69. +37 −0 Classes/SMLPreviewController.h
  70. +163 −0 Classes/SMLPreviewController.m
  71. +25 −0 Classes/SMLPrintTextView.h
  72. +162 −0 Classes/SMLPrintTextView.m
  73. +33 −0 Classes/SMLPrintViewController.h
  74. +83 −0 Classes/SMLPrintViewController.m
  75. +33 −0 Classes/SMLProject+DocumentViewsController.h
  76. +302 −0 Classes/SMLProject+DocumentViewsController.m
  77. +22 −0 Classes/SMLProject+TableViewDelegate.h
  78. +112 −0 Classes/SMLProject+TableViewDelegate.m
  79. +41 −0 Classes/SMLProject+ToolbarController.h
  80. +536 −0 Classes/SMLProject+ToolbarController.m
  81. +154 −0 Classes/SMLProject.h
  82. +866 −0 Classes/SMLProject.m
  83. +22 −0 Classes/SMLProjectWindow.h
  84. +32 −0 Classes/SMLProjectWindow.m
  85. +39 −0 Classes/SMLProjectsController.h
  86. +239 −0 Classes/SMLProjectsController.m
  87. +22 −0 Classes/SMLSearchField.h
  88. +47 −0 Classes/SMLSearchField.m
  89. +24 −0 Classes/SMLServicesController.h
  90. +101 −0 Classes/SMLServicesController.m
  91. +35 −0 Classes/SMLShortcutsController.h
  92. +264 −0 Classes/SMLShortcutsController.m
  93. +22 −0 Classes/SMLSingleDocumentPanel.h
  94. +23 −0 Classes/SMLSingleDocumentPanel.m
  95. +24 −0 Classes/SMLSingleDocumentWindowDelegate.h
  96. +89 −0 Classes/SMLSingleDocumentWindowDelegate.m
  97. +22 −0 Classes/SMLSnippetCollectionManagedObject.h
  98. +47 −0 Classes/SMLSnippetCollectionManagedObject.m
  99. +22 −0 Classes/SMLSnippetManagedObject.h
  100. +58 −0 Classes/SMLSnippetManagedObject.m
  101. +55 −0 Classes/SMLSnippetsController.h
  102. +364 −0 Classes/SMLSnippetsController.m
  103. +23 −0 Classes/SMLSplitView.h
  104. +56 −0 Classes/SMLSplitView.m
  105. +169 −0 Classes/SMLStandardHeader.h
  106. +150 −0 Classes/SMLSyntaxColouring.h
  107. +1,331 −0 Classes/SMLSyntaxColouring.m
  108. +22 −0 Classes/SMLSyntaxDefinitionManagedObject.h
  109. +50 −0 Classes/SMLSyntaxDefinitionManagedObject.m
  110. +21 −0 Classes/SMLTableView.h
  111. +147 −0 Classes/SMLTableView.m
  112. +54 −0 Classes/SMLTextMenuController.h
  113. +1,025 −0 Classes/SMLTextMenuController.m
  114. +39 −0 Classes/SMLTextPerformer.h
  115. +152 −0 Classes/SMLTextPerformer.m
  116. +46 −0 Classes/SMLTextView.h
  117. +654 −0 Classes/SMLTextView.m
  118. +62 −0 Classes/SMLToolsMenuController.h
  119. +474 −0 Classes/SMLToolsMenuController.m
  120. +71 −0 Classes/SMLVariousPerformer.h
  121. +708 −0 Classes/SMLVariousPerformer.m
  122. +48 −0 Classes/SMLViewMenuController.h
  123. +509 −0 Classes/SMLViewMenuController.m
  124. +13 −0 Classes/main.m
  125. +27 −0 Command Line Utility/smultron.1
  126. +50 −0 Command Line Utility/smultron_main.m
  127. BIN  Graphics/Preferences Icons/SMLAppearanceIcon.pdf
  128. BIN  Graphics/Preferences Icons/SMLOpenSaveIcon.pdf
  129. BIN  Graphics/SMLCommandsIcon.icns
  130. BIN  Graphics/SMLDefaultIcon.png
  131. BIN  Graphics/SMLDefaultUnsavedIcon.png
  132. BIN  Graphics/SMLDocumentIcon.icns
  133. BIN  Graphics/SMLMainIcon.icns
  134. BIN  Graphics/SMLProjectIcon.icns
  135. BIN  Graphics/SMLSnippetsIcon.icns
  136. BIN  Graphics/Tab Bar/SMLTabBarClose.pdf
  137. BIN  Graphics/Tab Bar/SMLTabBarClosePressed.pdf
  138. BIN  Graphics/Tab Bar/SMLTabBarCloseRollover.pdf
  139. BIN  Graphics/Tab Bar/SMLTabBarOverflow.pdf
  140. BIN  Graphics/Tab Bar/SMLTabBarOverflowPressed.pdf
  141. BIN  Graphics/Toolbar Icons/SMLAdvancedFindIcon.pdf
  142. BIN  Graphics/Toolbar Icons/SMLCloseIcon.pdf
  143. BIN  Graphics/Toolbar Icons/SMLFunctionIcon.pdf
  144. BIN  Graphics/Toolbar Icons/SMLInfoIcon.pdf
  145. BIN  Graphics/Toolbar Icons/SMLNewCollectionIcon.pdf
  146. BIN  Graphics/Toolbar Icons/SMLNewIcon.pdf
  147. BIN  Graphics/Toolbar Icons/SMLOpenIcon.pdf
  148. BIN  Graphics/Toolbar Icons/SMLPreviewIcon.pdf
  149. BIN  Graphics/Toolbar Icons/SMLRunIcon.pdf
  150. BIN  Graphics/Toolbar Icons/SMLSaveIcon.pdf
  151. +127 −0 ICU/ICUMatcher.h
  152. +228 −0 ICU/ICUMatcher.m
  153. +115 −0 ICU/ICUPattern.h
  154. +242 −0 ICU/ICUPattern.m
  155. +25 −0 ICU/LICENSE.txt
  156. +78 −0 ICU/NSStringICUAdditions.h
  157. +96 −0 ICU/NSStringICUAdditions.m
  158. +51 −0 ICU/icu/LICENSE.html
  159. +88 −0 ICU/icu/unicode/parseerr.h
  160. +267 −0 ICU/icu/unicode/platform.h
  161. +180 −0 ICU/icu/unicode/putil.h
  162. +186 −0 ICU/icu/unicode/uconfig.h
  163. +246 −0 ICU/icu/unicode/udraft.h
  164. +707 −0 ICU/icu/unicode/uiter.h
  165. +371 −0 ICU/icu/unicode/umachine.h
  166. +630 −0 ICU/icu/unicode/uregex.h
  167. +1,471 −0 ICU/icu/unicode/urename.h
  168. +1,320 −0 ICU/icu/unicode/ustring.h
  169. +221 −0 ICU/icu/unicode/utf.h
  170. +605 −0 ICU/icu/unicode/utf16.h
  171. +627 −0 ICU/icu/unicode/utf8.h
Sorry, we could not display the entire diff because too many files (328) changed.
28 Classes/NSImage+Smultron.h
@@ -0,0 +1,28 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface NSImage (NSImageSmultron)
+
++ (NSArray *)iconsForPath:(NSString *)path;
+
++ (NSArray *)quickLookIconForPath:(NSString *)path;
+
++ (CIImage *)unsavedFilterForCIImage:(CIImage *)ciImage;
+
+//+ (NSBitmapImageRep *)unsavedIconBitmapRep:(NSBitmapImageRep *)bitmapImageRep;
+
+@end
110 Classes/NSImage+Smultron.m
@@ -0,0 +1,110 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "NSImage+Smultron.h"
+#import "SMLStandardHeader.h"
+#import "SMLVariousPerformer.h"
+
+@implementation NSImage (NSImageSmultron)
+
++ (NSArray *)iconsForPath:(NSString *)path
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSArray *iconsArray;
+ if ([[SMLDefaults valueForKey:@"UseQuickLookIcon"] boolValue] == YES) {
+ iconsArray = [NSImage quickLookIconForPath:path];
+ if (iconsArray != nil && [iconsArray count] > 0) {
+ [pool drain];
+ return iconsArray;
+ }
+ }
+
+ NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile:path];
+
+ //NSImageRep *imageRep = [temporaryIcon bestRepresentationForRect:NSMakeRect(0.0, 0.0, 128, 128) context:nil hints:nil];
+//
+// unsigned char *bitmapData = [imageRep bitmapData];
+//
+// NSBitmapImageRep *imageRep2 = [NSBitmapImageRep imageRepWithData:[NSData dataWithBytes:bitmapData length:sizeof(bitmapData)]];
+
+ //NSSize iconSize = NSMakeSize([icon pixelsWide], [icon pixelsHigh]);
+ //NSImage *icon = [[NSImage alloc] initWithSize:iconSize];
+
+ //[icon addRepresentation:imageRep];
+
+ [icon setSize:NSMakeSize(ICON_MAX_SIZE, ICON_MAX_SIZE)]; // This makes sure that unsavedIcon will not get "fuzzy"
+
+ NSImage *unsavedIcon = [[NSImage alloc] initWithSize:[icon size]];
+ //Log(imageRep);
+ CIImage *ciImage = [CIImage imageWithData:[icon TIFFRepresentation]];
+ //Log(ciImage);
+ [unsavedIcon addRepresentation:[NSCIImageRep imageRepWithCIImage:[NSImage unsavedFilterForCIImage:ciImage]]];
+ [unsavedIcon setSize:NSMakeSize(ICON_MAX_SIZE, ICON_MAX_SIZE)];
+ [unsavedIcon setScalesWhenResized:YES];
+ iconsArray = [NSArray arrayWithObjects:icon, unsavedIcon, nil];
+ [pool drain];
+
+ return iconsArray;
+}
+
+
++ (NSArray *)quickLookIconForPath:(NSString *)path
+{
+ // Thanks to Matt Gemmel (http://mattgemmell.com/) for the basics of this code
+
+ NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],(NSString *)kQLThumbnailOptionIconModeKey, nil];
+ CGImageRef imageRef = QLThumbnailImageCreate(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:path], CGSizeMake(ICON_MAX_SIZE, ICON_MAX_SIZE), (CFDictionaryRef)options);
+ NSMakeCollectable(imageRef);
+
+ if (imageRef != NULL) {
+ NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
+
+ if (bitmapImageRep != nil) {
+
+ NSSize iconSize = NSMakeSize([bitmapImageRep pixelsWide], [bitmapImageRep pixelsHigh]);
+ NSImage *icon = [[NSImage alloc] initWithSize:iconSize];
+
+ [icon addRepresentation:bitmapImageRep];
+ NSImage *unsavedIcon = [[NSImage alloc] initWithSize:iconSize];
+ CIImage *ciImage = [[CIImage alloc] initWithBitmapImageRep:bitmapImageRep];
+ [unsavedIcon addRepresentation:[NSCIImageRep imageRepWithCIImage:[NSImage unsavedFilterForCIImage:ciImage]]];
+
+ [icon setScalesWhenResized:YES];
+ [unsavedIcon setScalesWhenResized:YES];
+
+ return [NSArray arrayWithObjects:icon, unsavedIcon, nil];
+ }
+ }
+
+ return nil;
+}
+
+
++ (CIImage *)unsavedFilterForCIImage:(CIImage *)ciImage
+{
+ CIFilter *filter1 = [CIFilter filterWithName:@"CIColorControls"];
+ [filter1 setDefaults];
+ [filter1 setValue:ciImage forKey:@"inputImage"];
+ [filter1 setValue:[NSNumber numberWithFloat:-0.1] forKey:@"inputBrightness"];
+
+ CIFilter *filter2 = [CIFilter filterWithName:@"CISepiaTone"];
+ [filter2 setDefaults];
+ [filter2 setValue:[filter1 valueForKey:@"outputImage"] forKey:@"inputImage"];
+ [filter2 setValue:[NSNumber numberWithFloat:0.9] forKey:@"inputIntensity"];
+
+ return [filter2 valueForKey:@"outputImage"];
+}
+
+
+@end
26 Classes/NSString+Smultron.h
@@ -0,0 +1,26 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface NSString (NSStringSmultron)
+
++ (NSString *)dateStringForDate:(NSCalendarDate *)date formatIndex:(NSInteger)index;
+
+- (NSArray *)divideCommandIntoArray;
+
+
+
+@end
111 Classes/NSString+Smultron.m
@@ -0,0 +1,111 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "NSString+Smultron.h"
+
+#import "SMLStandardHeader.h"
+
+@implementation NSString (NSStringSmultron)
+
+
++ (NSString *)dateStringForDate:(NSCalendarDate *)date formatIndex:(NSInteger)index
+{
+ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
+ [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
+
+ if (index == 1) {
+ [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm Z"];
+ } else if (index == 2) {
+ [dateFormatter setDateStyle:NSDateFormatterShortStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+ } else if (index == 3) {
+ [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+ } else if (index == 4) {
+ [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
+ } else if (index == 5) {
+ [dateFormatter setDateStyle:NSDateFormatterLongStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
+ } else if (index == 6) {
+ [dateFormatter setDateStyle:NSDateFormatterLongStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterLongStyle];
+ } else if (index == 7) {
+ [dateFormatter setDateStyle:NSDateFormatterFullStyle];
+ [dateFormatter setTimeStyle:NSDateFormatterFullStyle];
+ } else if (index == 8) {
+ [dateFormatter setDateFormat:[SMLDefaults valueForKey:@"UserDateFormat"]];
+ } else {
+ [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm"];
+ }
+
+ return [dateFormatter stringFromDate:date];
+}
+
+
+- (NSArray *)divideCommandIntoArray
+{
+ if ([self rangeOfString:@"\""].location == NSNotFound && [self rangeOfString:@"'"].location == NSNotFound) {
+ return [self componentsSeparatedByString:@" "];
+ } else {
+ NSMutableArray *returnArray = [NSMutableArray array];
+ NSScanner *scanner = [NSScanner scannerWithString:self];
+ NSInteger location = 0;
+ NSInteger commandLength = [self length];
+ NSInteger beginning;
+ NSInteger savedBeginning = -1;
+ NSString *characterToScanFor;
+
+ while (location < commandLength) {
+ if (savedBeginning == -1) {
+ beginning = location;
+ } else {
+ beginning = savedBeginning;
+ savedBeginning = -1;
+ }
+ if ([self characterAtIndex:location] == '"') {
+ characterToScanFor = @"\"";
+ beginning++;
+ location++;
+ } else if ([self characterAtIndex:location] == '\'') {
+ characterToScanFor = @"'";
+ beginning++;
+ location++;
+ } else {
+ characterToScanFor = @" ";
+ }
+
+ [scanner setScanLocation:location];
+ if ([scanner scanUpToString:characterToScanFor intoString:nil]) {
+ if (![characterToScanFor isEqualToString:@" "] && [self characterAtIndex:([scanner scanLocation] - 1)] == '\\') {
+ location = [scanner scanLocation];
+ savedBeginning = beginning - 1;
+ continue;
+ }
+ location = [scanner scanLocation];
+ } else {
+ location = commandLength - 1;
+ }
+
+ [returnArray addObject:[self substringWithRange:NSMakeRange(beginning, location - beginning)]];
+ location++;
+ }
+ return (NSArray *)returnArray;
+ }
+}
+
+
+
+
+@end
25 Classes/NSToolbarItem+Smultron.h
@@ -0,0 +1,25 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface NSToolbarItem (NSToolbarItemSmultron)
+
++ (NSToolbarItem *)createToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name image:(NSImage *)image action:(SEL)selector tag:(NSInteger)tag target:(id)target;
+
++ (NSToolbarItem *)createPreferencesToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name image:(NSImage *)image action:(SEL)selector target:(id)target;
+
++ (NSToolbarItem *)createSeachFieldToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name view:(NSView *)view;
+@end
87 Classes/NSToolbarItem+Smultron.m
@@ -0,0 +1,87 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "NSToolbarItem+Smultron.h"
+
+
+@implementation NSToolbarItem (NSToolbarItemSmultron)
+
+
++ (NSToolbarItem *)createToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name image:(NSImage *)image action:(SEL)selector tag:(NSInteger)tag target:(id)target
+{
+ NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+
+// [toolbarItem setLabel:name];
+// [toolbarItem setPaletteLabel:name];
+// [toolbarItem setToolTip:name];
+// [toolbarItem setTag:tag];
+//
+// [toolbarItem setImage:image];
+// [toolbarItem setTarget:target];
+// [toolbarItem setAction:selector];
+
+ NSRect toolbarItemRect = NSMakeRect(0.0, 0.0, 28.0, 27.0);
+
+ NSView *view = [[NSView alloc] initWithFrame:toolbarItemRect];
+ NSButton *button = [[NSButton alloc] initWithFrame:toolbarItemRect];
+ [button setBezelStyle:NSTexturedRoundedBezelStyle];
+ [button setTitle:@""];
+ [button setImage:image];
+ [button setTarget:target];
+ [button setAction:selector];
+ [[button cell] setImageScaling:NSImageScaleProportionallyDown];
+ [button setImagePosition:NSImageOnly];
+
+ [toolbarItem setLabel:name];
+ [toolbarItem setPaletteLabel:name];
+ [toolbarItem setToolTip:name];
+
+ [view addSubview:button];
+
+ [toolbarItem setTag:tag];
+ [toolbarItem setView:view];
+
+ return toolbarItem;
+}
+
+
++ (NSToolbarItem *)createPreferencesToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name image:(NSImage *)image action:(SEL)selector target:(id)target
+{
+ NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+
+ [toolbarItem setLabel:name];
+ [toolbarItem setPaletteLabel:name];
+ [toolbarItem setToolTip:name];
+
+ [toolbarItem setImage:image];
+ [toolbarItem setTarget:target];
+ [toolbarItem setAction:selector];
+
+ return toolbarItem;
+}
+
+
++ (NSToolbarItem *)createSeachFieldToolbarItemWithIdentifier:(NSString *)itemIdentifier name:(NSString *)name view:(NSView *)view
+{
+ NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
+ [toolbarItem setLabel:name];
+ [toolbarItem setToolTip:name];
+ [toolbarItem setPaletteLabel:name];
+ [toolbarItem setView:view];
+ [toolbarItem setMinSize:NSMakeSize(70, 32)];
+ [toolbarItem setMaxSize:NSMakeSize(200, 32)];
+
+ return toolbarItem;
+}
+@end
66 Classes/SMLAdvancedFindController.h
@@ -0,0 +1,66 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SMLAdvancedFindController : NSObject <NSOutlineViewDelegate>
+{
+ IBOutlet NSWindow *advancedFindWindow;
+ IBOutlet NSSearchField *findSearchField;
+ IBOutlet NSSearchField *replaceSearchField;
+ IBOutlet NSTextField *findResultTextField;
+ IBOutlet NSOutlineView *findResultsOutlineView;
+ IBOutlet NSView *resultDocumentContentView;
+ IBOutlet NSTreeController *findResultsTreeController;
+
+ IBOutlet NSSplitView *advancedFindSplitView;
+
+ IBOutlet NSButton *currentDocumentScope;
+ IBOutlet NSButton *currentProjectScope;
+ IBOutlet NSButton *allDocumentsScope;
+
+ id currentlyDisplayedDocumentInAdvancedFind;
+}
+
+@property (assign) id currentlyDisplayedDocumentInAdvancedFind;
+@property (readonly) IBOutlet NSWindow *advancedFindWindow;
+@property (readonly) IBOutlet NSOutlineView *findResultsOutlineView;
+
++ (SMLAdvancedFindController *)sharedInstance;
+
+- (IBAction)findAction:(id)sender;
+- (IBAction)replaceAction:(id)sender;
+
+- (void)performNumberOfReplaces:(NSInteger)numberOfReplaces;
+
+- (void)showAdvancedFindWindow;
+
+- (NSEnumerator *)scopeEnumerator;
+
+- (void)removeCurrentlyDisplayedDocumentInAdvancedFind;
+
+- (NSView *)resultDocumentContentView;
+
+- (NSManagedObjectContext *)managedObjectContext;
+
+- (NSMutableDictionary *)preparedResultDictionaryFromString:(NSString *)completeString searchStringLength:(NSInteger)searchStringLength range:(NSRange)foundRange lineNumber:(NSInteger)lineNumber document:(id)document;
+
+- (void)alertThatThisIsNotAValidRegularExpression:(NSString *)string;
+
+- (void)searchScopeChanged:(id)sender;
+
+- (IBAction)showRegularExpressionsHelpPanelAction:(id)sender;
+
+@end
693 Classes/SMLAdvancedFindController.m
@@ -0,0 +1,693 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "SMLStandardHeader.h"
+
+#import "SMLAdvancedFindController.h"
+
+#import "ICUPattern.h"
+#import "ICUMatcher.h"
+#import "NSStringICUAdditions.h"
+#import "SMLExtraInterfaceController.h"
+#import "SMLProjectsController.h"
+#import "SMLBasicPerformer.h"
+#import "SMLApplicationDelegate.h"
+#import "SMLInterfacePerformer.h"
+#import "SMLLineNumbers.h"
+#import "SMLProject.h"
+#import "SMLTextPerformer.h"
+
+@implementation SMLAdvancedFindController
+
+@synthesize currentlyDisplayedDocumentInAdvancedFind, advancedFindWindow, findResultsOutlineView;
+
+static id sharedInstance = nil;
+
++ (SMLAdvancedFindController *)sharedInstance
+{
+ if (sharedInstance == nil) {
+ sharedInstance = [[self alloc] init];
+ }
+
+ return sharedInstance;
+}
+
+
+- (id)init
+{
+ if (sharedInstance == nil) {
+ sharedInstance = [super init];
+ }
+ return sharedInstance;
+}
+
+
+- (IBAction)findAction:(id)sender
+{
+ NSString *searchString = [findSearchField stringValue];
+
+ [findResultsOutlineView setDelegate:nil];
+
+ [findResultsTreeController setContent:nil];
+ [findResultsTreeController setContent:[NSMutableArray array]];
+
+ NSMutableArray *recentSearches = [[NSMutableArray alloc] initWithArray:[findSearchField recentSearches]];
+ if ([recentSearches indexOfObject:searchString] != NSNotFound) {
+ [recentSearches removeObject:searchString];
+ }
+ [recentSearches insertObject:searchString atIndex:0];
+ if ([recentSearches count] > 15) {
+ [recentSearches removeLastObject];
+ }
+ [findSearchField setRecentSearches:recentSearches];
+
+ NSInteger searchStringLength = [searchString length];
+ if (!searchStringLength > 0 || SMLCurrentDocument == nil || SMLCurrentProject == nil) {
+ NSBeep();
+ return;
+ }
+
+ NSString *completeString;
+ NSInteger completeStringLength;
+ NSInteger startLocation;
+ NSInteger resultsInThisDocument = 0;
+ NSInteger lineNumber;
+ NSInteger index;
+ NSInteger numberOfResults = 0;
+ NSRange foundRange;
+ NSRange searchRange;
+ NSIndexPath *folderIndexPath;
+ NSMutableDictionary *node;
+
+ NSEnumerator *enumerator = [self scopeEnumerator];
+
+ NSInteger documentIndex = 0;
+ for (id document in enumerator) {
+ node = [NSMutableDictionary dictionary];
+ if ([[SMLDefaults valueForKey:@"ShowFullPathInWindowTitle"] boolValue] == YES) {
+ [node setValue:[document valueForKey:@"nameWithPath"] forKey:@"displayString"];
+ } else {
+ [node setValue:[document valueForKey:@"name"] forKey:@"displayString"];
+ }
+ [node setValue:[NSNumber numberWithBool:NO] forKey:@"isLeaf"];
+ [node setValue:[SMLBasic uriFromObject:document] forKey:@"document"];
+ folderIndexPath = [[NSIndexPath alloc] initWithIndex:documentIndex];
+ [findResultsTreeController insertObject:node atArrangedObjectIndexPath:folderIndexPath];
+
+ documentIndex++;
+
+ completeString = [[document valueForKey:@"firstTextView"] string];
+ searchRange = [[document valueForKey:@"firstTextView"] selectedRange];
+ completeStringLength = [completeString length];
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ searchRange = NSMakeRange(0, completeStringLength);
+ }
+ startLocation = searchRange.location;
+ resultsInThisDocument = 0;
+
+ if ([[SMLDefaults valueForKey:@"UseRegularExpressionsAdvancedFind"] boolValue] == YES) {
+ ICUPattern *pattern;
+ @try {
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:(ICUCaseInsensitiveMatching | ICUMultiline)];
+ } else {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:ICUMultiline];
+ }
+ }
+ @catch (NSException *exception) {
+ [self alertThatThisIsNotAValidRegularExpression:searchString];
+ return;
+ }
+ @finally {
+ }
+
+ if ([completeString length] > 0) { // Otherwise ICU throws an exception
+ ICUMatcher *matcher;
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:completeString];
+ } else {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:[completeString substringWithRange:searchRange]];
+ }
+
+ NSInteger indexTemp;
+ while ([matcher findNext]) {
+ NSInteger foundLocation = [matcher rangeOfMatch].location + startLocation;
+ for (index = 0, lineNumber = 0; index <= foundLocation; lineNumber++) {
+ indexTemp = index;
+ index = NSMaxRange([completeString lineRangeForRange:NSMakeRange(index, 0)]);
+ if (indexTemp == index) {
+ index++; // Make sure it moves forward if it is stuck when searching e.g. for [ \t\n]*
+ }
+ }
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSRange rangeMatch = NSMakeRange([matcher rangeOfMatch].location + searchRange.location, [matcher rangeOfMatch].length);
+ [findResultsTreeController insertObject:[self preparedResultDictionaryFromString:completeString searchStringLength:searchStringLength range:rangeMatch lineNumber:lineNumber document:document] atArrangedObjectIndexPath:[folderIndexPath indexPathByAddingIndex:resultsInThisDocument]];
+ [pool drain];
+
+ resultsInThisDocument++;
+ }
+ }
+
+ } else {
+ while (startLocation < completeStringLength) {
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ foundRange = [completeString rangeOfString:searchString options:NSCaseInsensitiveSearch range:NSMakeRange(startLocation, NSMaxRange(searchRange) - startLocation)];
+ } else {
+ foundRange = [completeString rangeOfString:searchString options:NSLiteralSearch range:NSMakeRange(startLocation, NSMaxRange(searchRange) - startLocation)];
+ }
+
+ if (foundRange.location == NSNotFound) {
+ break;
+ }
+ for (index = 0, lineNumber = 0; index <= foundRange.location; lineNumber++) {
+ index = NSMaxRange([completeString lineRangeForRange:NSMakeRange(index, 0)]);
+ }
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [findResultsTreeController insertObject:[self preparedResultDictionaryFromString:completeString searchStringLength:searchStringLength range:foundRange lineNumber:lineNumber document:document] atArrangedObjectIndexPath:[folderIndexPath indexPathByAddingIndex:resultsInThisDocument]];
+ [pool drain];
+
+ resultsInThisDocument++;
+ startLocation = NSMaxRange(foundRange);
+ }
+ }
+ if (resultsInThisDocument == 0) {
+ [findResultsTreeController removeObjectAtArrangedObjectIndexPath:folderIndexPath];
+ documentIndex--;
+ } else {
+ numberOfResults += resultsInThisDocument;
+ }
+
+ }
+
+ NSString *searchResultString;
+ if (numberOfResults == 0) {
+ searchResultString = [NSString stringWithFormat:NSLocalizedString(@"Could not find a match for search-string %@", @"Could not find a match for search-string %@ in Advanced Find"), searchString];
+ } else if (numberOfResults == 1) {
+ searchResultString = [NSString stringWithFormat:NSLocalizedString(@"Found one match for search-string %@", @"Found one match for search-string %@ in Advanced Find"), searchString];
+ } else {
+ searchResultString = [NSString stringWithFormat:NSLocalizedString(@"Found %i matches for search-string %@", @"Found %i matches for search-string %@ in Advanced Find"), numberOfResults, searchString];
+ }
+
+ [findResultTextField setStringValue:searchResultString];
+
+ NSArray *nodes = [[findResultsTreeController arrangedObjects] childNodes];
+ for (id item in nodes) {
+ [findResultsOutlineView expandItem:item expandChildren:NO];
+ }
+
+ [findResultsOutlineView setDelegate:self];
+
+ [[NSGarbageCollector defaultCollector] collectIfNeeded];
+}
+
+
+- (IBAction)replaceAction:(id)sender
+{
+ NSString *searchString = [findSearchField stringValue];
+ NSString *replaceString = [replaceSearchField stringValue];
+
+ NSMutableArray *recentSearches = [[NSMutableArray alloc] initWithArray:[findSearchField recentSearches]];
+ if ([recentSearches indexOfObject:searchString] != NSNotFound) {
+ [recentSearches removeObject:searchString];
+ }
+ [recentSearches insertObject:searchString atIndex:0];
+ if ([recentSearches count] > 15) {
+ [recentSearches removeLastObject];
+ }
+ [findSearchField setRecentSearches:recentSearches];
+
+ NSMutableArray *recentReplaces = [[NSMutableArray alloc] initWithArray:[replaceSearchField recentSearches]];
+ if ([recentReplaces indexOfObject:replaceString] != NSNotFound) {
+ [recentReplaces removeObject:replaceString];
+ }
+ [recentReplaces insertObject:replaceString atIndex:0];
+ if ([recentReplaces count] > 15) {
+ [recentReplaces removeLastObject];
+ }
+ [replaceSearchField setRecentSearches:recentReplaces];
+
+ NSInteger searchStringLength = [searchString length];
+ if (!searchStringLength > 0 || SMLCurrentDocument == nil || SMLCurrentProject == nil) {
+ NSBeep();
+ return;
+ }
+
+ NSString *completeString;
+ NSInteger completeStringLength;
+ NSInteger startLocation;
+ NSInteger resultsInThisDocument = 0;
+ NSInteger numberOfResults = 0;
+ NSRange foundRange;
+ NSRange searchRange;
+
+ NSEnumerator *enumerator = [self scopeEnumerator];
+ for (id document in enumerator) {
+ completeString = [[[document valueForKey:@"firstTextScrollView"] documentView] string];
+ searchRange = [[[document valueForKey:@"firstTextScrollView"] documentView] selectedRange];
+ completeStringLength = [completeString length];
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ searchRange = NSMakeRange(0, completeStringLength);
+ }
+
+ startLocation = searchRange.location;
+ resultsInThisDocument = 0;
+
+ if ([[SMLDefaults valueForKey:@"UseRegularExpressionsAdvancedFind"] boolValue] == YES) {
+ ICUPattern *pattern;
+ @try {
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:(ICUCaseInsensitiveMatching | ICUMultiline)];
+ } else {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:ICUMultiline];
+ }
+ }
+ @catch (NSException *exception) {
+ [self alertThatThisIsNotAValidRegularExpression:searchString];
+ return;
+ }
+ @finally {
+ }
+
+ ICUMatcher *matcher;
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:completeString];
+ } else {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:[completeString substringWithRange:searchRange]];
+ }
+
+
+ while ([matcher findNext]) {
+ resultsInThisDocument++;
+ }
+
+
+ } else {
+ NSInteger searchLength;
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ searchLength = completeStringLength;
+ } else {
+ searchLength = NSMaxRange(searchRange);
+ }
+ while (startLocation < searchLength) {
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ foundRange = [completeString rangeOfString:searchString options:NSCaseInsensitiveSearch range:NSMakeRange(startLocation, NSMaxRange(searchRange) - startLocation)];
+ } else {
+ foundRange = [completeString rangeOfString:searchString options:NSLiteralSearch range:NSMakeRange(startLocation, NSMaxRange(searchRange) - startLocation)];
+ }
+
+ if (foundRange.location == NSNotFound) {
+ break;
+ }
+ resultsInThisDocument++;
+ startLocation = NSMaxRange(foundRange);
+ }
+ }
+ numberOfResults += resultsInThisDocument;
+ }
+
+ if (numberOfResults == 0) {
+ [findResultTextField setObjectValue:[NSString stringWithFormat:NSLocalizedString(@"Could not find a match for search-string %@", @"Could not find a match for search-string %@ in Advanced Find"), searchString]];
+ NSBeep();
+ return;
+ }
+
+ if ([[SMLDefaults valueForKey:@"SuppressReplaceWarning"] boolValue] == YES) {
+ [self performNumberOfReplaces:numberOfResults];
+ } else {
+ NSString *title;
+ NSString *defaultButton;
+ if ([replaceString length] > 0) {
+ if (numberOfResults != 1) {
+ title = [NSString stringWithFormat:NSLocalizedString(@"Are you sure that you want to replace %i occurrences of %@ with %@?", @"Ask if you are sure that you want to replace %i occurrences of %@ with %@ in ask-if-sure-you-want-to-replace-in-advanced-find-sheet"), numberOfResults, searchString, replaceString];
+ } else {
+ title = [NSString stringWithFormat:NSLocalizedString(@"Are you sure that you want to replace one occurrence of %@ with %@?", @"Ask if you are sure that you want to replace one occurrence of %@ with %@ in ask-if-sure-you-want-to-replace-in-advanced-find-sheet"), searchString, replaceString];
+ }
+ defaultButton = NSLocalizedString(@"Replace", @"Replace-button in ask-if-sure-you-want-to-replace-in-advanced-find-sheet");
+ } else {
+ if (numberOfResults != 1) {
+ title = [NSString stringWithFormat:NSLocalizedString(@"Are you sure that you want to delete %i occurrences of %@?", @"Ask if you are sure that you want to delete %i occurrences of %@ in ask-if-sure-you-want-to-replace-in-advanced-find-sheet"), numberOfResults, searchString, replaceString];
+ } else {
+ title = [NSString stringWithFormat:NSLocalizedString(@"Are you sure that you want to delete the one occurrence of %@?", @"Ask if you are sure that you want to delete the one occurrence of %@ in ask-if-sure-you-want-to-replace-in-advanced-find-sheet"), searchString, replaceString];
+ }
+ defaultButton = DELETE_BUTTON;
+ }
+
+ NSBeginAlertSheet(title,
+ defaultButton,
+ nil,
+ NSLocalizedString(@"Cancel", @"Cancel-button"),
+ advancedFindWindow,
+ self,
+ @selector(replaceSheetDidEnd:returnCode:contextInfo:),
+ nil,
+ (void *)numberOfResults,
+ NSLocalizedString(@"Remember that you can always Undo any changes", @"Remember that you can always Undo any changes in ask-if-sure-you-want-to-replace-in-advanced-find-sheet"));
+ }
+}
+
+
+- (void)replaceSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ [sheet close];
+ if (returnCode == NSAlertDefaultReturn) { // Replace
+ [self performNumberOfReplaces:(NSInteger)contextInfo];
+ }
+}
+
+
+- (void)performNumberOfReplaces:(NSInteger)numberOfReplaces
+{
+ NSString *searchString = [findSearchField stringValue];
+ NSString *replaceString = [replaceSearchField stringValue];
+ NSRange searchRange;
+
+ NSEnumerator *enumerator = [self scopeEnumerator];
+ for (id document in enumerator) {
+ NSTextView *textView = [[document valueForKey:@"firstTextScrollView"] documentView];
+ NSString *originalString = [NSString stringWithString:[textView string]];
+ NSMutableString *completeString = [NSMutableString stringWithString:[textView string]];
+ searchRange = [[[document valueForKey:@"firstTextScrollView"] documentView] selectedRange];
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO || searchRange.length == 0) {
+ searchRange = NSMakeRange(0, [[[[document valueForKey:@"firstTextScrollView"] documentView] string] length]);
+ }
+
+ if ([[SMLDefaults valueForKey:@"UseRegularExpressionsAdvancedFind"] boolValue] == YES) {
+ ICUPattern *pattern;
+ @try {
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:(ICUCaseInsensitiveMatching | ICUMultiline)];
+ } else {
+ pattern = [[ICUPattern alloc] initWithString:searchString flags:ICUMultiline];
+ }
+ }
+ @catch (NSException *exception) {
+ [self alertThatThisIsNotAValidRegularExpression:searchString];
+ return;
+ }
+ @finally {
+ }
+ ICUMatcher *matcher;
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO) {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:completeString];
+ } else {
+ matcher = [[ICUMatcher alloc] initWithPattern:pattern overString:[completeString substringWithRange:searchRange]];
+ }
+
+ NSMutableString *regularExpressionReplaceString = [NSMutableString stringWithString:replaceString];
+ [regularExpressionReplaceString replaceOccurrencesOfString:@"\\n" withString:[NSString stringWithFormat:@"%C", 0x000A] options:NSLiteralSearch range:NSMakeRange(0, [regularExpressionReplaceString length])]; // It doesn't seem to work without this workaround
+ [regularExpressionReplaceString replaceOccurrencesOfString:@"\\r" withString:[NSString stringWithFormat:@"%C", 0x000D] options:NSLiteralSearch range:NSMakeRange(0, [regularExpressionReplaceString length])];
+ [regularExpressionReplaceString replaceOccurrencesOfString:@"\\t" withString:[NSString stringWithFormat:@"%C", 0x0009] options:NSLiteralSearch range:NSMakeRange(0, [regularExpressionReplaceString length])];
+
+ if ([[SMLDefaults valueForKey:@"OnlyInSelectionAdvancedFind"] boolValue] == NO) {
+ [completeString setString:[matcher replaceAllWithString:regularExpressionReplaceString]];
+ } else {
+ [completeString replaceCharactersInRange:searchRange withString:[matcher replaceAllWithString:regularExpressionReplaceString]];
+ }
+
+
+ } else {
+
+ if ([[SMLDefaults valueForKey:@"IgnoreCaseAdvancedFind"] boolValue] == YES) {
+ [completeString replaceOccurrencesOfString:searchString withString:replaceString options:NSCaseInsensitiveSearch range:searchRange];
+ } else {
+ [completeString replaceOccurrencesOfString:searchString withString:replaceString options:NSLiteralSearch range:searchRange];
+ }
+ }
+
+ NSRange selectedRange = [textView selectedRange];
+ if (![originalString isEqualToString:completeString] && [originalString length] != 0) {
+ if ([textView shouldChangeTextInRange:NSMakeRange(0, [[textView string] length]) replacementString:completeString]) { // Do it this way to mark it as an Undo
+ [textView replaceCharactersInRange:NSMakeRange(0, [[textView string] length]) withString:completeString];
+ [textView didChangeText];
+ [document setValue:[NSNumber numberWithBool:YES] forKey:@"isEdited"];
+ }
+ }
+
+ if (selectedRange.location <= [[textView string] length]) {
+ [textView setSelectedRange:NSMakeRange(selectedRange.location, 0)];
+ }
+ }
+
+ if (numberOfReplaces != 1) {
+ [findResultTextField setObjectValue:[NSString stringWithFormat:NSLocalizedString(@"Replaced %i occurrences of %@ with %@", @"Indicate that we replaced %i occurrences of %@ with %@ in update-search-textField-after-replace"), numberOfReplaces, searchString, replaceString]];
+ } else {
+ [findResultTextField setObjectValue:[NSString stringWithFormat:NSLocalizedString(@"Replaced one occurrence of %@ with %@", @"Indicate that we replaced one occurrence of %@ with %@ in update-search-textField-after-replace"), searchString, replaceString]];
+ }
+
+ [findResultsTreeController setContent:nil];
+ [findResultsTreeController setContent:[NSArray array]];
+ [self removeCurrentlyDisplayedDocumentInAdvancedFind];
+ [advancedFindWindow makeKeyAndOrderFront:self];
+}
+
+
+- (void)showAdvancedFindWindow
+{
+ if (advancedFindWindow == nil) {
+ [NSBundle loadNibNamed:@"SMLAdvancedFind.nib" owner:self];
+
+ [[findResultTextField cell] setBackgroundStyle:NSBackgroundStyleRaised];
+
+ [findResultsOutlineView setBackgroundColor:[[NSColor controlAlternatingRowBackgroundColors] objectAtIndex:1]];
+
+ [findResultsOutlineView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
+
+ SMLAdvancedFindScope searchScope = [[SMLDefaults valueForKey:@"AdvancedFindScope"] integerValue];
+
+ if (searchScope == SMLCurrentDocumentScope) {
+ [currentDocumentScope setState:NSOnState];
+ } else if (searchScope == SMLCurrentProjectScope) {
+ [currentProjectScope setState:NSOnState];
+ } else if (searchScope == SMLAllDocumentsScope) {
+ [allDocumentsScope setState:NSOnState];
+ }
+
+ [findResultsTreeController setContent:nil];
+ [findResultsTreeController setContent:[NSArray array]];
+ }
+
+ [advancedFindWindow makeKeyAndOrderFront:self];
+}
+
+
+- (void)outlineViewSelectionDidChange:(NSNotification *)aNotification
+{
+ if ([[findResultsTreeController arrangedObjects] count] == 0) {
+ return;
+ }
+
+ id object = [[findResultsTreeController selectedObjects] objectAtIndex:0];
+ if ([[object valueForKey:@"isLeaf"] boolValue] == NO) {
+ return;
+ }
+
+ id document = [SMLBasic objectFromURI:[object valueForKey:@"document"]];
+
+ if (document == nil) {
+ NSString *title = [NSString stringWithFormat:NSLocalizedString(@"The document %@ is no longer open", @"Indicate that the document %@ is no longer open in Document-is-no-longer-opened-after-selection-in-advanced-find-sheet"), [document valueForKey:@"name"]];
+ NSBeginAlertSheet(title,
+ OK_BUTTON,
+ nil,
+ nil,
+ advancedFindWindow,
+ self,
+ nil,
+ NULL,
+ nil,
+ @"");
+ return;
+ }
+
+ currentlyDisplayedDocumentInAdvancedFind = document;
+
+ if ([document valueForKey:@"fourthTextView"] == nil) {
+ [SMLInterface insertDocumentIntoFourthContentView:document];
+ }
+
+ [self removeCurrentlyDisplayedDocumentInAdvancedFind];
+ [resultDocumentContentView addSubview:[document valueForKey:@"fourthTextScrollView"]];
+ if ([[document valueForKey:@"showLineNumberGutter"] boolValue] == YES) {
+ [resultDocumentContentView addSubview:[document valueForKey:@"fourthGutterScrollView"]];
+ }
+
+ [[document valueForKey:@"lineNumbers"] updateLineNumbersForClipView:[[document valueForKey:@"fourthTextScrollView"] contentView] checkWidth:YES recolour:YES]; // If the window has changed since the view was last visible
+
+ NSRange selectRange = NSRangeFromString([[[findResultsTreeController selectedObjects] objectAtIndex:0] valueForKey:@"range"]);
+ NSString *completeString = [[document valueForKey:@"fourthTextView"] string];
+ if (NSMaxRange(selectRange) > [completeString length]) {
+ NSBeep();
+ return;
+ }
+
+ [[document valueForKey:@"fourthTextView"] setSelectedRange:selectRange];
+ [[document valueForKey:@"fourthTextView"] scrollRangeToVisible:selectRange];
+ [[document valueForKey:@"fourthTextView"] showFindIndicatorForRange:selectRange];
+ [findResultsOutlineView setNextKeyView:[document valueForKey:@"fourthTextView"]];
+
+ if ([[SMLDefaults valueForKey:@"FocusOnTextInAdvancedFind"] boolValue] == YES) {
+ [advancedFindWindow makeFirstResponder:[document valueForKey:@"fourthTextView"]];
+ }
+}
+
+
+
+- (NSEnumerator *)scopeEnumerator
+{
+ SMLAdvancedFindScope searchScope = [[SMLDefaults valueForKey:@"AdvancedFindScope"] integerValue];
+
+ NSEnumerator *enumerator;
+ if (searchScope == SMLCurrentProjectScope) {
+ enumerator = [[[SMLCurrentProject documentsArrayController] arrangedObjects] reverseObjectEnumerator];
+ } else if (searchScope == SMLAllDocumentsScope) {
+ enumerator = [[SMLBasic fetchAll:@"DocumentSortKeyName"] reverseObjectEnumerator];
+ } else {
+ enumerator = [[NSArray arrayWithObject:SMLCurrentDocument] objectEnumerator];
+ }
+
+ return enumerator;
+}
+
+
+- (id)currentlyDisplayedDocumentInAdvancedFind
+{
+ return currentlyDisplayedDocumentInAdvancedFind;
+}
+
+
+- (void)removeCurrentlyDisplayedDocumentInAdvancedFind
+{
+ [SMLInterface removeAllSubviewsFromView:resultDocumentContentView];
+}
+
+
+- (NSView *)resultDocumentContentView
+{
+ return resultDocumentContentView;
+}
+
+
+- (NSManagedObjectContext *)managedObjectContext
+{
+ return SMLManagedObjectContext;
+}
+
+
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ if ([[SMLDefaults valueForKey:@"SizeOfDocumentsListTextPopUp"] integerValue] == 0) {
+ [cell setFont:[NSFont systemFontOfSize:11.0]];
+ } else {
+ [cell setFont:[NSFont systemFontOfSize:13.0]];
+ }
+}
+
+
+- (NSMutableDictionary *)preparedResultDictionaryFromString:(NSString *)completeString searchStringLength:(NSInteger)searchStringLength range:(NSRange)foundRange lineNumber:(NSInteger)lineNumber document:(id)document
+{
+ NSMutableString *displayString = [[NSMutableString alloc] init];
+ NSString *lineNumberString = [NSString stringWithFormat:@"%d\t", lineNumber];
+ [displayString appendString:lineNumberString];
+ NSRange linesRange = [completeString lineRangeForRange:foundRange];
+ [displayString appendString:[SMLText replaceAllNewLineCharactersWithSymbolInString:[completeString substringWithRange:linesRange]]];
+
+ NSMutableDictionary *node = [NSMutableDictionary dictionary];
+ [node setValue:[NSNumber numberWithBool:YES] forKey:@"isLeaf"];
+ [node setValue:NSStringFromRange(foundRange) forKey:@"range"];
+ [node setValue:[SMLBasic uriFromObject:document] forKey:@"document"];
+ NSInteger fontSize;
+ if ([[SMLDefaults valueForKey:@"SizeOfDocumentsListTextPopUp"] integerValue] == 0) {
+ fontSize = 11;
+ } else {
+ fontSize = 13;
+ }
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:displayString attributes:[NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:fontSize] forKey:NSFontAttributeName]];
+ NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
+ [style setLineBreakMode:NSLineBreakByTruncatingMiddle];
+ [attributedString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, [displayString length])];
+ [attributedString applyFontTraits:NSBoldFontMask range:NSMakeRange(foundRange.location - linesRange.location + [lineNumberString length], foundRange.length)];
+ [node setValue:attributedString forKey:@"displayString"];
+
+ return node;
+}
+
+
+- (void)alertThatThisIsNotAValidRegularExpression:(NSString *)string
+{
+ NSString *title = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ is not a valid regular expression", @"Localizable3", @"%@ is not a valid regular expression"), string];
+ NSBeginAlertSheet(title,
+ OK_BUTTON,
+ nil,
+ nil,
+ advancedFindWindow,
+ self,
+ @selector(notAValidRegularExpressionSheetDidEnd:returnCode:contextInfo:),
+ nil,
+ nil,
+ @"");
+}
+
+
+- (void)notAValidRegularExpressionSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
+{
+ [sheet close];
+ [findResultsTreeController setContent:nil];
+ [findResultsTreeController setContent:[NSArray array]];
+ [advancedFindWindow makeKeyAndOrderFront:nil];
+}
+
+
+- (IBAction)searchScopeChanged:(id)sender
+{
+ SMLAdvancedFindScope searchScope = [sender tag];
+
+ if (searchScope == SMLCurrentDocumentScope) {
+ [currentProjectScope setState:NSOffState];
+ [allDocumentsScope setState:NSOffState];
+ [currentDocumentScope setState:NSOnState]; // If the user has clicked an already clicked button make sure it is on and not turned off
+ } else if (searchScope == SMLCurrentProjectScope) {
+ [currentDocumentScope setState:NSOffState];
+ [allDocumentsScope setState:NSOffState];
+ [currentProjectScope setState:NSOnState];
+ } else if (searchScope == SMLAllDocumentsScope) {
+ [currentDocumentScope setState:NSOffState];
+ [currentProjectScope setState:NSOffState];
+ [allDocumentsScope setState:NSOnState];
+ }
+
+ [SMLDefaults setValue:[NSNumber numberWithInteger:searchScope] forKey:@"AdvancedFindScope"];
+
+ if (![[findSearchField stringValue] isEqualToString:@""]) {
+ [self findAction:nil];
+ }
+}
+
+
+- (IBAction)showRegularExpressionsHelpPanelAction:(id)sender
+{
+ [[SMLExtraInterfaceController sharedInstance] showRegularExpressionsHelpPanel];
+}
+
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item
+{
+ if ([item isLeaf] == NO) {
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+@end
22 Classes/SMLAdvancedFindPanel.h
@@ -0,0 +1,22 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SMLAdvancedFindPanel : NSPanel {
+
+}
+
+@end
32 Classes/SMLAdvancedFindPanel.m
@@ -0,0 +1,32 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "SMLStandardHeader.h"
+
+#import "SMLAdvancedFindPanel.h"
+
+@implementation SMLAdvancedFindPanel
+
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
+{
+ self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation];
+
+ if (self) {
+ [self setContentBorderThickness:22.0 forEdge:NSMinYEdge];
+ }
+
+ return self;
+}
+
+@end
27 Classes/SMLApplication.h
@@ -0,0 +1,27 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SMLApplication : NSApplication {
+ unichar key;
+ NSInteger keyCode;
+ NSUInteger flags;
+ NSWindow *eventWindow;
+ id textViewClass;
+ NSString *character;
+}
+
+@end
249 Classes/SMLApplication.m
@@ -0,0 +1,249 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "SMLStandardHeader.h"
+
+#import "SMLApplication.H"
+#import "SMLProjectsController.h"
+#import "SMLTextView.h"
+#import "SMLApplicationDelegate.h"
+#import "SMLDocumentsMenuController.h"
+#import "SMLTextMenuController.h"
+#import "SMLInterfacePerformer.h"
+#import "SMLMainController.h"
+#import "SMLFullScreenWindow.h"
+#import "SMLSnippetsController.h"
+#import "SMLShortcutsController.h"
+#import "SMLCommandsController.h"
+#import "SMLLineNumbers.h"
+#import "SMLProject.h"
+#import "SMLProject+ToolbarController.h"
+#import "SMLSearchField.h"
+
+@implementation SMLApplication
+
+- (void)awakeFromNib
+{
+ textViewClass = [SMLTextView class];
+
+ [self setDelegate:[SMLApplicationDelegate sharedInstance]];
+}
+
+
+- (void)sendEvent:(NSEvent *)event
+{
+ if ([event type] == NSKeyDown) {
+ eventWindow = [event window];
+ if (eventWindow == SMLCurrentWindow) {
+ flags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+
+ if (flags == 1703936) { // Command, Option, Shift
+ keyCode = [event keyCode];
+ if (keyCode == 3) { // 3 is F
+ if ([[SMLCurrentProject projectWindowToolbar] isVisible] && [[SMLCurrentProject projectWindowToolbar] displayMode] != NSToolbarDisplayModeLabelOnly) {
+ NSArray *array = [[SMLCurrentProject projectWindowToolbar] visibleItems];
+ for (id item in array) {
+ if ([[item itemIdentifier] isEqualToString:@"FunctionToolbarItem"]) {
+ [SMLCurrentProject functionToolbarItemAction:[SMLCurrentProject functionButton]];
+ return;
+ }
+ }
+
+ }
+ }
+ } else if (flags == 12058624) { // Command, Option
+ keyCode = [event keyCode];
+ if (keyCode == 124) { // 124 is right arrow
+ if ([[SMLCurrentProject documents] count] > 1) {
+ [[SMLDocumentsMenuController sharedInstance] nextDocumentAction:nil];
+ return;
+ }
+ } else if (keyCode == 123) { // 123 is left arrow
+ if ([[SMLCurrentProject documents] count] > 1) {
+ [[SMLDocumentsMenuController sharedInstance] previousDocumentAction:nil];
+ return;
+ }
+ }
+ } else if (flags == 131072) { // Shift
+ keyCode = [event keyCode];
+ if (keyCode == 48) { // 48 is Tab
+ if (SMLCurrentTextView != nil) {
+ [[SMLTextMenuController sharedInstance] shiftLeftAction:nil];
+ return;
+ }
+ }
+ } else if (flags == 1048576 || flags == 3145728 || flags == 1179648) { // Command, command with a numerical key and command with shift for the keyboards that requires it
+ character = [event charactersIgnoringModifiers];
+ if ([character isEqualToString:@"+"] || [character isEqualToString:@"="]) {
+ NSFont *oldFont = [NSUnarchiver unarchiveObjectWithData:[SMLDefaults valueForKey:@"TextFont"]];
+ CGFloat size = [oldFont pointSize] + 1;
+ [SMLDefaults setValue:[NSArchiver archivedDataWithRootObject:[NSFont fontWithName:[oldFont fontName] size:size]] forKey:@"TextFont"];
+ return;
+ } else if ([character isEqualToString:@"-"]) {
+ NSFont *oldFont = [NSUnarchiver unarchiveObjectWithData:[SMLDefaults valueForKey:@"TextFont"]];
+ CGFloat size = [oldFont pointSize];
+ if (size > 4) {
+ size--;
+ [SMLDefaults setValue:[NSArchiver archivedDataWithRootObject:[NSFont fontWithName:[oldFont fontName] size:size]] forKey:@"TextFont"];
+ return;
+ }
+ }
+ }
+
+
+ } else if (eventWindow == [SMLInterface fullScreenWindow]) {
+ if ([SMLMain isInFullScreenMode]) {
+ flags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+ keyCode = [event keyCode];
+ if (keyCode == 0x35 && flags == 0) { // 35 is Escape,
+ [(SMLFullScreenWindow *)[SMLInterface fullScreenWindow] returnFromFullScreen];
+ return;
+ } else if (keyCode == 0x07 && flags == 1048576) { // 07 is X, 1048576 is Command
+ [(NSTextView *)[[SMLInterface fullScreenWindow] firstResponder] cut:nil];
+ return;
+ } else if (keyCode == 0x08 && flags == 1048576) { // 08 is C
+ [(NSTextView *)[[SMLInterface fullScreenWindow] firstResponder] copy:nil];
+ return;
+ } else if (keyCode == 0x09 && flags == 1048576) { // 09 is V
+ [(NSTextView *)[[SMLInterface fullScreenWindow] firstResponder] paste:nil];
+ return;
+ } else if (keyCode == 0x06 && flags == 1048576) { // 06 is Z
+ [[(NSTextView *)[[SMLInterface fullScreenWindow] firstResponder] undoManager] undo];
+ return;
+ }
+ }
+
+
+ } else if (eventWindow == [[SMLSnippetsController sharedInstance] snippetsWindow]) {
+ NSInteger editedColumn = [[[SMLSnippetsController sharedInstance] snippetsTableView] editedColumn];
+ if (editedColumn != -1) {
+ NSTableColumn *tableColumn = [[[[SMLSnippetsController sharedInstance] snippetsTableView] tableColumns] objectAtIndex:editedColumn];
+
+ if ([[tableColumn identifier] isEqualToString:@"shortcut"]) {
+ key = [[event charactersIgnoringModifiers] characterAtIndex:0];
+ keyCode = [event keyCode];
+ if (keyCode == 0x35) { // If the user cancels by pressing Escape don't insert a hot key
+ [[[SMLSnippetsController sharedInstance] snippetsWindow] makeFirstResponder:[[SMLSnippetsController sharedInstance] snippetsTableView]];
+ return;
+ } else if (keyCode == 0x30) { // Tab
+ [[[SMLSnippetsController sharedInstance] snippetsWindow] makeFirstResponder:[[SMLSnippetsController sharedInstance] snippetsTextView]];
+ return;
+ } else {
+ flags = ([event modifierFlags] & 0x00FF);
+ if ((key == NSDeleteCharacter || keyCode == 0x75) && flags == 0) { // 0x75 is forward delete
+ [[SMLShortcutsController sharedInstance] unregisterSelectedSnippetShortcut];
+ } else {
+ [[SMLShortcutsController sharedInstance] registerSnippetShortcutWithEvent:event];
+ }
+ [[[SMLSnippetsController sharedInstance] snippetsWindow] makeFirstResponder:[[SMLSnippetsController sharedInstance] snippetsTableView]];
+ return;
+ }
+ }
+ }
+
+
+ } else if (eventWindow == [[SMLCommandsController sharedInstance] commandsWindow]) {
+ NSInteger editedColumn = [[[SMLCommandsController sharedInstance] commandsTableView] editedColumn];
+ if (editedColumn != -1) {
+ NSTableColumn *tableColumn = [[[[SMLCommandsController sharedInstance] commandsTableView] tableColumns] objectAtIndex:editedColumn];
+
+ if ([[tableColumn identifier] isEqualToString:@"shortcut"]) {
+ key = [[event charactersIgnoringModifiers] characterAtIndex:0];
+ keyCode = [event keyCode];
+
+ if (keyCode == 0x35) { // If the user cancels by pressing Escape don't insert a hot key
+ [[[SMLCommandsController sharedInstance] commandsWindow] makeFirstResponder:[[SMLCommandsController sharedInstance] commandsTableView]];
+ return;
+ } else if (keyCode == 0x30) { // Tab
+ [[[SMLCommandsController sharedInstance] commandsWindow] makeFirstResponder:[[SMLCommandsController sharedInstance] commandsTextView]];
+ return;
+ } else {
+ flags = ([event modifierFlags] & 0x00FF);
+ if ((key == NSDeleteCharacter || keyCode == 0x75) && flags == 0) { // 0x75 is forward delete
+ [[SMLShortcutsController sharedInstance] unregisterSelectedCommandShortcut];
+ } else {
+ [[SMLShortcutsController sharedInstance] registerCommandShortcutWithEvent:event];
+ }
+
+ [[[SMLCommandsController sharedInstance] commandsWindow] makeFirstResponder:[[SMLCommandsController sharedInstance] commandsTableView]];
+ return;
+ }
+ }
+ }
+ }
+ }
+ [super sendEvent:event];
+}
+
+
+// See -[SMLTextView complete:]
+- (NSEvent *)nextEventMatchingMask:(NSUInteger)eventMask untilDate:(NSDate *)expirationDate inMode:(NSString *)runLoopMode dequeue:(BOOL)dequeue
+{
+ if ([runLoopMode isEqualToString:NSEventTrackingRunLoopMode]) {
+ if ([SMLCurrentTextView inCompleteMethod]) eventMask &= ~NSAppKitDefinedMask;
+ }
+
+ return [super nextEventMatchingMask:eventMask untilDate:expirationDate inMode:runLoopMode dequeue:dequeue];
+}
+
+
+#pragma mark
+#pragma mark AppleScript
+- (NSString *)name
+{
+ return [SMLCurrentDocument valueForKey:@"name"];
+}
+
+
+- (NSString *)path
+{
+ return [SMLCurrentDocument valueForKey:@"path"];
+}
+
+
+- (NSString *)content
+{
+ return [[SMLCurrentDocument valueForKey:@"firstTextView"] string];
+}
+
+
+- (void)setContent:(NSString *)newContent
+{
+ SMLTextView *textView = [SMLCurrentDocument valueForKey:@"firstTextView"];
+ if ([textView shouldChangeTextInRange:NSMakeRange(0, [[textView string] length]) replacementString:newContent]) { // Do it this way to mark it as an Undo
+ [textView replaceCharactersInRange:NSMakeRange(0, [[textView string] length]) withString:newContent];
+ [textView didChangeText];
+ }
+ [[SMLCurrentDocument valueForKey:@"lineNumbers"] updateLineNumbersCheckWidth:YES recolour:YES];
+}
+
+
+- (BOOL)edited
+{
+ return [[SMLCurrentDocument valueForKey:@"isEdited"] boolValue];
+}
+
+
+- (BOOL)smartInsertDelete
+{
+ return [[SMLDefaults valueForKey:@"SmartInsertDelete"] boolValue];
+}
+
+
+- (void)setSmartInsertDelete:(BOOL)flag
+{
+ [SMLDefaults setValue:[NSNumber numberWithBool:flag] forKey:@"SmartInsertDelete"];
+}
+
+@end
48 Classes/SMLApplicationDelegate.h
@@ -0,0 +1,48 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@interface SMLApplicationDelegate : NSObject <NSApplicationDelegate>
+{
+ NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ NSManagedObjectModel *managedObjectModel;
+ NSManagedObjectContext *managedObjectContext;
+
+ BOOL shouldCreateEmptyDocument;
+ BOOL hasFinishedLaunching;
+ BOOL isTerminatingApplication;
+
+ NSMutableArray *filesToOpenArray;
+ NSAppleEventDescriptor *appleEventDescriptor;
+
+}
+
+@property (readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+@property (readonly) NSManagedObjectModel *managedObjectModel;
+@property (readonly) NSManagedObjectContext *managedObjectContext;
+
+@property (readonly) BOOL shouldCreateEmptyDocument, hasFinishedLaunching, isTerminatingApplication;
+
+@property (readonly) NSMutableArray *filesToOpenArray;
+@property (assign) NSAppleEventDescriptor *appleEventDescriptor;
+
+
++ (SMLApplicationDelegate *)sharedInstance;
+
+- (IBAction)saveAction:sender;
+
+- (void)importFromVersion2;
+
+@end
456 Classes/SMLApplicationDelegate.m
@@ -0,0 +1,456 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "SMLStandardHeader.h"
+
+#import "SMLApplicationDelegate.h"
+#import "SMLOpenSavePerformer.h"
+#import "SMLProjectsController.h"
+#import "SMLCommandsController.h"
+#import "SMLBasicPerformer.h"
+#import "SMLServicesController.h"
+#import "SMLToolsMenuController.h"
+#import "SMLProject.h"
+#import "SMLVariousPerformer.h"
+
+#import "ODBEditorSuite.h"
+
+@implementation SMLApplicationDelegate
+
+@synthesize persistentStoreCoordinator, managedObjectModel, managedObjectContext, shouldCreateEmptyDocument, hasFinishedLaunching, isTerminatingApplication, filesToOpenArray, appleEventDescriptor;
+
+
+static id sharedInstance = nil;
+
++ (SMLApplicationDelegate *)sharedInstance
+{
+ if (sharedInstance == nil) {
+ sharedInstance = [[self alloc] init];
+ }
+
+ return sharedInstance;
+}
+
+
+- (id)init
+{
+ if (sharedInstance == nil) {
+ sharedInstance = [super init];
+
+ shouldCreateEmptyDocument = YES;
+ hasFinishedLaunching = NO;
+ isTerminatingApplication = NO;
+ appleEventDescriptor = nil;
+ }
+
+ return sharedInstance;
+}
+
+
+- (NSString *)applicationSupportFolder
+{
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+ NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
+ return [basePath stringByAppendingPathComponent:@"Smultron"];
+}
+
+
+- (NSManagedObjectModel *)managedObjectModel
+{
+ if (managedObjectModel != nil) {
+ return managedObjectModel;
+ }
+
+ managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SMLDataModel3" ofType:@"mom"]]];
+
+ return managedObjectModel;
+}
+
+
+- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
+{
+ if (persistentStoreCoordinator != nil) {
+ return persistentStoreCoordinator;
+ }
+
+ NSString *applicationSupportFolder = nil;
+ NSError *error;
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ applicationSupportFolder = [self applicationSupportFolder];
+ if (![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
+ [fileManager createDirectoryAtPath:applicationSupportFolder withIntermediateDirectories:YES attributes:nil error:nil];
+ }
+
+ NSString *storePath = [applicationSupportFolder stringByAppendingPathComponent: @"Smultron3.smultron"];
+
+ NSURL *url = [NSURL fileURLWithPath:storePath];
+ persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
+ if (![persistentStoreCoordinator addPersistentStoreWithType:NSBinaryStoreType configuration:nil URL:url options:nil error:&error]){
+ [[NSApplication sharedApplication] presentError:error];
+ }
+
+ return persistentStoreCoordinator;
+}
+
+
+- (NSManagedObjectContext *)managedObjectContext
+{
+ if (managedObjectContext != nil) {
+ return managedObjectContext;
+ }
+
+ NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
+ if (coordinator != nil) {
+ managedObjectContext = [[NSManagedObjectContext alloc] init];
+ [managedObjectContext setPersistentStoreCoordinator: coordinator];
+ }
+
+ return managedObjectContext;
+}
+
+
+- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window
+{
+ return [[self managedObjectContext] undoManager];
+}
+
+
+- (IBAction)saveAction:(id)sender
+{
+ NSError *error = nil;
+ if (![[self managedObjectContext] save:&error]) {
+ [[NSApplication sharedApplication] presentError:error];
+ }
+}
+
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ id item;
+ NSArray *array = [[SMLProjectsController sharedDocumentController] documents];
+ for (item in array) {
+ [item autosave];
+ if ([item areAllDocumentsSaved] == NO) {
+ return NSTerminateCancel;
+ }
+ }
+
+ isTerminatingApplication = YES; // This is to avoid changing the document when quiting the application because otherwise it "flashes" when removing the documents
+
+ [[SMLCommandsController sharedInstance] clearAnyTemporaryFiles];
+
+ if ([[SMLDefaults valueForKey:@"OpenAllDocumentsIHadOpen"] boolValue] == YES) {
+
+ NSMutableArray *documentsArray = [NSMutableArray array];
+ NSArray *projects = [[SMLProjectsController sharedDocumentController] documents];
+ for (id project in projects) {
+ if ([project fileURL] == nil) {
+ NSArray *documents = [[project documentsArrayController] arrangedObjects];
+ for (id document in documents) {
+ if ([document valueForKey:@"path"] != nil && [[document valueForKey:@"fromExternal"] boolValue] != YES) {
+ [documentsArray addObject:[document valueForKey:@"path"]];
+ }
+ }
+ }
+ }
+
+ [SMLDefaults setValue:documentsArray forKey:@"OpenDocuments"];
+ }
+
+ if ([[SMLDefaults valueForKey:@"OpenAllProjectsIHadOpen"] boolValue] == YES) {
+ NSMutableArray *projectsArray = [NSMutableArray array];
+ NSArray *array = [[SMLProjectsController sharedDocumentController] documents];
+ for (id project in array) {
+ if ([project fileURL] != nil) {
+ [projectsArray addObject:[[project fileURL] path]];
+ }
+ }
+
+ [SMLDefaults setValue:projectsArray forKey:@"OpenProjects"];
+ }
+
+ array = [SMLBasic fetchAll:@"Document"]; // Mark any external documents as closed
+ for (item in array) {
+ if ([[item valueForKey:@"fromExternal"] boolValue] == YES) {
+ [SMLVarious sendClosedEventToExternalDocument:item];
+ }
+ }
+
+ [SMLBasic removeAllObjectsForEntity:@"Document"];
+ [SMLBasic removeAllObjectsForEntity:@"Encoding"];
+ [SMLBasic removeAllObjectsForEntity:@"SyntaxDefinition"];
+ [SMLBasic removeAllObjectsForEntity:@"Project"];
+
+ NSError *error;
+ NSInteger reply = NSTerminateNow;
+
+ if (managedObjectContext != nil) {
+ if ([managedObjectContext commitEditing]) {
+ if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
+
+ BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
+
+ if (errorResult == YES) {
+ reply = NSTerminateCancel;
+ } else {
+ NSInteger alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
+ if (alertReturn == NSAlertAlternateReturn) {
+ reply = NSTerminateCancel;
+ }
+ }
+ }
+ } else {
+ reply = NSTerminateCancel;
+ }
+ }
+
+ if (reply == NSTerminateCancel) {
+ isTerminatingApplication = NO;
+ }
+
+ return reply;
+}
+
+
+- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
+{
+ filesToOpenArray = [[NSMutableArray alloc] initWithArray:filenames];
+ [filesToOpenArray sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
+ shouldCreateEmptyDocument = NO;
+
+ if (hasFinishedLaunching) {
+ [SMLOpenSave openAllTheseFiles:filesToOpenArray];
+ filesToOpenArray = nil;
+ } else if ([[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent] paramDescriptorForKeyword:keyFileSender] != nil || [[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent] paramDescriptorForKeyword:keyAEPropData] != nil) {
+ if (appleEventDescriptor == nil) {
+ appleEventDescriptor = [[NSAppleEventDescriptor alloc] initWithDescriptorType:[[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent] descriptorType] data:[[[NSAppleEventManager sharedAppleEventManager] currentAppleEvent] data]];
+ shouldCreateEmptyDocument = NO;
+ }
+ }
+}
+
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ [NSApp setServicesProvider:[SMLServicesController sharedInstance]];
+
+ [self performSelector:@selector(markItAsTrulyFinishedWithLaunching) withObject:nil afterDelay:0.0]; // Do it this way because otherwise this is called before the values are inserted by Core Data
+}
+
+
+- (void)markItAsTrulyFinishedWithLaunching
+{
+ if (filesToOpenArray != nil && [filesToOpenArray count] > 0) {
+ NSArray *openDocument = [SMLBasic fetchAll:@"Document"];
+ if ([openDocument count] != 0) {
+ if (SMLCurrentProject != nil) {
+ [SMLCurrentProject performCloseDocument:[openDocument objectAtIndex:0]];
+ }
+ }
+ [SMLManagedObjectContext processPendingChanges];
+ [SMLOpenSave openAllTheseFiles:filesToOpenArray];
+ [SMLCurrentProject selectionDidChange];
+ filesToOpenArray = nil;
+ } else { // Open previously opened documents/projects only if Smultron wasn't opened by e.g. dragging a document onto the icon
+
+ if ([[SMLDefaults valueForKey:@"OpenAllDocumentsIHadOpen"] boolValue] == YES && [[SMLDefaults valueForKey:@"OpenDocuments"] count] > 0) {
+ shouldCreateEmptyDocument = NO;
+ NSArray *openDocument = [SMLBasic fetchAll:@"Document"];
+ if ([openDocument count] != 0) {
+ if (SMLCurrentProject != nil) {
+ filesToOpenArray = [[NSMutableArray alloc] init]; // A hack so that -[SMLProject performCloseDocument:] won't close the window
+ [SMLCurrentProject performCloseDocument:[openDocument objectAtIndex:0]];
+ filesToOpenArray = nil;
+ }
+ }
+ [SMLManagedObjectContext processPendingChanges];
+ [SMLOpenSave openAllTheseFiles:[SMLDefaults valueForKey:@"OpenDocuments"]];
+ [SMLCurrentProject selectionDidChange];
+ }
+
+ if ([[SMLDefaults valueForKey:@"OpenAllProjectsIHadOpen"] boolValue] == YES && [[SMLDefaults valueForKey:@"OpenProjects"] count] > 0) {
+ shouldCreateEmptyDocument = NO;
+ [SMLOpenSave openAllTheseFiles:[SMLDefaults valueForKey:@"OpenProjects"]];
+ }
+ }
+
+ hasFinishedLaunching = YES;
+ shouldCreateEmptyDocument = NO;
+
+ // Do this here so that it won't slow down the perceived start-up time
+ [[SMLToolsMenuController sharedInstance] buildInsertSnippetMenu];
+ [[SMLToolsMenuController sharedInstance] buildRunCommandMenu];
+
+ if ([[SMLDefaults valueForKey:@"HasImportedFromVersion2"] boolValue] == NO) {
+ [self importFromVersion2];
+ }
+
+}
+
+
+- (void)changeFont:(id)sender // When you change the font in the print panel
+{
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFont *panelFont = [fontManager convertFont:[fontManager selectedFont]];
+ [SMLDefaults setValue:[NSArchiver archivedDataWithRootObject:panelFont] forKey:@"PrintFont"];
+}
+
+
+- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
+{
+ if ([[SMLDefaults valueForKey:@"OpenAllProjectsIHadOpen"] boolValue] == YES && [[SMLDefaults valueForKey:@"OpenProjects"] count] > 0 || [[[SMLProjectsController sharedDocumentController] documents] count] > 0) {
+ return NO;
+ } else {
+ return [[SMLDefaults valueForKey:@"NewDocumentAtStartup"] boolValue];
+ }
+}
+
+
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender
+{
+ NSMenu *returnMenu = [[NSMenu alloc] init];
+ NSMenuItem *menuItem;
+ id document;
+
+ NSEnumerator *currentProjectEnumerator = [[[SMLCurrentProject documentsArrayController] arrangedObjects] reverseObjectEnumerator];
+ for (document in currentProjectEnumerator) {
+ menuItem = [[NSMenuItem alloc] initWithTitle:[document valueForKey:@"name"] action:@selector(selectDocumentFromTheDock:) keyEquivalent:@""];
+ [menuItem setTarget:[SMLProjectsController sharedDocumentController]];
+ [menuItem setRepresentedObject:document];
+ [returnMenu insertItem:menuItem atIndex:0];
+ }
+
+ NSArray *projects = [[SMLProjectsController sharedDocumentController] documents];
+ for (id project in projects) {
+ if (project == SMLCurrentProject) {
+ continue;
+ }
+ NSMenu *menu;
+ if ([project valueForKey:@"name"] == nil) {
+ menu = [[NSMenu alloc] initWithTitle:UNTITLED_PROJECT_NAME];
+ } else {
+ menu = [[NSMenu alloc] initWithTitle:[project valueForKey:@"name"]];
+ }
+
+ NSEnumerator *documentsEnumerator = [[[(SMLProject *)project documents] allObjects] reverseObjectEnumerator];
+ for (document in documentsEnumerator) {
+ menuItem = [[NSMenuItem alloc] initWithTitle:[document valueForKey:@"name"] action:@selector(selectDocumentFromTheDock:) keyEquivalent:@""];
+ [menuItem setTarget:[SMLProjectsController sharedDocumentController]];
+ [menuItem setRepresentedObject:document];
+ [menu insertItem:menuItem atIndex:0];
+ }
+
+ NSMenuItem *subMenuItem = [[NSMenuItem alloc] initWithTitle:[menu title] action:nil keyEquivalent:@""];
+ [subMenuItem setSubmenu:menu];
+ [returnMenu addItem:subMenuItem];
+ }
+
+ return returnMenu;
+}
+
+
+- (void)applicationDidBecomeActive:(NSNotification *)aNotification
+{
+ if ([[SMLDefaults valueForKey:@"CheckIfDocumentHasBeenUpdated"] boolValue] == YES) { // Check for updates directly when Smultron gets focus
+ [SMLVarious checkIfDocumentsHaveBeenUpdatedByAnotherApplication];
+ }
+}
+
+
+#pragma mark
+#pragma mark Import from version 2
+
+- (void)importFromVersion2
+{
+ [SMLDefaults setValue:[NSNumber numberWithBool:YES] forKey:@"HasImportedFromVersion2"];
+
+ @try {
+ NSManagedObjectModel *managedObjectModelVersion2 = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SMLDataModel2" ofType:@"mom"]]];
+
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSString *applicationSupportFolder = [self applicationSupportFolder];
+ if (![fileManager fileExistsAtPath:[applicationSupportFolder stringByAppendingPathComponent:@"Smultron.smultron"] isDirectory:NULL]) {
+ return;
+ }
+
+ NSURL *url = [NSURL fileURLWithPath:[applicationSupportFolder stringByAppendingPathComponent:@"Smultron.smultron"]];
+ NSPersistentStoreCoordinator *persistentStoreCoordinatorVersion2 = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModelVersion2];
+ if (![persistentStoreCoordinatorVersion2 addPersistentStoreWithType:NSBinaryStoreType configuration:nil URL:url options:nil error:nil]){
+ return;
+ }
+
+ NSManagedObjectContext *managedObjectContextVersion2 = [[NSManagedObjectContext alloc] init];
+ [managedObjectContextVersion2 setPersistentStoreCoordinator:persistentStoreCoordinatorVersion2];
+
+ NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Command" inManagedObjectContext:managedObjectContextVersion2];
+ NSFetchRequest *request = [[NSFetchRequest alloc] init];
+ [request setEntity:entityDescription];
+
+ // Commands
+ NSArray *oldCommands = [managedObjectContextVersion2 executeFetchRequest:request error:nil];
+ if ([oldCommands count] != 0) {
+ id newCollection = [SMLBasic createNewObjectForEntity:@"CommandCollection"];
+ [newCollection setValue:NSLocalizedStringFromTable(@"Old Commands", @"Localizable3", @"Old Commands") forKey:@"name"];
+
+ id command;
+ for (command in oldCommands) {
+ id newCommand = [SMLBasic createNewObjectForEntity:@"Command"];
+ [newCommand setValue:[command valueForKey:@"command"] forKey:@"name"];
+ [newCommand setValue:[command valueForKey:@"command"] forKey:@"text"];
+ [newCommand setValue:[command valueForKey:@"shortcutDisplayString"] forKey:@"shortcutDisplayString"];
+ [newCommand setValue:[command valueForKey:@"shortcutMenuItemKeyString"] forKey:@"shortcutMenuItemKeyString"];
+ [newCommand setValue:[command valueForKey:@"shortcutModifier"] forKey:@"shortcutModifier"];
+ [newCommand setValue:[command valueForKey:@"sortOrder"] forKey:@"sortOrder"];
+ [newCommand setValue:[NSNumber numberWithInteger:3] forKey:@"version"];
+ [[newCollection mutableSetValueForKey:@"commands"] addObject:newCommand];
+ }
+ }
+
+
+ // Snippets
+ entityDescription = [NSEntityDescription entityForName:@"SnippetCollection" inManagedObjectContext:managedObjectContextVersion2];
+ request = [[NSFetchRequest alloc] init];
+ [request setEntity:entityDescription];
+
+ NSArray *collections = [managedObjectContextVersion2 executeFetchRequest:request error:nil];
+ for (id collection in collections) {
+ id newCollection = [SMLBasic createNewObjectForEntity:@"SnippetCollection"];
+ [newCollection setValue:[collection valueForKey:@"name"] forKey:@"name"];
+
+ NSEntityDescription *entityDescriptionSnippet = [NSEntityDescription entityForName:@"Snippet" inManagedObjectContext:managedObjectContextVersion2];
+ NSFetchRequest *requestSnippet = [[NSFetchRequest alloc] init];
+ [requestSnippet setEntity:entityDescriptionSnippet];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"collectionUUID == %@", [collection valueForKey:@"uuid"]];
+ [requestSnippet setPredicate:predicate];
+
+ NSArray *snippets = [managedObjectContextVersion2 executeFetchRequest:requestSnippet error:nil];
+ for (id oldSnippet in snippets) {
+ id snippet = [SMLBasic createNewObjectForEntity:@"Snippet"];
+ [snippet setValue:[oldSnippet valueForKey:@"name"] forKey:@"name"];
+ [snippet setValue:[oldSnippet valueForKey:@"text"] forKey:@"text"];
+ [snippet setValue:[oldSnippet valueForKey:@"shortcutDisplayString"] forKey:@"shortcutDisplayString"];
+ [snippet setValue:[oldSnippet valueForKey:@"shortcutMenuItemKeyString"] forKey:@"shortcutMenuItemKeyString"];
+ [snippet setValue:[oldSnippet valueForKey:@"shortcutModifier"] forKey:@"shortcutModifier"];
+ [snippet setValue:[oldSnippet valueForKey:@"sortOrder"] forKey:@"sortOrder"];
+ [[newCollection mutableSetValueForKey:@"snippets"] addObject:snippet];
+ }
+ }
+
+ }
+ @catch (NSException *exception) {
+ }
+}
+
+@end
24 Classes/SMLApplicationMenuController.h
@@ -0,0 +1,24 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@interface SMLApplicationMenuController : NSObject
+{
+
+}
+
+- (IBAction)showPreferencesWindowAction:(id)sender;
+
+@end
29 Classes/SMLApplicationMenuController.m
@@ -0,0 +1,29 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import "SMLStandardHeader.h"
+
+#import "SMLApplicationMenuController.h"
+#import "SMLPreferencesController.h"
+
+@implementation SMLApplicationMenuController
+
+
+- (IBAction)showPreferencesWindowAction:(id)sender
+{
+ [[SMLPreferencesController sharedInstance] showPreferencesWindow];
+}
+
+
+@end
29 Classes/SMLAuthenticationController.h
@@ -0,0 +1,29 @@
+/*
+Smultron version 3.6b1, 2009-09-12
+Written by Peter Borg, pgw3@mac.com
+Find the latest version at http://smultron.sourceforge.net
+
+Copyright 2004-2009 Peter Borg
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SMLAuthenticationController : NSObject {
+
+}
+
++ (SMLAuthenticationController *)sharedInstance;
+
+- (void)performAuthenticatedOpenOfPath:(NSString *)path withEncoding:(NSStringEncoding)encoding;
+- (void)performAuthenticatedSaveOfDocument:(id)document data:(NSData *)data path:(NSString *)path fromSaveAs:(BOOL)fromSaveAs aCopy:(BOOL)aCopy;
+
+- (void)installCommandLineUtility;
+
+@end
185