diff --git a/Assets/buttonBar.psd b/Assets/buttonBar.psd new file mode 100644 index 00000000..08c5076b Binary files /dev/null and b/Assets/buttonBar.psd differ diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 9b1e1f48..eded05d8 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -19,10 +19,12 @@ 4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A83F15B8B474005EF8EE /* MPOutlineDataSource.m */; }; 4C3BD51516D276F800389F1F /* MPToolbarDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3BD51416D276F800389F1F /* MPToolbarDelegate.m */; }; 4C3FFD9E16DAF60600DF9186 /* FilterBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C3FFD9D16DAF60600DF9186 /* FilterBar.xib */; }; + 4C431BCD16E2A82800700A81 /* MPPasteBoardController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C431BCC16E2A82700700A81 /* MPPasteBoardController.m */; }; 4C4E1DC716DC6536007B9B47 /* PathBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C4E1DC616DC6536007B9B47 /* PathBar.xib */; }; 4C586F9E16D07ABD00E7DB57 /* 00_PasswordTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C586F9D16D07ABD00E7DB57 /* 00_PasswordTemplate.pdf */; }; 4C586FA016D07D7200E7DB57 /* 01_PackageNetworkTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C586F9F16D07D7200E7DB57 /* 01_PackageNetworkTemplate.pdf */; }; 4C586FA216D07F6A00E7DB57 /* 02_MessageBoxWarningTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C586FA116D07F6A00E7DB57 /* 02_MessageBoxWarningTemplate.pdf */; }; + 4C587F2E16E0257B0003718D /* MPButtonBarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C587F2D16E0257B0003718D /* MPButtonBarButton.m */; }; 4C61EA0316D2FD0800AC519E /* MPOutlineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C61EA0216D2FD0800AC519E /* MPOutlineViewController.m */; }; 4C61EA0516D2FFE200AC519E /* OutlineView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C61EA0416D2FFE200AC519E /* OutlineView.xib */; }; 4C65C79C16DD283900E32CFF /* MPToolbarButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */; }; @@ -96,7 +98,9 @@ 4CD78ABF16D155FF00768A1D /* 10_ContactTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4CD78ABA16D155FF00768A1D /* 10_ContactTemplate.pdf */; }; 4CD78AC016D155FF00768A1D /* 11_CameraTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4CD78ABB16D155FF00768A1D /* 11_CameraTemplate.pdf */; }; 4CD884B715BD47080042BBF8 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CD884B615BD47080042BBF8 /* MainWindow.xib */; }; + 4CDB556416E29A7C00635918 /* MPPathControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDB556316E29A7C00635918 /* MPPathControl.m */; }; 4CDF01A316D1B76700D0AC08 /* MPEntryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDF01A216D1B76700D0AC08 /* MPEntryViewController.m */; }; + 4CE06D7D16DEF3FE00840E3A /* MPButtonBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE06D7C16DEF3FE00840E3A /* MPButtonBar.m */; }; 4CF5D49616D5B6E900CB78BD /* MPEntryEditController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF5D49416D5B6E900CB78BD /* MPEntryEditController.m */; }; 4CF5D49716D5B6E900CB78BD /* EntryEditView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CF5D49516D5B6E900CB78BD /* EntryEditView.xib */; }; /* End PBXBuildFile section */ @@ -120,10 +124,14 @@ 4C3BD51316D276F800389F1F /* MPToolbarDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPToolbarDelegate.h; sourceTree = ""; }; 4C3BD51416D276F800389F1F /* MPToolbarDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPToolbarDelegate.m; sourceTree = ""; }; 4C3FFD9D16DAF60600DF9186 /* FilterBar.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FilterBar.xib; sourceTree = ""; }; + 4C431BCB16E2A82700700A81 /* MPPasteBoardController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPasteBoardController.h; sourceTree = ""; }; + 4C431BCC16E2A82700700A81 /* MPPasteBoardController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasteBoardController.m; sourceTree = ""; }; 4C4E1DC616DC6536007B9B47 /* PathBar.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PathBar.xib; sourceTree = ""; }; 4C586F9D16D07ABD00E7DB57 /* 00_PasswordTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 00_PasswordTemplate.pdf; sourceTree = ""; }; 4C586F9F16D07D7200E7DB57 /* 01_PackageNetworkTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 01_PackageNetworkTemplate.pdf; sourceTree = ""; }; 4C586FA116D07F6A00E7DB57 /* 02_MessageBoxWarningTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 02_MessageBoxWarningTemplate.pdf; sourceTree = ""; }; + 4C587F2C16E0257B0003718D /* MPButtonBarButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPButtonBarButton.h; sourceTree = ""; }; + 4C587F2D16E0257B0003718D /* MPButtonBarButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPButtonBarButton.m; sourceTree = ""; }; 4C61EA0116D2FD0800AC519E /* MPOutlineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineViewController.h; sourceTree = ""; }; 4C61EA0216D2FD0800AC519E /* MPOutlineViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineViewController.m; sourceTree = ""; }; 4C61EA0416D2FFE200AC519E /* OutlineView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OutlineView.xib; sourceTree = ""; }; @@ -264,8 +272,12 @@ 4CD78ABA16D155FF00768A1D /* 10_ContactTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 10_ContactTemplate.pdf; sourceTree = ""; }; 4CD78ABB16D155FF00768A1D /* 11_CameraTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 11_CameraTemplate.pdf; sourceTree = ""; }; 4CD884B615BD47080042BBF8 /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; + 4CDB556216E29A7C00635918 /* MPPathControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPathControl.h; sourceTree = ""; }; + 4CDB556316E29A7C00635918 /* MPPathControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPathControl.m; sourceTree = ""; }; 4CDF01A116D1B76700D0AC08 /* MPEntryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntryViewController.h; sourceTree = ""; }; 4CDF01A216D1B76700D0AC08 /* MPEntryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntryViewController.m; sourceTree = ""; }; + 4CE06D7B16DEF3FE00840E3A /* MPButtonBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPButtonBar.h; sourceTree = ""; }; + 4CE06D7C16DEF3FE00840E3A /* MPButtonBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPButtonBar.m; sourceTree = ""; }; 4CF5D49316D5B6E900CB78BD /* MPEntryEditController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntryEditController.h; sourceTree = ""; }; 4CF5D49416D5B6E900CB78BD /* MPEntryEditController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntryEditController.m; sourceTree = ""; }; 4CF5D49516D5B6E900CB78BD /* EntryEditView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EntryEditView.xib; sourceTree = ""; }; @@ -302,12 +314,6 @@ 4C4E1DC616DC6536007B9B47 /* PathBar.xib */, 4C69A73816D589DF00EC1B1A /* MPGradientView.h */, 4C69A73916D589DF00EC1B1A /* MPGradientView.m */, - 4C16854216D704980027ECBC /* MPPathBar.h */, - 4C16854316D704980027ECBC /* MPPathBar.m */, - 4C6DA0F716D81B8A0011224B /* MPPathBarItemView.h */, - 4C6DA0F816D81B8A0011224B /* MPPathBarItemView.m */, - 4C65C79A16DD283900E32CFF /* MPToolbarButton.h */, - 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */, ); name = Views; sourceTree = ""; @@ -525,6 +531,7 @@ 4CA0B30E15BCB70200654E32 /* Protocolls */, 4CA0B2F115BCAEE600654E32 /* Controller */, 4C06398C15B980480004DE27 /* Views */, + 4CDB556616E29A8A00635918 /* Controls */, 4C37A84215B8B495005EF8EE /* Model */, 4C37A84115B8B47D005EF8EE /* Delegates */, 4C77E36D15B84A240093A587 /* Supporting Files */, @@ -565,6 +572,8 @@ 4C61EA0216D2FD0800AC519E /* MPOutlineViewController.m */, 4CF5D49316D5B6E900CB78BD /* MPEntryEditController.h */, 4CF5D49416D5B6E900CB78BD /* MPEntryEditController.m */, + 4C431BCB16E2A82700700A81 /* MPPasteBoardController.h */, + 4C431BCC16E2A82700700A81 /* MPPasteBoardController.m */, ); name = Controller; sourceTree = ""; @@ -635,6 +644,25 @@ path = Private; sourceTree = ""; }; + 4CDB556616E29A8A00635918 /* Controls */ = { + isa = PBXGroup; + children = ( + 4C16854216D704980027ECBC /* MPPathBar.h */, + 4C16854316D704980027ECBC /* MPPathBar.m */, + 4C6DA0F716D81B8A0011224B /* MPPathBarItemView.h */, + 4C6DA0F816D81B8A0011224B /* MPPathBarItemView.m */, + 4C65C79A16DD283900E32CFF /* MPToolbarButton.h */, + 4C65C79B16DD283900E32CFF /* MPToolbarButton.m */, + 4CE06D7B16DEF3FE00840E3A /* MPButtonBar.h */, + 4CE06D7C16DEF3FE00840E3A /* MPButtonBar.m */, + 4C587F2C16E0257B0003718D /* MPButtonBarButton.h */, + 4C587F2D16E0257B0003718D /* MPButtonBarButton.m */, + 4CDB556216E29A7C00635918 /* MPPathControl.h */, + 4CDB556316E29A7C00635918 /* MPPathControl.m */, + ); + name = Controls; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -804,6 +832,10 @@ 4C6DA0F916D81B8A0011224B /* MPPathBarItemView.m in Sources */, 4C920E2A16DCDFA00083839B /* MPLoggerProxy.m in Sources */, 4C65C79C16DD283900E32CFF /* MPToolbarButton.m in Sources */, + 4CE06D7D16DEF3FE00840E3A /* MPButtonBar.m in Sources */, + 4C587F2E16E0257B0003718D /* MPButtonBarButton.m in Sources */, + 4CDB556416E29A7C00635918 /* MPPathControl.m in Sources */, + 4C431BCD16E2A82800700A81 /* MPPasteBoardController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -863,7 +895,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2/**"; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-lxml2"; SDKROOT = macosx; @@ -890,7 +922,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2/**"; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; OTHER_LDFLAGS = "-lxml2"; SDKROOT = macosx; }; @@ -903,7 +935,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MacPass/MacPass-Prefix.pch"; INFOPLIST_FILE = "MacPass/MacPass-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -916,7 +948,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "MacPass/MacPass-Prefix.pch"; INFOPLIST_FILE = "MacPass/MacPass-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/MacPass/GeneralSettings.xib b/MacPass/GeneralSettings.xib index aa30581b..96998bba 100644 --- a/MacPass/GeneralSettings.xib +++ b/MacPass/GeneralSettings.xib @@ -2,7 +2,7 @@ 1080 - 12C60 + 12C3103 3084 1187.34 625.00 @@ -42,23 +42,13 @@ 268 - - - 268 - {{0, 56}, {291, 24}} - - - - _NS:9 - MPPathBar - 268 {{146, 91}, {127, 26}} - + _NS:9 {750, 751} YES @@ -196,14 +186,6 @@ 83 - - - pathBar - - - - 372 - @@ -317,54 +299,6 @@ 40 3 - - - 9 - 0 - - 9 - 1 - - 0.0 - - 1000 - - 9 - 40 - 2 - - - - 5 - 0 - - 5 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 10 - 0 - - 10 - 1 - - 0.0 - - 1000 - - 9 - 40 - 2 - 7 @@ -413,7 +347,6 @@ 40 3 - @@ -511,49 +444,6 @@ - - 357 - - - - - 8 - 0 - - 0 - 1 - - 24 - - 1000 - - 9 - 40 - 1 - - - - - - 366 - - - - - 368 - - - - - 370 - - - - - 371 - - - @@ -564,9 +454,6 @@ - - - @@ -585,15 +472,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -606,7 +484,7 @@ - 379 + 407 @@ -632,22 +510,6 @@ ./Classes/MPGeneralSettingsController.h - - MPGradientView - NSView - - IBProjectSource - ./Classes/MPGradientView.h - - - - MPPathBar - MPGradientView - - IBProjectSource - ./Classes/MPPathBar.h - - MPViewController NSViewController diff --git a/MacPass/MPButtonBar.h b/MacPass/MPButtonBar.h new file mode 100644 index 00000000..1f12a45a --- /dev/null +++ b/MacPass/MPButtonBar.h @@ -0,0 +1,52 @@ +// +// MPButtonBar.h +// MacPass +// +// Created by michael starke on 28.02.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPGradientView.h" + +/* + Notifications and userInfo dictionary keys + */ +APPKIT_EXTERN NSString *const MPButtonBarSelectionChangedNotification; +/* + Key in for the Index of the new selection. NSNumber with NSUInteger + */ +APPKIT_EXTERN NSString *const MPButtonBarSelectionIndexKey; + +/* + Exception thrown if an illegal delegate is used. + */ +APPKIT_EXTERN NSString *const MPButtonBarInvalidDelegateException; + +@class MPButtonBar; + +@protocol MPButtonBarDelegate + +@required +- (NSUInteger)buttonsInButtonBar:(MPButtonBar *)buttonBar; +@optional +- (NSImage *)buttonBar:(MPButtonBar *)buttonBar imageAtIndex:(NSUInteger)index; +- (NSString *)buttonBar:(MPButtonBar *)buttonBar labelAtIndex:(NSUInteger)index; + +/* + A delegate that implements this function automatically gets registred to recive MPButtonBarSelectionDidChangeNotification + The object in the notification is the buttonbar, + The userDictionary contrains the following keys: + MPButtonBarSelectionIndexKey; + */ +- (void)didChangeButtonSelection:(NSNotification *)notification; + +@end + +@interface MPButtonBar : MPGradientView + +@property (nonatomic, assign) id delegate; +@property (nonatomic, readonly) NSUInteger selectedIndex; +@property (nonatomic, readonly) BOOL hasSelection; + + +@end diff --git a/MacPass/MPButtonBar.m b/MacPass/MPButtonBar.m new file mode 100644 index 00000000..bdddd658 --- /dev/null +++ b/MacPass/MPButtonBar.m @@ -0,0 +1,131 @@ +// +// MPButtonBar.m +// MacPass +// +// Created by michael starke on 28.02.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPButtonBar.h" +#import "MPButtonBarButton.h" + +#define MPBUTTONBAR_BUTTON_MARGIN 5.0; + +NSString *const MPButtonBarSelectionChangedNotification = @"MPButtonBarSelectionChangedNotification"; +NSString *const MPButtonBarSelectionIndexKey = @"MPButtonBarSelectionIndexKey"; + +NSString *const MPButtonBarInvalidDelegateException = @"MPButtonBarInvalidDelegateException"; + + +@interface MPButtonBar () + +@property (retain) NSMutableArray *buttons; +@property (nonatomic, assign) NSUInteger selectedIndex; +@property (assign) BOOL delegateSupportsImage; +@property (assign) BOOL delegateSupportsLabel; + +- (void)_updateButtons; +- (void)_didClickButton:(id)sender; + +@end + +@implementation MPButtonBar + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.selectedIndex = NSNotFound; + self.buttons = [NSMutableArray arrayWithCapacity:5]; + self.delegateSupportsImage = NO; + self.delegateSupportsLabel = NO; + [self _updateButtons]; + } + return self; +} + +# pragma mark Layout + +- (void)_updateButtons { + NSUInteger currentButtonCount = [self.buttons count]; + NSUInteger newButtonCount = 5;//[self.delegate buttonsInButtonBar:self]; + /* + remove unused buttons + */ + if(currentButtonCount > newButtonCount) { + NSRange removalRange = NSMakeRange(newButtonCount - 1, currentButtonCount - newButtonCount); + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:removalRange]; + NSArray *obsolteButtons = [self.buttons objectsAtIndexes:indexSet]; + for(NSButton *button in obsolteButtons) { + [button removeFromSuperviewWithoutNeedingDisplay]; + } + [self.buttons removeObjectsInRange:NSMakeRange(newButtonCount - 1, currentButtonCount - newButtonCount)]; + } + CGFloat startPosition = MPBUTTONBAR_BUTTON_MARGIN; + for(NSUInteger buttonIndex = 0; buttonIndex < newButtonCount ; buttonIndex++) { + BOOL needsDisplay = NO; + if(buttonIndex >= currentButtonCount) { + NSButton *newButton= [[MPButtonBarButton alloc] initWithFrame:NSMakeRect(0, 0, 30, 30)]; + [self addSubview:newButton]; + [self.buttons addObject:newButton]; + [newButton release]; + [newButton setTarget:self]; + [newButton setImage:[NSImage imageNamed:NSImageNameActionTemplate]]; + [newButton setAction:@selector(_didClickButton:)]; + needsDisplay = YES; + } + NSButton *currentButton = self.buttons[buttonIndex]; + if (self.delegateSupportsImage) { + [currentButton setImage:[self.delegate buttonBar:self imageAtIndex:buttonIndex]]; + needsDisplay = YES; + } + if(self.delegateSupportsLabel) { + [currentButton setStringValue:[self.delegate buttonBar:self labelAtIndex:buttonIndex]]; + needsDisplay = YES; + } + [currentButton sizeToFit]; + NSRect frame = [currentButton frame]; + frame.size.width += 20; + frame.origin.x = startPosition; + [currentButton setFrame:frame]; + startPosition += frame.size.width + MPBUTTONBAR_BUTTON_MARGIN; + [self setNeedsDisplay:needsDisplay]; + } +} + +#pragma mark Button Events + +- (void)_didClickButton:(id)sender { + NSUInteger index = [[self subviews] indexOfObject:sender]; + if(index == NSNotFound) { + return; // Nothing we need to know about happened; + } + NSDictionary *userInfo = @{ MPButtonBarSelectionIndexKey: @(index) }; + [[NSNotificationCenter defaultCenter] postNotificationName:MPButtonBarSelectionChangedNotification object:self userInfo:userInfo]; +} + +# pragma mark Properties + +- (void)setDelegate:(id)delegate { + if( ![delegate conformsToProtocol:@protocol(MPButtonBarDelegate)]) { + NSException *invalidDelegateException = [NSException exceptionWithName:MPButtonBarInvalidDelegateException reason:@"The Delegate does not conform to the MPButtonBarDelegate protocoll" userInfo:nil]; + @throw invalidDelegateException; + } + if(_delegate != delegate) { + if([_delegate respondsToSelector:@selector(didChangeButtonSelection:)]) { + [[NSNotificationCenter defaultCenter] removeObserver:_delegate]; + } + _delegate = delegate; + self.delegateSupportsLabel = [delegate respondsToSelector:@selector(buttonBar:labelAtIndex:)]; + self.delegateSupportsImage = [delegate respondsToSelector:@selector(buttonBar:imageAtIndex:)]; + if([delegate respondsToSelector:@selector(selectionDidChanged:)]) { + [[NSNotificationCenter defaultCenter] addObserver:self.delegate selector:@selector(didChangeButtonSelection:) name:MPButtonBarSelectionChangedNotification object:self]; + } + [self _updateButtons]; + } +} + +- (BOOL)hasSelection { + return self.selectedIndex != NSNotFound; +} + +@end \ No newline at end of file diff --git a/MacPass/MPButtonBarButton.h b/MacPass/MPButtonBarButton.h new file mode 100644 index 00000000..2c0bac33 --- /dev/null +++ b/MacPass/MPButtonBarButton.h @@ -0,0 +1,13 @@ +// +// MPButtonBarButton.h +// MacPass +// +// Created by Michael Starke on 01.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPButtonBarButton : NSButton + +@end diff --git a/MacPass/MPButtonBarButton.m b/MacPass/MPButtonBarButton.m new file mode 100644 index 00000000..74aa3712 --- /dev/null +++ b/MacPass/MPButtonBarButton.m @@ -0,0 +1,41 @@ +// +// MPButtonBarButton.m +// MacPass +// +// Created by Michael Starke on 01.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPButtonBarButton.h" + +@implementation MPButtonBarButton + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self setButtonType:NSPushOnPushOffButton]; + [self setBordered:NO]; + + [[self cell] setHighlightsBy:NSContentsCellMask]; + [[self cell] setShowsStateBy:NSNoCellMask]; + [[self cell] setBackgroundStyle:NSBackgroundStyleRaised]; + } + return self; +} + +- (void)drawRect:(NSRect)dirtyRect { + if(self.state == NSOnState) { + NSRect drawingRect = [self bounds]; + NSColor *edgeColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.2]; + NSColor *middelColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0]; + NSGradient *borderGradient = [[NSGradient alloc] initWithColors:@[edgeColor, middelColor]]; + drawingRect.size.width = 5; + [borderGradient drawInRect:drawingRect relativeCenterPosition:NSMakePoint(-1.0, 0)]; + drawingRect.origin.x = [self bounds].size.width - 5; + [borderGradient drawInRect:drawingRect relativeCenterPosition:NSMakePoint(1.0, 0)]; + } + [super drawRect:dirtyRect]; +} + +@end diff --git a/MacPass/MPEntryViewController.m b/MacPass/MPEntryViewController.m index 9d08d732..dd0609e7 100644 --- a/MacPass/MPEntryViewController.m +++ b/MacPass/MPEntryViewController.m @@ -12,6 +12,7 @@ #import "MPDatabaseDocument.h" #import "MPIconHelper.h" #import "MPMainWindowController.h" +#import "MPPasteBoardController.h" #import "KdbGroup+MPAdditions.h" #import @@ -25,6 +26,13 @@ typedef enum { MPFilterTitles = 8, } MPFilterModeType; +typedef enum { + MPCopyUsername, + MPCopyPassword, + MPCopyURL, + MPCopyWholeEntry, +} MPCopyContentTypeTag; + NSString *const MPEntryTableUserNameColumnIdentifier = @"MPUserNameColumnIdentifier"; NSString *const MPEntryTableTitleColumnIdentifier = @"MPTitleColumnIdentifier"; NSString *const MPEntryTablePasswordColumnIdentifier = @"MPPasswordColumnIdentifier"; @@ -69,10 +77,13 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; - (void)updateFilter; - (void)setupFilterBar; - (void)setupPathBar; +- (void)_setupEntryMenu; - (void)_didChangeGroupSelectionInOutlineView:(NSNotification *)notification; - (void)_showFilterBarAnimated:(BOOL)animate; - (void)_hideStatusBarAnimated:(BOOL)animate; +- (void)_copyEntryData:(id)sender; + @end @implementation MPEntryViewController @@ -114,6 +125,7 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; [self _hideStatusBarAnimated:NO]; [self.entryTable setDelegate:self]; + [self _setupEntryMenu]; NSTableColumn *parentColumn = [self.entryTable tableColumns][0]; NSTableColumn *titleColumn = [self.entryTable tableColumns][1]; @@ -340,8 +352,65 @@ NSString *const _toggleFilterUsernameButton = @"SearchUsername"; } } +#pragma mark EntryMenu + +- (void)_setupEntryMenu { + NSMenu *menu = [[NSMenu allocWithZone:[NSMenu menuZone]] init]; + NSMenuItem *copyUserItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Copy Username" + action:@selector(_copyEntryData:) + keyEquivalent:@"C"]; + [copyUserItem setTag:MPCopyUsername]; + [copyUserItem setTarget:self]; + NSMenuItem *copyPasswordItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Copy Password" + action:@selector(_copyEntryData:) + keyEquivalent:@"c"]; + [copyPasswordItem setTag:MPCopyPassword]; + [copyPasswordItem setTarget:self]; + + [menu addItem:copyUserItem]; + [menu addItem:copyPasswordItem]; + [copyUserItem release]; + [copyPasswordItem release]; + + [self.entryTable setMenu:menu]; + [menu release]; +} + #pragma mark Actions +- (void)_copyEntryData:(id)sender { + + NSInteger selectedRow = [self.entryTable selectedRow]; + if(selectedRow > [[self.entryArrayController arrangedObjects] count]) { + return; + } + KdbEntry *selectedEntry = [self.entryArrayController arrangedObjects][selectedRow]; + + if([sender respondsToSelector:@selector(tag)]) { + MPCopyContentTypeTag contentTag = (MPCopyContentTypeTag)[sender tag]; + SEL contentTypeSelector = @selector(description); + switch (contentTag) { + case MPCopyPassword: + contentTypeSelector = @selector(password); + break; + + case MPCopyUsername: + contentTypeSelector = @selector(username); + break; + + case MPCopyURL: + contentTypeSelector = @selector(URL); + break; + + case MPCopyWholeEntry: + default: + break; + } + [[MPPasteBoardController defaultController] copyObjects:@[ [selectedEntry performSelector:contentTypeSelector] ]]; + } + +} + - (void)_toggleFilterSpace:(id)sender { NSButton *button = sender; NSNumber *value = self.filterButtonToMode[[button identifier]]; diff --git a/MacPass/MPGeneralSettingsController.m b/MacPass/MPGeneralSettingsController.m index 1607ed72..9fc5a088 100644 --- a/MacPass/MPGeneralSettingsController.m +++ b/MacPass/MPGeneralSettingsController.m @@ -51,7 +51,5 @@ NSString *const MPGeneralSetingsIdentifier = @"GeneralSettingsTab"; [_encodingPopup setMenu:encodingMenu]; [encodingMenu release]; - } - @end diff --git a/MacPass/MPOutlineViewDelegate.m b/MacPass/MPOutlineViewDelegate.m index 4ff19d26..4b92ee13 100644 --- a/MacPass/MPOutlineViewDelegate.m +++ b/MacPass/MPOutlineViewDelegate.m @@ -57,7 +57,9 @@ NSString *const _MPOutlinveViewHeaderViewIdentifier = @"HeaderCell"; NSOutlineView *outlineView = [notification object]; KdbGroup *selectedGroup = [outlineView itemAtRow:[outlineView selectedRow]]; self.selectedGroup = selectedGroup; +#ifdef DEBUG NSLog(@"Selected: %@", self.selectedGroup); +#endif [[NSNotificationCenter defaultCenter] postNotificationName:MPOutlineViewDidChangeGroupSelection object:self userInfo:nil]; } diff --git a/MacPass/MPPasswordInputController.m b/MacPass/MPPasswordInputController.m index 29bcd0ff..3c631743 100644 --- a/MacPass/MPPasswordInputController.m +++ b/MacPass/MPPasswordInputController.m @@ -50,6 +50,8 @@ } - (void)_showError { +#ifdef DEBUG NSLog(@"Something went wrong"); +#endif } @end diff --git a/MacPass/MPPasteBoardController.h b/MacPass/MPPasteBoardController.h new file mode 100644 index 00000000..9f9cddd6 --- /dev/null +++ b/MacPass/MPPasteBoardController.h @@ -0,0 +1,23 @@ +// +// MPPastBoardController.h +// MacPass +// +// Created by Michael Starke on 02.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPPasteBoardController : NSObject + +/* + This time sets the time interval after which a copied entry shoudl be purged from the pasteboard + */ +@property (assign, nonatomic) NSTimeInterval clearTimeout; +@property (assign, nonatomic) BOOL clearPasteboardOnShutdown; + ++ (MPPasteBoardController *)defaultController; + +- (void)copyObjects:(NSArray *)objects; + +@end diff --git a/MacPass/MPPasteBoardController.m b/MacPass/MPPasteBoardController.m new file mode 100644 index 00000000..cc3c73c6 --- /dev/null +++ b/MacPass/MPPasteBoardController.m @@ -0,0 +1,87 @@ +// +// MPPastBoardController.m +// MacPass +// +// Created by Michael Starke on 02.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPPasteBoardController.h" + +@interface MPPasteBoardController () + +@property (assign) BOOL isEmpty; + +- (void)_clearPasteboardContents; +- (void)_updateNotifications; + +@end + +@implementation MPPasteBoardController + ++ (MPPasteBoardController *)defaultController { + static MPPasteBoardController* sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[MPPasteBoardController alloc] init]; + }); + return sharedInstance; +} + +- (id)init { + self = [super init]; + if (self) { + _isEmpty = YES; + /* User preferences and bindings */ + _clearTimeout = 30; + _clearPasteboardOnShutdown = YES; + [self _updateNotifications]; + } + return self; +} + +- (void)dealloc +{ + if(_clearPasteboardOnShutdown) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } + [super dealloc]; +} + +- (void)_updateNotifications { + if(self.clearPasteboardOnShutdown) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearContents) name:NSApplicationWillTerminateNotification object:nil]; + } + else { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } +} + +- (void)setClearTimeout:(NSTimeInterval)clearTimeout { + if(_clearTimeout != clearTimeout) { + _clearTimeout = clearTimeout; + } +} + +- (void)setClearPasteboardOnShutdown:(BOOL)clearPasteboardOnShutdown { + if(_clearPasteboardOnShutdown != clearPasteboardOnShutdown ) { + _clearPasteboardOnShutdown = !_clearPasteboardOnShutdown; + [self _updateNotifications]; + } +} + +- (void)copyObjects:(NSArray *)objects { + [[NSPasteboard generalPasteboard] clearContents]; + [[NSPasteboard generalPasteboard] writeObjects:objects]; + self.isEmpty = NO; + [self performSelector:@selector(clearContents) withObject:nil afterDelay:self.clearTimeout]; +} + +- (void)_clearPasteboardContents { + /* Only clear stuff we might have put there */ + if(!self.isEmpty) { + [[NSPasteboard generalPasteboard] clearContents]; + } + self.isEmpty = YES; +} +@end diff --git a/MacPass/MPPathControl.h b/MacPass/MPPathControl.h new file mode 100644 index 00000000..0a633e99 --- /dev/null +++ b/MacPass/MPPathControl.h @@ -0,0 +1,13 @@ +// +// MPPathControl.h +// MacPass +// +// Created by Michael Starke on 02.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPPathControl : NSPathControl + +@end diff --git a/MacPass/MPPathControl.m b/MacPass/MPPathControl.m new file mode 100644 index 00000000..78620d52 --- /dev/null +++ b/MacPass/MPPathControl.m @@ -0,0 +1,22 @@ +// +// MPPathControl.m +// MacPass +// +// Created by Michael Starke on 02.03.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPPathControl.h" + +@implementation MPPathControl + +- (id)initWithFrame:(NSRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [[self cell] setShowsStateBy:NSNoCellMask]; + } + return self; +} + +@end diff --git a/MacPass/MacPass-Info.plist b/MacPass/MacPass-Info.plist index 77aba2fe..49d07b96 100644 --- a/MacPass/MacPass-Info.plist +++ b/MacPass/MacPass-Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 34B + 37D LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright diff --git a/MacPass/MainWindow.xib b/MacPass/MainWindow.xib index 9bb3f927..758e4616 100644 --- a/MacPass/MainWindow.xib +++ b/MacPass/MainWindow.xib @@ -70,6 +70,7 @@ {{257, 0}, {470, 449}} + _NS:13 NSView @@ -88,7 +89,7 @@ - {{0, 0}, {1920, 1058}} + {{0, 0}, {2560, 1418}} {400, 422} {10000000000000, 10000000000000} YES @@ -211,7 +212,7 @@ - 643 + 674