home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / Apps / DevTools / ClassEditor.0.3 / Source / CEAppManager.m < prev    next >
Encoding:
Text File  |  1995-02-14  |  11.4 KB  |  525 lines

  1. /* CEAppManager.m                 
  2.  *
  3.  * This is the basic controller of the App. It manages all big abstraction
  4.  * tasks for the panels, documents and connections to the outside.
  5.  *
  6.  * For interface-info see the header file. The comments in this file mostly
  7.  * cover only the real implementation details.
  8.  *
  9.  * Written by:         Thomas Engel
  10.  * Created:            23.10.1993 (Copyleft)
  11.  * Last modified:     07.05.1994
  12.  */
  13.  
  14. #import "CEAppManager.h"
  15. #import "CEClassEditor.h"
  16. #import "CEListener.h"
  17. #import "Text_MiscExtensions.h"
  18. #import "MiscCompletionText.h"
  19.  
  20. #import <misckit/MiscString.h>
  21.  
  22.  
  23. @implementation CEAppManager
  24.  
  25. - appWillInit:sender
  26. {
  27.     // This is the init part we need to pass before we get the messages that
  28.     // we have to open some files.
  29.     // To be able to init a class we need the have the Preferences,
  30.  
  31.     // preferences = [CEPreferencesManager new];
  32.     
  33.     // Now lets load the docu templates
  34.     
  35.     NXStream     * aStream;
  36.     id            aPath;
  37.     id            ourListener;
  38.  
  39.     // Setup out own Listener...this is really nasty..anyway.
  40.     
  41.     [[NXApp appListener] free];
  42.  
  43.     ourListener = [[CEListener alloc] init];
  44.     [ourListener setDelegate:self];
  45.     [ourListener checkInAs:[NXApp appName]];
  46.     [ourListener addPort];
  47.  
  48.     [NXApp setAppListener:ourListener];    
  49.     
  50.     // Well now this is a litle rough....maybe we should search for those files
  51.     // inside the ~/AppInfo or even *Library/ClassEditor sections..anyway.    
  52.     
  53.     aPath = [MiscString newWithString:
  54.                 [(NXBundle *)[NXBundle mainBundle] directory]];
  55.     [aPath cat:"/CEClassDocuTemplate.rtf"];
  56.     if( [aPath doesExistInFileSystem] )
  57.     {
  58.         aStream = NXMapFile( [aPath stringValue], NX_READONLY );
  59.         [classDocTemplateView readRichText:aStream];
  60.         NXCloseMemory( aStream, NX_FREEBUFFER );
  61.     }
  62.     [aPath free];
  63.  
  64.     aPath = [MiscString newWithString:
  65.                 [(NXBundle *)[NXBundle mainBundle] directory]];
  66.     [aPath cat:"/CEMethodDocuTemplate.rtf"];
  67.     if( [aPath doesExistInFileSystem] )
  68.     {
  69.         aStream = NXMapFile( [aPath stringValue], NX_READONLY );
  70.         [methodDocuTemplateView readRichText:aStream];
  71.         NXCloseMemory( aStream, NX_FREEBUFFER );
  72.     }
  73.     [aPath free];
  74.     
  75.     // Here comes teh hack...
  76.  
  77.     [MiscCompletionText poseAs:[Text class]];
  78.  
  79.     return self;
  80. }
  81.  
  82. - appDidInit:sender
  83. {
  84.     // This is some kind of late init. These object are need for working but
  85.     // not for reading the classes or having a class initialized.
  86.  
  87.     
  88.     return self;
  89. }
  90.  
  91. - (int)app:sender openFile:(const char *)path type:(const char *)type
  92. {
  93.     // This method is performed whenever a user opens a document from the
  94.     // Workspace Manager.
  95.     // We use our default file open method with some default params.
  96.     
  97.     return [self openFile:path onHost:"*" atTrueLine:0];
  98. }
  99.  
  100. - (BOOL)appAcceptsAnotherFile:sender
  101. {
  102.     // Inform the workspace that we can open multiple files.
  103.     return YES;
  104. }
  105.  
  106. - appDidBecomeActive:sender
  107. {
  108.     return self;
  109. }
  110.  
  111. - appWillTerminate:sender
  112. {
  113.     // Now lets see what we have...ask every window what is going on.
  114.  
  115.     BOOL    ready;
  116.     int     i;
  117.     id    windowList;
  118.     int    count;
  119.     int    result;
  120.  
  121.     windowList = [NXApp windowList];
  122.     count = 0;
  123.  
  124.     for( i=0; i<[windowList count]; i++ )
  125.         if( [[windowList objectAt:i] isDocEdited] ) count++;
  126.  
  127.     // Well if there are windows with unsaved contents we should tell the
  128.     // user about it.
  129.     // We won't leave until the user has decided what to do on the top level.
  130.  
  131.     if( count == 0 ) return self;
  132.  
  133.     ready = NO;
  134.     while( !ready )
  135.     {
  136.         result = NXRunAlertPanel( "Quit", "There are edited windows.", 
  137.                                 "Review Unsaved", "Quit Anyway", "Cancel" );
  138.  
  139.         if( result == NX_ALERTOTHER )
  140.             return nil;
  141.     
  142.         else if( result == NX_ALERTDEFAULT )
  143.             ready = [self _closeAllWindows];
  144.  
  145.         else ready = YES;
  146.     }
  147.     return self;
  148. }
  149.  
  150. - (BOOL)_closeAllWindows
  151. {
  152.     // We will try to close all windows and if we succeed we will let the app
  153.     // know. YES = all closed
  154.     // NOTE: Well this is kind of ugly because the app should maintain a list
  155.     //         of all the controllers that are responsible for some data. But I
  156.     //        don't want to hack down another list access stuff. So we do it
  157.     //         this way. Maybe in the future I will change that.
  158.  
  159.     id    delegateList;
  160.     id    aDelegate;
  161.     int    i;
  162.     id    windowList;
  163.     BOOL    success;
  164.  
  165.     windowList = [NXApp windowList];
  166.     delegateList = [List new];
  167.  
  168.     // Lets find all the delegates first.
  169.  
  170.     for( i=0; i<[windowList count]; i++ )
  171.     {
  172.         aDelegate = [[windowList objectAt:i] delegate];
  173.         if( aDelegate != nil &&
  174.             [aDelegate isKindOf:[CEClassEditor class]] )
  175.             [delegateList addObjectIfAbsent:aDelegate];
  176.     }
  177.     success = YES;
  178.  
  179.     for( i=0; i<[delegateList count]; i++ )
  180.     {
  181.         if( [[delegateList objectAt:i] close:self] == nil )
  182.         {
  183.             success = NO;
  184.             break;
  185.         }
  186.     }
  187.  
  188.     return success;
  189. }
  190.  
  191. - addToReleasePool:anObject
  192. {
  193.     return [NXApp delayedFree:anObject];
  194. }
  195.  
  196. - (int)openFile:(char *)path onHost:(char *)host atTrueLine:(int *)line;
  197. {
  198.     // This method is performed whenever a user opens a document.
  199.     // It takes care that every file is only opened once.
  200.     
  201.     id    newEditor;
  202.     id    aString;
  203.     id    basename;
  204.     id    filetype;
  205.     id    thePath;
  206.     id    windowList;
  207.     id    aDelegate;
  208.     int    i;
  209.     BOOL    loadIt;
  210.  
  211.     // First we have to check if we already know this file !
  212.     // Some window delegate should have the same filename (without .h or .m)
  213.     // Using the window list might not be the safest way..but I guess it
  214.     // will work.
  215.     
  216.     aString = [MiscString newWithString:path];
  217.     filetype = [aString fileExtension];
  218.     
  219.     if( [filetype cmp:"m"] != 0 &&
  220.         [filetype cmp:"h"] != 0 &&
  221.         [filetype cmp:"rtf"] != 0 )
  222.     {
  223.         // Looks like this is no valid file !
  224.         
  225.         [aString free];
  226.         [filetype free];
  227.         return -1;
  228.     }
  229.     // Now that it is clear that this is a valid file...
  230.     
  231.     [NXApp activateSelf:NO];
  232.  
  233.     windowList = [NXApp windowList];
  234.     basename = [aString fileBasename];
  235.     thePath = [aString pathName];
  236.     [thePath addChar:[MiscString pathSeparator]];
  237.     [thePath concatenate:basename];
  238.     [basename free];
  239.     [aString free];
  240.     loadIt = YES;
  241.  
  242.     for( i=0; i<[windowList count]; i++ )
  243.     {
  244.         aDelegate = [[windowList objectAt:i] delegate];
  245.  
  246.         if( [aDelegate respondsTo:@selector(filename)] &&
  247.             aDelegate != nil )
  248.         {
  249.             if( [thePath cmp:[aDelegate filename]] == 0 )
  250.             {
  251.                 // Looks like we have found a delegate that belongs to exactly
  252.                 // the same path.
  253.                 // We must to ask this delegate now what window we should top.
  254.                 
  255.                 [[aDelegate window] makeKeyAndOrderFront:self];
  256.                 loadIt = NO;
  257.             }
  258.         }
  259.     }
  260.     [thePath free];
  261.  
  262.       // If we really have a new editor...let the world know about it.
  263.       
  264.     if( loadIt )
  265.     {
  266.         newEditor = [[CEClassEditor alloc] initFromFile:path];
  267.          if( newEditor ) return YES;
  268.     }
  269.     return 0;
  270. }
  271.  
  272. - showInfo:sender
  273. {
  274. //    if( !info ) info = [BBInfo new];
  275.         
  276. //    [info makeKeyAndOrderFront:self];
  277.     return self;
  278. }
  279.  
  280. - showPreferences:sender
  281. {
  282. //    if( preferences ) [preferences makeKeyAndOrderFront:self];
  283.     return self;
  284. }
  285.  
  286. - preferences
  287. {
  288.     return self;
  289. }
  290.  
  291. - open:sender
  292. {
  293.     id         openPanel;
  294.     char     fullName[MAXPATHLEN];
  295.     const char *const *files;
  296.     const char *const fileType[6] = { "m",
  297.                                       "h",
  298.                                        NULL};
  299.  
  300.      openPanel = [[OpenPanel new] allowMultipleFiles:YES];
  301.  
  302.      // Run the open panel, filtering for our type of documents
  303.      // We try to open every file the panel returns.
  304.   
  305.       if( [openPanel runModalForTypes:fileType] )
  306.       {
  307.           files = [openPanel filenames];
  308.         for( files = [openPanel filenames]; files && *files; files++)
  309.         {
  310.             // Now lets merge the fullFilename from the directory and the
  311.             // current filename and try to init a editor from this file.
  312.             // We use the default open method with some default params.
  313.               
  314.             sprintf( fullName, "%s/%s", 
  315.                     [(OpenPanel *)openPanel directory], *files );
  316.               [self openFile:fullName onHost:"*" atTrueLine:0];
  317.             }
  318.     }
  319.       return self;
  320. }
  321.  
  322. - new:sender
  323. {
  324.     [CEClassEditor new];
  325.     return self;
  326. }
  327.  
  328. - save:sender
  329. {
  330.     // [[NXApp keyWindow] save:sender];
  331.     //
  332.     // This is a posible solution
  333.     // But we currently work with a firstResponder solution
  334.     
  335.     return self;
  336. }
  337.  
  338. - saveAs:sender
  339. {
  340.     return self;
  341. }
  342.  
  343. - saveTo:sender
  344. {
  345.     return self;
  346. }
  347.  
  348. - saveAll:sender
  349. {
  350.     return self;
  351. }
  352.  
  353. - revert:sender
  354. {
  355.     return self;
  356. }
  357.  
  358. - close:sender
  359. {
  360.     return self;
  361. }
  362.  
  363. - print:sender
  364. {
  365.     return self;
  366. }
  367.  
  368. - setTextFontStyle:sender
  369. {
  370.     [self _setSelectionFont:textFontField andColor:textFontColorWell];
  371.     return self;
  372. }
  373.  
  374. - setMethodNameFontStyle:sender
  375. {
  376.     [self _setSelectionFont:methodNameField andColor:methodNameColorWell];
  377.     return self;
  378. }
  379.  
  380. - setParameterFontStyle:sender
  381. {
  382.     id firstResponder = [[NXApp mainWindow] firstResponder];
  383.     
  384.     if( [firstResponder respondsTo:@selector(setSelFont:)] )
  385.         [firstResponder setSelFont:[Font newFont:"Times-Italic" size:14]];
  386.     return self;
  387. }
  388.  
  389. - setMathSymbolFontStyle:sender
  390. {
  391.     id firstResponder = [[NXApp mainWindow] firstResponder];
  392.     
  393.     if( [firstResponder respondsTo:@selector(setSelFont:)] )
  394.         [firstResponder setSelFont:[Font newFont:"Symbol" size:14]];
  395.     return self;
  396. }
  397.  
  398. - setHeadlinesFontStyle:sender
  399. {
  400.     [self _setSelectionFont:headlinesFontField
  401.                    andColor:headlinesFontColorWell];
  402.     return self;
  403. }
  404.  
  405. - setExampleCodeFontStyle:sender
  406. {
  407.     [self _setSelectionFont:exampleCodeFontField
  408.                    andColor:exampleCodeFontColorWell];
  409.     return self;
  410. }
  411.  
  412. - setBlankLinesFontStyle:sender
  413. {
  414.     [self _setSelectionFont:blankLinesFontField
  415.                    andColor:blankLinesFontColorWell];
  416.     return self;
  417. }
  418.  
  419. - setSourceFontStyle:sender
  420. {
  421.     [self _setSelectionFont:sourceFontField andColor:sourceFontColorWell];
  422.     return self;
  423. }
  424.  
  425. - setKeywordsFontStyle:sender
  426. {
  427.     [self _setSelectionFont:keywordsFontField andColor:keywordsFontColorWell];
  428.     return self;
  429. }
  430.  
  431. - setTypecastFontStyle:sender
  432. {
  433.     [self _setSelectionFont:typecastFontField andColor:typecastFontColorWell];
  434.     return self;
  435. }
  436.  
  437. - setRemarkFontStyle:sender
  438. {
  439.     [self _setSelectionFont:remarkFontField andColor:remarkFontColorWell];
  440.     return self;
  441. }
  442.  
  443. - setBugNoteFontStyle:sender
  444. {
  445.     [self _setSelectionFont:bugNoteFontField andColor:bugNoteFontColorWell];
  446.     return self;
  447. }
  448.  
  449. - _setSelectionFont:aFont andColor:aColor
  450. {
  451.     // Well this is a lie...we don't get the font but the TextField that has
  452.     // the right font set !!
  453.     
  454.     id firstResponder = [[NXApp mainWindow] firstResponder];
  455.     
  456.     if( [firstResponder respondsTo:@selector(setSelFont:)] &&
  457.         aFont != nil )
  458.         [firstResponder setSelFont:[aFont font]];
  459.     if( [firstResponder respondsTo:@selector(setSelColor:)] &&
  460.         aColor != nil )
  461.         [firstResponder setSelColor:[aColor color]];
  462.  
  463.     // This is for letting the delegates know about the changes to
  464.     // be able to track document modification.
  465.     // The first responder must know about the window because the
  466.     // textDidChange might require it.
  467.     
  468.     if( [firstResponder respondsTo:@selector(window)] )
  469.         [[[NXApp mainWindow] delegate] textDidChange:firstResponder];
  470.  
  471.     return self;
  472. }
  473.  
  474. - copyClassDocuTemplate
  475. {
  476.     // All we do here is to copy the docu template to the pasteboard.
  477.     
  478.     [classDocTemplateView selectAll:self];
  479.     [classDocTemplateView copyTo:[Pasteboard newName:"CETempPb"]];
  480.     return self;
  481. }
  482.  
  483. - copyMethodDocuTemplate
  484. {
  485.     // All we do here is to copy the method template to the pasteboard.
  486.     
  487.     [methodDocuTemplateView selectAll:self];
  488.     [methodDocuTemplateView copyTo:[Pasteboard newName:"CETempPb"]];
  489.     return self;
  490. }
  491.  
  492. - windowDidBecomeKey:sender
  493. {
  494.     // now if our Docu window will become key...we should load the text into
  495.     // it if we havn't yet.
  496.  
  497.     NXStream     * aStream;
  498.     id            aPath;
  499.     
  500.     if( sender != docuTemplateWindow ) return self;
  501.     
  502.     if( [docuTemplateTextView textLength] < 10 )
  503.     {
  504.         aPath = [MiscString newWithString:
  505.                         [(NXBundle *)[NXBundle mainBundle] directory]];
  506.         [aPath cat:"/DocuTemplate.rtf"];
  507.         if( [aPath doesExistInFileSystem] )
  508.         {
  509.             aStream = NXMapFile( [aPath stringValue], NX_READONLY );
  510.             [docuTemplateTextView readRichText:aStream];
  511.             NXCloseMemory( aStream, NX_FREEBUFFER );
  512.         }
  513.         [aPath free];
  514.     }
  515.     return self;
  516. }
  517.  
  518. @end
  519.  
  520. /*
  521.  * History: 13.01.95 Bla.
  522.  *
  523.  *
  524.  * Bugs: No bugs and birds seen....
  525.  */