apps-projectcenter/Library/PCEditor.m
Sergii Stoian a66f7753e3 Fix bug in releasing PCButton
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/projectcenter/trunk@20529 72102866-910b-0410-8b05-ffd578937521
2005-01-08 22:17:23 +00:00

758 lines
18 KiB
Objective-C

/*
GNUstep ProjectCenter - http://www.gnustep.org
Copyright (C) 2002-2004 Free Software Foundation
Authors: Philippe C.D. Robert
Serg Stoyan
This file is part of GNUstep.
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This application is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include "PCDefines.h"
#include "PCProjectEditor.h"
#include "PCEditor.h"
#include "PCEditorView.h"
#include "PCLogController.h"
@implementation PCEditor (UInterface)
- (void)_createWindow
{
unsigned int style;
NSRect rect;
float windowWidth;
// PCLogInfo(self, @"[_createWindow]");
style = NSTitledWindowMask
| NSClosableWindowMask
| NSMiniaturizableWindowMask
| NSResizableWindowMask;
windowWidth = [[NSFont userFixedPitchFontOfSize:0.0] widthOfString:@"A"];
windowWidth *= 80;
windowWidth += 35+80;
rect = NSMakeRect(100,100,windowWidth,320);
_window = [[NSWindow alloc] initWithContentRect:rect
styleMask:style
backing:NSBackingStoreBuffered
defer:YES];
[_window setReleasedWhenClosed:YES];
[_window setMinSize:NSMakeSize(512,320)];
[_window setDelegate:self];
rect = [[_window contentView] frame];
// Scroll view
_extScrollView = [[NSScrollView alloc] initWithFrame:rect];
[_extScrollView setHasHorizontalScroller:NO];
[_extScrollView setHasVerticalScroller:YES];
[_extScrollView setAutoresizingMask:
(NSViewWidthSizable|NSViewHeightSizable)];
rect = [[_extScrollView contentView] frame];
// Editor view
_extEditorView = [self _createEditorViewWithFrame:rect];
// Include editor view
[_extScrollView setDocumentView:_extEditorView];
[_extEditorView setNeedsDisplay:YES];
RELEASE(_extEditorView);
// Include scroll view
[_window setContentView:_extScrollView];
[_window makeFirstResponder:_extEditorView];
RELEASE(_extScrollView);
}
- (void)_createInternalView
{
NSRect rect = NSMakeRect(0,0,512,320);
// Scroll view
_intScrollView = [[NSScrollView alloc] initWithFrame:rect];
[_intScrollView setHasHorizontalScroller:NO];
[_intScrollView setHasVerticalScroller:YES];
[_intScrollView setBorderType:NSBezelBorder];
[_intScrollView setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
rect = [[_intScrollView contentView] frame];
// Text view
_intEditorView = [self _createEditorViewWithFrame:rect];
/*
* Setting up ext view / scroll view / window
*/
[_intScrollView setDocumentView:_intEditorView];
[_intEditorView setNeedsDisplay:YES];
RELEASE(_intEditorView);
}
- (PCEditorView *)_createEditorViewWithFrame:(NSRect)fr
{
PCEditorView *ev;
NSTextContainer *tc;
NSLayoutManager *lm;
/*
* setting up the objects needed to manage the view but using the
* shared textStorage.
*/
lm = [[NSLayoutManager alloc] init];
tc = [[NSTextContainer alloc] initWithContainerSize:fr.size];
[lm addTextContainer:tc];
RELEASE(tc);
[_storage addLayoutManager:lm];
RELEASE(lm);
ev = [[PCEditorView alloc] initWithFrame:fr textContainer:tc];
[ev setEditor:self];
[ev setMinSize:NSMakeSize( 0, 0)];
[ev setMaxSize:NSMakeSize(1e7, 1e7)];
[ev setRichText:YES];
[ev setEditable:YES];
[ev setVerticallyResizable:YES];
[ev setHorizontallyResizable:NO];
[ev setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
[ev setTextContainerInset:NSMakeSize( 5, 5)];
[[ev textContainer] setWidthTracksTextView:YES];
[[ev textContainer] setContainerSize:NSMakeSize(fr.size.width, 1e7)];
return ev;
}
@end
@implementation PCEditor
// ===========================================================================
// ==== Initialization
// ===========================================================================
- (id)initWithPath:(NSString *)file
categoryPath:(NSString *)categoryPath
projectEditor:(PCProjectEditor *)aProjectEditor
{
if ((self = [super init]))
{
NSString *t;
NSAttributedString *as;
NSDictionary *at;
NSFont *ft;
projectEditor = aProjectEditor;
_isEdited = NO;
_isWindowed = NO;
_window = nil;
_path = [file copy];
_categoryPath = [categoryPath copy];
ft = [NSFont userFixedPitchFontOfSize:0.0];
at = [NSDictionary dictionaryWithObject:ft forKey:NSFontAttributeName];
t = [NSString stringWithContentsOfFile:file];
as = [[NSAttributedString alloc] initWithString:t attributes:at];
_storage = [[NSTextStorage alloc] init];
[_storage setAttributedString:as];
RELEASE(as);
if (categoryPath) // category == nil if we're non project editor
{
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
if (![[ud objectForKey:SeparateEditor] isEqualToString:@"YES"])
{
[self _createInternalView];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(textDidChange:)
name:NSTextDidChangeNotification
object:_intEditorView];
}
}
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(textDidChange:)
name:NSTextDidChangeNotification
object:_extEditorView];
// Inform about file opening
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidOpenNotification
object:self];
}
return self;
}
- (id)initExternalEditor:(NSString *)editor
withPath:(NSString *)file
projectEditor:(PCProjectEditor *)aProjectEditor
{
NSTask *editorTask = nil;
NSArray *ea = nil;
NSMutableArray *args = nil;
NSString *app = nil;
if (!(self = [super init]))
{
return nil;
}
projectEditor = aProjectEditor;
_extScrollView = nil;
_extEditorView = nil;
_intScrollView = nil;
_intEditorView = nil;
_storage = nil;
_path = [file copy];
_categoryPath = nil;
_window = nil;
_isEdited = NO;
_isWindowed = NO;
_isExternal = YES;
// Task
ea = [editor componentsSeparatedByString:@" "];
args = [NSMutableArray arrayWithArray:ea];
app = [ea objectAtIndex:0];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector (externalEditorDidClose:)
name:NSTaskDidTerminateNotification
object:nil];
editorTask = [[NSTask alloc] init];
[editorTask setLaunchPath:app];
[args removeObjectAtIndex:0];
[args addObject:file];
[editorTask setArguments:args];
[editorTask launch];
// AUTORELEASE(editorTask);
// Inform about file opening
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidOpenNotification
object:self];
return self;
}
- (void)externalEditorDidClose:(NSNotification *)aNotif
{
NSString *path = [[[aNotif object] arguments] lastObject];
if (![path isEqualToString:_path])
{
PCLogError(self, @"external editor task terminated");
return;
}
PCLogStatus(self, @"Our Editor task terminated");
// Inform about closing
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidCloseNotification
object:self];
}
- (void)dealloc
{
#ifdef DEVELOPMENT
NSLog(@"PCEditor: %@ dealloc", _path);
#endif
[[NSNotificationCenter defaultCenter] removeObserver:self];
// _window is setReleasedWhenClosed:YES
RELEASE(_path);
RELEASE(_categoryPath);
RELEASE(_intScrollView);
[super dealloc];
}
- (void)show
{
if (_isWindowed)
{
[_window makeKeyAndOrderFront:nil];
}
}
- (void)setWindowed:(BOOL)yn
{
if ( (yn && _isWindowed) || (!yn && !_isWindowed) )
{
return;
}
if (yn && !_isWindowed)
{
[self _createWindow];
[_window setTitle:[NSString stringWithFormat: @"%@",
[_path stringByAbbreviatingWithTildeInPath]]];
}
else if (!yn && _isWindowed)
{
[_window close];
}
_isWindowed = yn;
}
- (BOOL)isWindowed
{
return _isWindowed;
}
// ===========================================================================
// ==== Accessor methods
// ===========================================================================
- (PCProjectEditor *)projectEditor
{
return projectEditor;
}
- (NSWindow *)editorWindow
{
return _window;
}
- (PCEditorView *)editorView
{
return _intEditorView;
}
- (NSView *)componentView
{
return _intScrollView;
}
- (NSString *)path
{
return _path;
}
- (void)setPath:(NSString *)path
{
NSMutableDictionary *notifDict = [[NSMutableDictionary dictionary] retain];
// Prepare notification object
[notifDict setObject:self forKey:@"Editor"];
[notifDict setObject:_path forKey:@"OldFile"];
[notifDict setObject:path forKey:@"NewFile"];
// Set path
[_path autorelease];
_path = [path copy];
// Post notification
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidChangeFileNameNotification
object:notifDict];
[notifDict autorelease];
}
- (NSString *)categoryPath
{
return _categoryPath;
}
- (void)setCategoryPath:(NSString *)path
{
[_categoryPath autorelease];
_categoryPath = [path copy];
}
- (BOOL)isEdited
{
return _isEdited;
}
- (void)setIsEdited:(BOOL)yn
{
if (_window)
{
[_window setDocumentEdited:yn];
}
_isEdited = yn;
}
// ===========================================================================
// ==== Object managment
// ===========================================================================
- (BOOL)saveFileIfNeeded
{
if ((_isEdited))
{
return [self saveFile];
}
return YES;
}
- (BOOL)saveFile
{
[self setIsEdited:NO];
// Operate on the text storage!
return [[_storage string] writeToFile:_path atomically:YES];
}
- (BOOL)saveFileTo:(NSString *)path
{
// Operate on the text storage!
return [[_storage string] writeToFile:path atomically:YES];
}
- (BOOL)revertFileToSaved
{
NSString *text = [NSString stringWithContentsOfFile:_path];
NSAttributedString *as = nil;
NSDictionary *at = nil;
NSFont *ft = nil;
// This is temporary
ft = [NSFont userFixedPitchFontOfSize:0.0];
at = [NSDictionary dictionaryWithObject:ft forKey:NSFontAttributeName];
as = [[NSAttributedString alloc] initWithString:text attributes:at];
[self setIsEdited:NO];
// Operate on the text storage!
[_storage setAttributedString:as];
RELEASE(as);
[_intEditorView setNeedsDisplay:YES];
[_extEditorView setNeedsDisplay:YES];
return YES;
}
- (BOOL)closeFile:(id)sender save:(BOOL)save
{
if ((save == NO) || [self editorShouldClose])
{
// Close window first if visible
if (_isWindowed && [_window isVisible] && (sender != _window))
{
[_window close];
}
// Inform about closing
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidCloseNotification
object:self];
return YES;
}
return NO;
}
- (BOOL)editorShouldClose
{
if (_isEdited)
{
BOOL ret;
if (_isWindowed && [_window isVisible])
{
[_window makeKeyAndOrderFront:self];
}
ret = NSRunAlertPanel(@"Close File",
@"File %@ has been modified",
@"Save and Close", @"Don't save", @"Cancel",
[_path lastPathComponent]);
if (ret == YES)
{
if ([self saveFile] == NO)
{
NSRunAlertPanel(@"Alert",
@"Error when saving file '%@'!",
@"OK", nil, nil, [_path lastPathComponent]);
return NO;
}
else
{
return YES;
}
}
else if (ret == NO) // Close but don't save
{
return YES;
}
else // Cancel closing
{
return NO;
}
[self setIsEdited:NO];
}
return YES;
}
// ===========================================================================
// ==== Window delegate
// ===========================================================================
- (BOOL)windowShouldClose:(id)sender
{
if ([sender isEqual:_window])
{
if (_intScrollView)
{
// Just close if this file also displayed in int view
_isWindowed = NO;
return YES;
}
else
{
return [self closeFile:_window save:YES];
}
}
return NO;
}
- (void)windowDidBecomeKey:(NSNotification *)aNotification
{
if ([[aNotification object] isEqual:_window] && [_window isVisible])
{
[_window makeFirstResponder:_extEditorView];
}
}
- (void)windowDidResignKey:(NSNotification *)aNotification
{
if ([[aNotification object] isEqual:_window] && [_window isVisible])
{
[_window makeFirstResponder:_window];
}
}
// ===========================================================================
// ==== TextView (_intEditorView, _extEditorView) delegate
// ===========================================================================
- (void)textDidChange:(NSNotification *)aNotification
{
id object = [aNotification object];
if ([object isKindOfClass:[PCEditorView class]]
&& (object == _intEditorView || object == _extEditorView))
{
[self setIsEdited:YES];
}
}
- (BOOL)becomeFirstResponder
{
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidBecomeActiveNotification
object:self];
return YES;
}
- (BOOL)resignFirstResponder
{
[[NSNotificationCenter defaultCenter]
postNotificationName:PCEditorDidResignActiveNotification
object:self];
return YES;
}
// ===========================================================================
// ==== Parser and scrolling
// ===========================================================================
- (NSString *)classNameFromString:(NSString *)string
{
NSString *className = nil;
NSMutableArray *lineComps = nil;
// @implementation ClassName (Category)
//
// @implementation ClassName(Category)
// @implementation ClassName( Category)
// @implementation ClassName(Category )
//
// @implementation ClassName ( Category )
// @implementation ClassName (Category )
// @implementation ClassName ( Category)
lineComps = [[string componentsSeparatedByString:@" "] mutableCopy];
if ([lineComps count] > 2)
// && [[[lineComps objectAtIndex:2] substringWithRange:NSMakeRange(0,1)] isEqualToString:@"("])
{
[lineComps removeObjectAtIndex:0];
className = [lineComps componentsJoinedByString:@""];
RELEASE(lineComps);
return [NSString stringWithFormat:@"@%@", className];
}
else
{
return [NSString stringWithFormat:@"@%@", [lineComps objectAtIndex:1]];
}
return nil;
}
- (NSString *)methodNameFromString:(NSString *)string
{
NSString *methodName = nil;
return methodName;
}
- (NSMutableArray *)linesWithKeyword:(NSString *)keyword atBOL:(BOOL)yn
{
NSMutableArray *lines = [[NSMutableArray alloc] init];
NSString *text = [_storage string];
NSRange range = {0, [text length]};
NSRange subRange = {0, 0};
NSRange lineRange = {0, 0};
NSString *tmpStr = nil;
NSString *lineString = nil;
while (range.location < [text length])
{
subRange = [text rangeOfString:keyword
options:NSLiteralSearch
range:range];
NSLog(@"subRange: {%i, %i}", subRange.location, subRange.length);
if (subRange.location == NSNotFound)
{
break;
}
// Set range for next search
range.location = subRange.location + subRange.length;
range.length = [text length] - range.location;
NSLog(@"range: {%i, %i}", range.location, range.length);
// If keyword is located not at the beginning of line then skip it.
if (yn)
{
tmpStr = [text substringWithRange:NSMakeRange(subRange.location-1,1)];
if (![tmpStr isEqualToString:@"\n"])
{
NSLog(@"CONTINUE %i %i", range.location, range.length);
continue;
}
}
// Get line range where @implementation is located
lineRange = [text lineRangeForRange:subRange];
lineString = [text substringWithRange:lineRange];
NSLog(@"0. line range: {%i, %i}", lineRange.location, lineRange.length);
[lines addObject:lineString];
}
return AUTORELEASE(lines);
}
- (NSArray *)listOfClasses
{
NSMutableArray *classesArray = [[NSMutableArray alloc] init];
NSMutableArray *linesArray = nil;
NSString *lineString = nil;
int i;
NSLog(@"Start searching for class implementations...");
// Get lines with keywords
if ([[[_path lastPathComponent] pathExtension] isEqualToString:@"m"])
{
linesArray = [self linesWithKeyword:@"@implementation" atBOL:YES];
}
else if ([[[_path lastPathComponent] pathExtension] isEqualToString:@"h"])
{
linesArray = [self linesWithKeyword:@"@interface" atBOL:YES];
}
// Get class names
for (i = 0; i < [linesArray count]; i++)
{
lineString = [linesArray objectAtIndex:i];
[classesArray addObject:[self classNameFromString:lineString]];
}
return AUTORELEASE((NSArray*)classesArray);
}
- (NSArray *)listOfMethodsOfClass:(NSString *)className
{
NSMutableArray *methodsArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)methodsArray);
}
- (NSArray *)listOfDefines
{
NSMutableArray *definesArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)definesArray);
}
- (NSArray *)listOfVars
{
NSMutableArray *varsArray = [[NSMutableArray alloc] init];
return AUTORELEASE((NSArray*)varsArray);
}
//--- Scrolling
- (void)scrollToClassName:(NSString *)className
{
}
- (void)scrollToMethodName:(NSString *)className
{
}
- (void)scrollToLineNumber:(int)line
{
}
@end