2008-12-29 10:28:59 +00:00
|
|
|
/** <title>GSThemePanel</title>
|
|
|
|
|
|
|
|
<abstract>Theme management utility</abstract>
|
|
|
|
|
2012-02-01 22:07:41 +00:00
|
|
|
Copyright (C) 2008-2012 Free Software Foundation, Inc.
|
2008-12-29 10:28:59 +00:00
|
|
|
|
|
|
|
Author: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
Date: 2007-2008
|
|
|
|
|
|
|
|
This file is part of the GNU Objective C User interface library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2010-04-10 17:48:46 +00:00
|
|
|
#import <Foundation/NSFileManager.h>
|
|
|
|
#import <Foundation/NSNotification.h>
|
|
|
|
#import <Foundation/NSPathUtilities.h>
|
|
|
|
#import <Foundation/NSSet.h>
|
|
|
|
#import <Foundation/NSUserDefaults.h>
|
|
|
|
#import "AppKit/NSButton.h"
|
|
|
|
#import "AppKit/NSMatrix.h"
|
|
|
|
#import "AppKit/NSScrollView.h"
|
|
|
|
#import "GSThemePrivate.h"
|
|
|
|
#import "GSGuiPrivate.h"
|
2008-12-29 10:28:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
@implementation GSThemePanel
|
|
|
|
|
|
|
|
static GSThemePanel *sharedPanel = nil;
|
|
|
|
|
|
|
|
+ (GSThemePanel*) sharedThemePanel
|
|
|
|
{
|
|
|
|
if (sharedPanel == nil)
|
|
|
|
{
|
|
|
|
sharedPanel = [self new];
|
|
|
|
}
|
|
|
|
return sharedPanel;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
NSRect winFrame;
|
|
|
|
NSRect sideFrame;
|
|
|
|
NSRect bottomFrame;
|
|
|
|
NSRect frame;
|
|
|
|
NSView *container;
|
|
|
|
NSButtonCell *proto;
|
|
|
|
|
|
|
|
winFrame = NSMakeRect(0, 0, 367, 420);
|
|
|
|
sideFrame = NSMakeRect(0, 0, 95, 420);
|
|
|
|
bottomFrame = NSMakeRect(95, 0, 272, 32);
|
|
|
|
|
|
|
|
self = [super initWithContentRect: winFrame
|
|
|
|
styleMask: (NSTitledWindowMask | NSClosableWindowMask
|
|
|
|
| NSMiniaturizableWindowMask | NSResizableWindowMask)
|
|
|
|
backing: NSBackingStoreBuffered
|
|
|
|
defer: NO];
|
|
|
|
|
|
|
|
[self setReleasedWhenClosed: NO];
|
|
|
|
container = [self contentView];
|
|
|
|
sideView = [[NSScrollView alloc] initWithFrame: sideFrame];
|
|
|
|
[sideView setHasHorizontalScroller: NO];
|
|
|
|
[sideView setHasVerticalScroller: YES];
|
|
|
|
[sideView setBorderType: NSBezelBorder];
|
|
|
|
[sideView setAutoresizingMask: (NSViewHeightSizable | NSViewMaxXMargin)];
|
|
|
|
[container addSubview: sideView];
|
|
|
|
RELEASE(sideView);
|
|
|
|
|
|
|
|
proto = [[NSButtonCell alloc] init];
|
|
|
|
[proto setBordered: NO];
|
|
|
|
[proto setAlignment: NSCenterTextAlignment];
|
|
|
|
[proto setImagePosition: NSImageAbove];
|
|
|
|
[proto setSelectable: NO];
|
|
|
|
[proto setEditable: NO];
|
|
|
|
[matrix setPrototype: proto];
|
|
|
|
|
|
|
|
frame = [sideView frame];
|
|
|
|
frame.origin = NSZeroPoint;
|
|
|
|
matrix = [[NSMatrix alloc] initWithFrame: frame
|
|
|
|
mode: NSRadioModeMatrix
|
|
|
|
prototype: proto
|
|
|
|
numberOfRows: 1
|
|
|
|
numberOfColumns: 1];
|
|
|
|
RELEASE(proto);
|
|
|
|
[matrix setAutosizesCells: NO];
|
|
|
|
[matrix setCellSize: NSMakeSize(72,72)];
|
|
|
|
[matrix setIntercellSpacing: NSMakeSize(8,8)];
|
|
|
|
[matrix setAutoresizingMask: NSViewNotSizable];
|
|
|
|
[matrix setMode: NSRadioModeMatrix];
|
|
|
|
[matrix setAction: @selector(changeSelection:)];
|
|
|
|
[matrix setTarget: self];
|
|
|
|
|
|
|
|
[sideView setDocumentView: matrix];
|
|
|
|
RELEASE(matrix);
|
|
|
|
|
|
|
|
bottomView = [[NSView alloc] initWithFrame: bottomFrame];
|
|
|
|
[bottomView setAutoresizingMask: (NSViewWidthSizable | NSViewMaxYMargin)];
|
|
|
|
[container addSubview: bottomView];
|
|
|
|
RELEASE(bottomView);
|
|
|
|
|
2010-01-03 22:27:01 +00:00
|
|
|
[self setTitle: _(@"Themes")];
|
2008-12-29 10:28:59 +00:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(notified:)
|
|
|
|
name: GSThemeDidActivateNotification
|
|
|
|
object: nil];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(notified:)
|
|
|
|
name: GSThemeDidDeactivateNotification
|
|
|
|
object: nil];
|
|
|
|
|
|
|
|
/* Fake a notification to set the initial value for the inspector.
|
|
|
|
*/
|
|
|
|
[self notified:
|
|
|
|
[NSNotification notificationWithName: GSThemeDidActivateNotification
|
|
|
|
object: [GSTheme theme]
|
|
|
|
userInfo: nil]];
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) changeSelection: (id)sender
|
|
|
|
{
|
|
|
|
NSButtonCell *cell = [sender selectedCell];
|
|
|
|
NSString *name = [cell title];
|
|
|
|
|
|
|
|
[GSTheme setTheme: [GSTheme loadThemeNamed: name]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) notified: (NSNotification*)n
|
|
|
|
{
|
|
|
|
NSView *cView;
|
|
|
|
GSThemeInspector *inspector;
|
|
|
|
|
|
|
|
inspector = (GSThemeInspector*)[[n object] themeInspector];
|
|
|
|
cView = [self contentView];
|
|
|
|
|
|
|
|
if ([[n name] isEqualToString: GSThemeDidActivateNotification] == YES)
|
|
|
|
{
|
|
|
|
NSView *iView;
|
|
|
|
NSRect frame;
|
|
|
|
NSButton *button;
|
|
|
|
NSString *dName;
|
|
|
|
|
|
|
|
/* Ask the inspector to ensure that it is up to date.
|
|
|
|
*/
|
|
|
|
[inspector update: self];
|
|
|
|
|
|
|
|
/* Move the inspector view into our window.
|
|
|
|
*/
|
|
|
|
iView = RETAIN([inspector contentView]);
|
|
|
|
[inspector setContentView: nil];
|
|
|
|
[cView addSubview: iView];
|
|
|
|
RELEASE(iView);
|
|
|
|
|
|
|
|
/* Set inspector view to fill the frame to the right of our
|
|
|
|
* scrollview and above the bottom view
|
|
|
|
*/
|
|
|
|
frame.origin.x = [sideView frame].size.width;
|
|
|
|
frame.origin.y = [bottomView frame].size.height;
|
|
|
|
frame.size = [cView frame].size;
|
|
|
|
frame.size.width -= [sideView frame].size.width;
|
|
|
|
frame.size.height -= [bottomView frame].size.height;
|
|
|
|
[iView setFrame: frame];
|
|
|
|
|
|
|
|
button = [[bottomView subviews] lastObject];
|
|
|
|
if (button == nil)
|
|
|
|
{
|
|
|
|
button = [NSButton new];
|
|
|
|
[button setTarget: self];
|
|
|
|
[button setAction: @selector(setDefault:)];
|
|
|
|
[bottomView addSubview: button];
|
|
|
|
RELEASE(button);
|
|
|
|
}
|
|
|
|
dName = [[NSUserDefaults standardUserDefaults] stringForKey: @"GSTheme"];
|
|
|
|
if ([[[n object] name] isEqual: dName] == YES)
|
|
|
|
{
|
2010-01-03 22:27:01 +00:00
|
|
|
[button setTitle: _(@"Revert default theme")];
|
2008-12-29 10:28:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-03 22:27:01 +00:00
|
|
|
[button setTitle: _(@"Make this the default theme")];
|
2008-12-29 10:28:59 +00:00
|
|
|
}
|
|
|
|
[button sizeToFit];
|
|
|
|
frame = [button frame];
|
|
|
|
frame.origin.x = ([bottomView frame].size.width - frame.size.width) / 2;
|
|
|
|
frame.origin.y = ([bottomView frame].size.height - frame.size.height) / 2;
|
2012-02-01 22:07:41 +00:00
|
|
|
frame = [bottomView centerScanRect: frame];
|
2008-12-29 10:28:59 +00:00
|
|
|
[button setFrame: frame];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Restore the inspector content view.
|
|
|
|
*/
|
|
|
|
[inspector setContentView: [[cView subviews] lastObject]];
|
|
|
|
}
|
|
|
|
[cView setNeedsDisplay: YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setDefault: (id)sender
|
|
|
|
{
|
|
|
|
NSButton *button = (NSButton*)sender;
|
|
|
|
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
NSString *cName;
|
|
|
|
NSString *dName;
|
|
|
|
NSRect frame;
|
|
|
|
|
|
|
|
dName = [defs stringForKey: @"GSTheme"];
|
|
|
|
cName = [[GSTheme theme] name];
|
|
|
|
|
|
|
|
if ([cName isEqual: dName] == YES)
|
|
|
|
{
|
|
|
|
[defs removeObjectForKey: @"GSTheme"];
|
2010-01-03 22:27:01 +00:00
|
|
|
[button setTitle: _(@"Make this the default theme")];
|
2008-12-29 10:28:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[defs setObject: cName forKey: @"GSTheme"];
|
2010-01-03 22:27:01 +00:00
|
|
|
[button setTitle: _(@"Revert default theme")];
|
2008-12-29 10:28:59 +00:00
|
|
|
}
|
|
|
|
[defs synchronize];
|
|
|
|
[button sizeToFit];
|
|
|
|
frame = [button frame];
|
|
|
|
frame.origin.x = ([bottomView frame].size.width - frame.size.width) / 2;
|
|
|
|
frame.origin.y = ([bottomView frame].size.height - frame.size.height) / 2;
|
|
|
|
[button setFrame: frame];
|
|
|
|
[bottomView setNeedsDisplay: YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) update: (id)sender
|
|
|
|
{
|
|
|
|
NSArray *array;
|
|
|
|
GSTheme *theme = [GSTheme loadThemeNamed: @"GNUstep.theme"];
|
|
|
|
|
|
|
|
/* Avoid [NSMutableSet set] that confuses GCC 3.3.3. It seems to confuse
|
|
|
|
* this static +(id)set method with the instance -(void)set, so it would
|
|
|
|
* refuse to compile saying
|
|
|
|
* GSTheme.m:1565: error: void value not ignored as it ought to be
|
|
|
|
*/
|
|
|
|
NSMutableSet *set = AUTORELEASE([NSMutableSet new]);
|
|
|
|
|
|
|
|
NSString *selected = RETAIN([[matrix selectedCell] title]);
|
|
|
|
unsigned existing = [[matrix cells] count];
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSString *path;
|
|
|
|
NSString *name;
|
|
|
|
NSButtonCell *cell;
|
|
|
|
unsigned count = 0;
|
|
|
|
|
|
|
|
/* Ensure the first cell contains the default theme.
|
|
|
|
*/
|
|
|
|
cell = [matrix cellAtRow: count++ column: 0];
|
|
|
|
[cell setImage: [theme icon]];
|
|
|
|
[cell setTitle: [theme name]];
|
|
|
|
|
|
|
|
/* Go through all the themes in the standard locations and find their names.
|
|
|
|
*/
|
|
|
|
enumerator = [NSSearchPathForDirectoriesInDomains
|
|
|
|
(NSAllLibrariesDirectory, NSAllDomainsMask, YES) objectEnumerator];
|
|
|
|
while ((path = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSEnumerator *files;
|
|
|
|
NSString *file;
|
|
|
|
|
|
|
|
path = [path stringByAppendingPathComponent: @"Themes"];
|
|
|
|
files = [[mgr directoryContentsAtPath: path] objectEnumerator];
|
|
|
|
while ((file = [files nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *ext = [file pathExtension];
|
|
|
|
|
|
|
|
name = [file stringByDeletingPathExtension];
|
|
|
|
if ([ext isEqualToString: @"theme"] == YES
|
2009-01-02 10:19:59 +00:00
|
|
|
&& [name isEqualToString: @"GNUstep"] == NO
|
|
|
|
&& [[name pathExtension] isEqual: @"backup"] == NO)
|
2008-12-29 10:28:59 +00:00
|
|
|
{
|
|
|
|
[set addObject: name];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort theme names alphabetically, and add each theme to the matrix.
|
|
|
|
*/
|
|
|
|
array = [[set allObjects] sortedArrayUsingSelector:
|
|
|
|
@selector(caseInsensitiveCompare:)];
|
|
|
|
enumerator = [array objectEnumerator];
|
|
|
|
while ((name = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
GSTheme *loaded;
|
|
|
|
|
|
|
|
loaded = [GSTheme loadThemeNamed: name];
|
|
|
|
if (loaded != nil)
|
|
|
|
{
|
|
|
|
if (count >= existing)
|
|
|
|
{
|
|
|
|
[matrix addRow];
|
|
|
|
existing++;
|
|
|
|
}
|
|
|
|
cell = [matrix cellAtRow: count column: 0];
|
|
|
|
[cell setImage: [loaded icon]];
|
|
|
|
[cell setTitle: [loaded name]];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Empty any unused cells.
|
|
|
|
*/
|
|
|
|
while (count < existing)
|
|
|
|
{
|
|
|
|
cell = [matrix cellAtRow: count column: 0];
|
|
|
|
[cell setImage: nil];
|
|
|
|
[cell setTitle: @""];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore the selected cell.
|
|
|
|
*/
|
|
|
|
array = [matrix cells];
|
|
|
|
count = [array count];
|
|
|
|
while (count-- > 0)
|
|
|
|
{
|
|
|
|
cell = [matrix cellAtRow: count column: 0];
|
|
|
|
if ([[cell title] isEqual: selected])
|
|
|
|
{
|
|
|
|
[matrix selectCellAtRow: count column: 0];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RELEASE(selected);
|
|
|
|
[matrix sizeToCells];
|
|
|
|
[matrix setNeedsDisplay: YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|