MAC : XCode -> Scroll View 控件以Thumbnail的方式显示一个文件夹的所有图片,类似图片浏览器
STEP1:将两个文件夹拷贝到工程里面ImageBrowserView和Utils,并且在工程里面建立对应组和导入文件
STEP2:将Quartz.framework 和QuartzCore.framework库 导入到工程里面,这两个库是系统库
STEP3: 找到控件Scroll View 控件,上面写着“Scroll View”拖入到工程里面,然后将其里面的类修改为:
ImageBrowser 这是上面文件夹里面一个类。
STEP4: 从控件面板里面,找到2个委托类,然后分别对应ImageDataSource 和 ImageBrowserDelegate
STEP5: 然后将控件(里面的)按住Ctrl拖拉到委托控件上,然后分别对应数据源Datasource和Delegate
STEP6: 然后还要对这个控件绑定,代码已经在数据源和委托类写好,只要拖拉对应这个控件就可以。也是一定是ScrollView里面一层的控件。
STEP7: 然后查看1下,是否DataSource和delegate,还有2个定义是否绑定好
STEP8:然后将主界面增加3个按钮,一个选择文件夹,直接输入:
- (IBAction)OnBT_SelectFolder:(id)sender
{
NSOpenPanel *panel = [NSOpenPanel
openPanel];
NSString *msg=[NSString
stringWithFormat:@"Select a folder"];
//不让新打开的窗口在新窗口出现标题
[panel setMessage:msg];
[panel setPrompt:@"OK"];
[panel setCanChooseDirectories:YES];
[panel setCanCreateDirectories:YES];
[panel setCanChooseFiles:NO];
[panel beginSheetModalForWindow:[NSApp
mainWindow] completionHandler:^(NSInteger result)
{
NSString *selected_folder=@"";
if (result ==
NSFileHandlingPanelOKButton)
{
selected_folder=[[panel URL]
path];
[g_ImageDataSource
Show_ThumbnailImages:selected_folder];
}
}];
}
就可以显示你选择的文件夹了。
另外全选和不全选按钮的函数是:
[g_ImageDataSource
SetSelected_All_or_None];
有时候你可能想修改标题
可以用以下代码实现
- (IBAction)OnBT_ChangeTitle:(id)sender
{
//picture_id
[g_ImageDataSource
setID];
//picture_path
NSMutableArray *array_image_id = [[NSMutableArray
alloc] init];
NSMutableArray *array_image_path = [[NSMutableArray
alloc] init];
NSMutableArray *array_image_file_size = [[NSMutableArray
alloc] init];
int i=0;
int i_pic_count =
10;//file_count, need you change
NSString *picture_id=nil;
NSString *picture_path=nil;
NSString *picture_file_size =
nil;
for (; i<i_pic_count; i++)
{
picture_id =[NSString
stringWithFormat:@"ID%d",i+1];
picture_path =[NSString
stringWithFormat:@"Path%d",i+1];
picture_file_size=[NSString
stringWithFormat:@"Size%d",i+1];
[array_image_id addObject:picture_id];
[array_image_path addObject:picture_path];
[array_image_file_size addObject:picture_file_size];
}
[g_ImageDataSource
setImagesPath:array_image_id
PhotoPath:array_image_path
PhotoFileSize:array_image_file_size];
}
特别注意:
当写好了图片数据源,需要外部引用
只需要做:
#import "ImageDataSource.h"
extern ImageDataSource *g_ImageDataSource;
用这个指针就可以调用所有的函数
如果在控件里面,需要当选中的时候,显示当前选中的文件名
Document *g_Document;
然后在调用的图片委托类里面
#import "Document.h"
extern Document *g_Document;
这样就可以在选择里面写入:
-(void)imageBrowserSelectionDidChange:(IKImageBrowserView *)aBrowser
{
。。。。。。
[g_Document
ShowMessageInBottom:msg];
}
这样就达到了选择一个文件夹,然后在下面显示选择的文件夹全路径
以上需要的两个程序包类,一共18个文件,9个类。
代码如下:
可以根据自己实际情况再酌情修改。
=============================================================
//ImageBrowser.h
#import <Quartz/Quartz.h>
@class ImageItem;
/**
Image browser view. Displays thumbnails of the images contained in a single
folder. Fullscreen is binded to the image view, and it implements the
CutCopy protocol.
*/
@interface ImageBrowser :
IKImageBrowserView
{
}
-(void)awakeFromNib;
-(void)reloadData;
-(void)reloadDataAndKeepSelection;
// utils
-(BOOL)setFullscreen;
-(void)deleteSelectedImages;
-(void)cutSelectedImages;
-(void)copySelectedImages;
-(IBAction)selectAll:(id)sender;
-(IBAction)deselectAll:(id)sender;
-(void)setSelectedImage:(NSString *)image;
-(ImageItem *)itemAtIndex:(NSUInteger)index;
-(NSArray *)selectedImagesAsURLArray;
-(NSArray *)selectedImagesAsTitelArray;
-(NSArray *)selectedImagesAsPhotoPathArray;
-(NSArray *)selectedImagesAsPhotoIDArray;
// used by the slide show timer
-(void)selectNextImage:(NSTimer *)timer;
// for binding
-(BOOL)showTitles;
-(void)setShowTitles:(BOOL)showTitles;
-(float)thumbnailMargin;
-(void)setThumbnailMargin:(BOOL)margin;
// event methods
-(void)keyDown:(NSEvent *)theEvent;
-(void)otherMouseDown:(NSEvent *)theEvent;
-(NSArray *)selectedImagesAsPhotoIDArray;
@end
=============================================================
//ImageBrowser.m
#import "ImageBrowser.h"
#import "ImageBrowserDelegate.h"
#import "ImageItem.h"
#import "ImageDataSource.h"
#import "../Utils/FileUtils.h"
#import "../Utils/Utils.h"
#import "../Utils/SlideShow.h"
@implementation ImageBrowser
-(void)awakeFromNib
{
// cell spacing
// [LeftRight Margin,UpDown Margin]
[self
setIntercellSpacing:NSMakeSize(3.0f,
5.0f)];
// forground color for the cell‘s titles
NSMutableDictionary * options = [[NSMutableDictionary
alloc]
init];
[options
setObject:[NSColor
blackColor]
forKey:NSForegroundColorAttributeName];
[self
setValue:options
forKey:IKImageBrowserCellsTitleAttributesKey];
[options release];
[self
setShowTitles :YES];
}
-(void)dealloc
{
[super
dealloc];
}
/**
This method is used to seemlessly reload data. Since the selected image is
bound to the current image of the image view, when we do the usual
reloadData, the selection is lost. If we‘re in fullscreen, it‘ll break it.
So this method reloads data and select the next available image just after
that.
*/
-(void)reloadDataAndKeepSelection
{
// remember the first selected image
int selectedIndex = (int)[[self
selectionIndexes]
firstIndex];
// reload the data
[(ImageBrowserDelegate *)[self
delegate]
setIgnoreSelectionChanges:YES];
[super
reloadData];
[(ImageBrowserDelegate *)[self
delegate]
setIgnoreSelectionChanges:NO];
// restore the selection, taking care of out of bound indexes
int numImages = (int)[[self
dataSource] numberOfItemsInImageBrowser:self];
if (numImages !=
0)
{
if (selectedIndex >= numImages)
selectedIndex = numImages -
1;
[self
setSelectionIndexes:[NSIndexSet
indexSetWithIndex:selectedIndex]
byExtendingSelection:NO];
}
else
{
// if there is no more images, we need to explicitely set the image
// property of the delegate to nil.ImageViewer
// This is because [super reloadData] set the current selection to
// nothing, so setting it again to nothing will NOT call the selection
// changed delegate, thus the need to explicitely call setSelectedImage.
[(ImageBrowserDelegate *)[self
delegate]
setSelectedImage:nil];
}
}
-(void)reloadData
{
[super
reloadData];
[self
scrollPoint:NSMakePoint(0, [self
frame].size.height)];
}
-(void)selectNextImage:(NSTimer *)timer
{
// get the index of the first selected image
int selectedImage = -1;
if ([self
selectionIndexes] != nil || [[self
selectionIndexes] count] !=
0)
selectedImage = (int)[[self
selectionIndexes]
firstIndex];
// increment it, and check for bound, and loop
++selectedImage;
int numImages = (int)[[self
dataSource] numberOfItemsInImageBrowser:nil];
if (selectedImage >= numImages)
{
if ([[timer
userInfo] boolValue] ==
YES)
{
selectedImage =
0;
}
else
{
selectedImage = (int)numImages -
1;
// also stop the slide show
[SlideShow
stopSlideShow];
}
}
// finally, set the new image
[self
setSelectionIndexes:[NSIndexSet
indexSetWithIndex:selectedImage]
byExtendingSelection:NO];
}
-(BOOL)showTitles
{
return [self
cellsStyleMask] & IKCellsStyleTitled;
}
-(void)setShowTitles:(BOOL)showTitles
{
if (showTitles ==
YES)
[self
setCellsStyleMask:[self
cellsStyleMask] | IKCellsStyleTitled];
else
[self
setCellsStyleMask:[self
cellsStyleMask] & ~IKCellsStyleTitled];
}
-(float)thumbnailMargin
{
return [self
intercellSpacing].width;
}
-(void)setThumbnailMargin:(BOOL)margin
{
[self
setIntercellSpacing:NSMakeSize(margin, margin)];
}
-(BOOL)setFullscreen
{
// if still nothing‘s selected, it means we don‘t have any image
// in the image browser, so simply break (launching a slideshow
// on an empty folder has no meaning :)
if ([self
selectionIndexes] == nil ||
[[self
selectionIndexes] count] ==
0)
return
NO;
// select only the first one
[self
setSelectionIndexes:[NSIndexSet
indexSetWithIndex:[[self
selectionIndexes] firstIndex]]
byExtendingSelection:NO];
// set the fullscreen property of the delegate (which is binded to the
// image view)
[(ImageBrowserDelegate *)[self
delegate]
setFullscreen:YES];
return
YES;
}
-(ImageItem *)itemAtIndex:(NSUInteger)index
{
return [[self
dataSource] imageBrowser:self
itemAtIndex:index];
}
-(NSArray *)selectedImagesAsURLArray
{
NSIndexSet * indexes = [self
selectionIndexes];
NSUInteger index = [indexes
firstIndex];
NSMutableArray * files = [NSMutableArray
arrayWithCapacity:[indexes
count]];
while (index !=
NSNotFound)
{
[files addObject:[NSURL
fileURLWithPath:[[self
itemAtIndex:index]
path]]];
index = [indexes
indexGreaterThanIndex:index];
}
return files;
}
-(NSArray *)selectedImagesAsTitelArray
{
NSIndexSet * indexes = [self
selectionIndexes];
NSUInteger index = [indexes
firstIndex];
NSMutableArray * files = [NSMutableArray
arrayWithCapacity:[indexes
count]];
while (index !=
NSNotFound)
{
[files addObject:[[self
itemAtIndex:index]
title]];
index = [indexes
indexGreaterThanIndex:index];
}
return files;
}
-(NSArray *)selectedImagesAsPhotoIDArray
{
NSIndexSet * indexes = [self
selectionIndexes];
NSUInteger index = [indexes
firstIndex];
NSMutableArray * files = [NSMutableArray
arrayWithCapacity:[indexes
count]];
while (index !=
NSNotFound)
{
[files addObject:[[self
itemAtIndex:index]
photo_id]];
index = [indexes
indexGreaterThanIndex:index];
}
return files;
}
-(NSArray *)selectedImagesAsPhotoPathArray
{
NSIndexSet * indexes = [self
selectionIndexes];
NSUInteger index = [indexes
firstIndex];
NSMutableArray * files = [NSMutableArray
arrayWithCapacity:[indexes
count]];
while (index !=
NSNotFound)
{
[files addObject:[[self
itemAtIndex:index]
photo_path]];
index = [indexes
indexGreaterThanIndex:index];
}
return files;
}
-(void)deleteSelectedImages
{
// remove files from the disk
NSArray * files = [self
selectedImagesAsURLArray];
for (NSURL * file
in files)
[[FileUtils
instance] removeItemAtPath:[file
path]];
}
-(void)cutSelectedImages
{
[[FileUtils
instance] cutItems:[self
selectedImagesAsURLArray]];
}
-(void)copySelectedImages
{
[[FileUtils
instance] copyItems:[self
selectedImagesAsURLArray]];
}
-(void)setSelectedImage:(NSString *)image
{
[(ImageBrowserDelegate *)[self
delegate]
setSelectedImage:image];
}
-(IBAction)selectAll:(id)sender
{
// check if we‘re not in fullscreen
if ([(ImageBrowserDelegate *)[self
delegate]
fullscreen] ==
YES)
return;
int numImages = (int)[[self
dataSource] numberOfItemsInImageBrowser:self];
if (numImages ==
0)
return;
// ensure the image browser is the first responder when it selects all
[[self
window] makeFirstResponder:self];
NSIndexSet * indexSet = [NSIndexSet
indexSetWithIndexesInRange:NSMakeRange(0, numImages)];
[self
setSelectionIndexes:indexSet byExtendingSelection:NO];
}
-(IBAction)deselectAll:(id)sender
{
// check if we‘re not in fullscreen
if ([(ImageBrowserDelegate *)[self
delegate]
fullscreen] ==
YES)
return;
[self
setSelectionIndexes:nil
byExtendingSelection:NO];
}
-(void)keyDown:(NSEvent *)theEvent
{
// get the event and the modifiers
NSString * characters = [theEvent
charactersIgnoringModifiers];
unichar event = [characters
characterAtIndex:0];
switch (event)
{
// space & p : play / pause slideshow
case
‘ ‘:
case
‘p‘:
if ([SlideShow
isRunning] == YES)
{
[SlideShow
stopSlideShow];
}
else
{
if ([self
setFullscreen] ==
YES)
[SlideShow
startSlideShow:self
callback:@"selectNextImage:"];
}
break;
// enter & escape : leave fullscreen
case
13:
case
27:
[self
setFullscreen];
break;
default:
[super
keyDown:theEvent];
}
}
-(void)otherMouseDown:(NSEvent *)theEvent
{
if ([theEvent
clickCount] == 1)
[self
setFullscreen];
}
@end
=============================================================
//ImageBrowserDelegate.h
#import <Cocoa/Cocoa.h>
@class IKImageBrowserView;
@class ImageBrowser;
@interface ImageBrowserDelegate:
NSObject
{
@private
NSString *
mSelectedImage;
ImageBrowser *
mImageBrowser;
BOOL
mIgnoreSelectionChanges;
BOOL
fullscreen;
}
@property BOOL
ignoreSelectionChanges;
@property BOOL
fullscreen;
@property (assign)
IBOutlet ImageBrowser *
imageBrowser;
-(id)init;
-(void)dealloc;
// used to bind the image view and the image browser view
-(NSString *)selectedImage;
-(void)setSelectedImage:(NSString *)image;
// implementation of IKImageBrowserDelegate protocol
-(void)imageBrowserSelectionDidChange:(IKImageBrowserView *)aBrowser;
-(void)imageBrowser:(IKImageBrowserView *)aBrowser cellWasDoubleClickedAtIndex:(NSUInteger)index;
-(NSUInteger)imageBrowser:(IKImageBrowserView *)aBrowser writeItemsAtIndexes:(NSIndexSet *)itemIndexes toPasteboard:(NSPasteboard
*)pasteboard;
@end
=============================================================
//ImageBrowserDelegate.mm
#import <Quartz/Quartz.h>
#import "ImageBrowserDelegate.h"
#import "ImageBrowser.h"
#import "ImageDataSource.h"
#import "ImageItem.h"
#import "../Utils/Utils.h"
#import "Document.h"
extern Document *g_Document;
@implementation ImageBrowserDelegate
@synthesize fullscreen;
@synthesize ignoreSelectionChanges
= mIgnoreSelectionChanges;
@synthesize imageBrowser
= mImageBrowser;
-(id)init
{
self = [super
init];
if (self !=
nil)
{
mSelectedImage
= nil;
mIgnoreSelectionChanges
= NO;
}
return
self;
}
-(void)dealloc
{
if (mSelectedImage !=
nil)
{
[mSelectedImage
release];
mSelectedImage =
nil;
}
[super
dealloc];
}
-(NSString *)selectedImage
{
return
mSelectedImage;
}
-(void)setSelectedImage:(NSString *)image
{
if (mSelectedImage != image)
{
// NOTE: here, we check if the image if different from the current one.
//
This means that if we reach this point, the selected image was
//
set by an external source (by binding or whatever)
//
This is also why we need to scroll the view to show the new
//
selected image.
if (mSelectedImage !=
nil)
[mSelectedImage
release];
mSelectedImage = [image
copy];
// update the selected image of the view
ImageDataSource *dataSource = (ImageDataSource *)[mImageBrowser
dataSource];
// get the index corresponding to the image
NSInteger imageIndex = [dataSource
indexOfImage:image];
NSIndexSet * indices = [NSIndexSet
indexSetWithIndex:imageIndex];
[mImageBrowser
setSelectionIndexes:indices byExtendingSelection:NO];
// scroll to selected image
[mImageBrowser
scrollIndexToVisible:imageIndex];
}
}
-(void)imageBrowserSelectionDidChange:(IKImageBrowserView *)aBrowser
{
if (mIgnoreSelectionChanges ==
YES)
return;
// get the selection indexes
NSIndexSet * selectionIndexes = [mImageBrowser
selectionIndexes];
// set the first selected image, so that any other view bound to
// selectedImage will be notified
if ([selectionIndexes
count] == 0)
{
[self
setSelectedImage:nil];
}
else
{
NSUInteger index = [selectionIndexes
firstIndex];
ImageItem * item = [[mImageBrowser
dataSource]
imageBrowser:nil
itemAtIndex:index];
[mSelectedImage
release];
mSelectedImage = [[item
path] copy];
NSLog(@"\nPath:\n%@",[item
path]);
NSLog(@"\nTitel:\n%@",[item
title]);
NSLog(@"\nPhoto_ID:\n%@",[item
photo_id]);
NSLog(@"\nPhoto_Path:\n%@",[item
photo_path]);
[self
setSelectedImage:[item path]];
NSString *msg=[NSString
stringWithFormat:@"File: \"%@\". ",[item
path]];
[g_Document
ShowMessageInBottom:msg];
}
}
-(void)imageBrowser:(IKImageBrowserView *)aBrowser cellWasDoubleClickedAtIndex:(NSUInteger)index
{
// NOTE: the fullscreen property of this instance is bound to the fullscreen
//
property of the image view, so this will automatically toggle
//
fullscreen without having a direct reference to ImageView
[self
setFullscreen:![self
fullscreen]];
}
-(NSUInteger)imageBrowser:(IKImageBrowserView *)aBrowser
writeItemsAtIndexes:(NSIndexSet *)itemIndexes
toPasteboard:(NSPasteboard *)pasteboard
{
NSArray * selectedImages = [mImageBrowser
selectedImagesAsURLArray];
[pasteboard clearContents];
[pasteboard writeObjects:selectedImages];
return [selectedImages
count];
}
@end
=============================================================
//ImageDataSource.h
#import <Cocoa/Cocoa.h>
#import "../Utils/FSEventsListener.h"
@class IKImageBrowserView;
@class ImageBrowser;
typedef struct ImageItemStruct
{
NSString *picture_id;
NSString *picture_name;
NSString *picture_file_size;
} A_ImageItemStruct;
/**
This is the image data source. It‘s responsible for giving access to all
the images contained in a single folder.
*/
@interface ImageDataSource:
NSObject<
FSEventListenerDelegate >
{
@private
/// the current directory. It‘s bound to the currently selected directory
NSString * mCurrentDirectory;
/// the associated view
ImageBrowser * mImageBrowser;
/// the images‘ paths.
NSMutableArray * mImages;
BOOL
isEmpty;
BOOL isSelectedAll;
}
@property (assign)
IBOutlet ImageBrowser *
imageBrowser;
@property (readonly)
NSArray *
images;
@property (readwrite)
BOOL
isEmpty;
@property (readwrite)
BOOL
isSelectedAll;
-(id)init;
-(void)dealloc;
// implementation of FSEventListenerDelegate protocol
-(void)fileWasAdded:(NSString *)file;
-(void)fileWasRemoved:(NSString *)file;
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile;
-(void)directoryWasAdded:(NSString *)directory;
-(void)directoryWasRemoved:(NSString *)directory;
-(void)directoryWasRenamed:(NSString *)oldDirectory to:(NSString *)newDirectory;
// this is used to bind the directory browser and the image data source
-(NSString *)currentDirectory;
-(void)setCurrentDirectory:(NSString *)path;
// these are internally used
-(void)addImage:(NSString *)path;
-(void)addImagesInPath:(NSString *)path;
// implementation of IKImageBrowserDataSource protocol
-(NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView *)view;
-(id)imageBrowser:(IKImageBrowserView *)view itemAtIndex:(NSUInteger)index;
// utility
-(NSInteger)indexOfImage:(NSString *)image;
-(NSArray *)imagesAtIndexes:(NSIndexSet *)indexes;
-(void)Show_ThumbnailImages:(NSString *)pic_folder;
-(void)SetSelected_All_or_None;
-(NSArray *)GetThumbnailImagesPaths:(id)sender;
-(NSArray *)GetThumbnailImagesTitles:(id)sender;
-(void) setID;
-(void) setImagesPath:(NSMutableArray *)data_Picture_ID
PhotoPath:(NSMutableArray *)data_Picture_Path
PhotoFileSize:(NSMutableArray *)data_File_Size;
-(A_ImageItemStruct) getPicturePath:(NSMutableArray *)data_Picture_ID
Picture_Path:(NSMutableArray *)data_Picture_Path
PhotoFileSize:(NSMutableArray *)data_File_Size
PictureID:(NSString *)strPhoto_ID;
-(NSArray *)get_selectedImagesAsPhotoIDArray;
-(NSArray *)get_selectedImagesAsPhotoPathArray;
@end
=============================================================
//ImageDataSource.mm
#import <Quartz/Quartz.h>
#import "ImageDataSource.h"
#import "ImageItem.h"
#import "ImageBrowser.h"
#import "../Utils/FileUtils.h"
#import "../Utils/FSEventsListener.h"
#import "../Utils/Utils.h"
ImageDataSource *g_ImageDataSource;
@implementation ImageDataSource
@synthesize imageBrowser
= mImageBrowser;
@synthesize images
= mImages;
@synthesize isEmpty;
@synthesize isSelectedAll;
-(id)init
{
self = [super
init];
if (self !=
nil)
{
mCurrentDirectory
= nil;
mImages
= [[NSMutableArray
alloc] init];
[self
setIsEmpty:YES];
g_ImageDataSource =
self;
isSelectedAll =
NO;
}
return
self;
}
-(void)dealloc
{
[mCurrentDirectory
release];
[mImages
release];
[super
dealloc];
}
-(NSString *)currentDirectory
{
return
mCurrentDirectory;
}
-(void)setCurrentDirectory:(NSString *)path
{
if (path !=
mCurrentDirectory && path !=
nil)
{
// unregister from the event listeners
[[FSEventsListener
instance]
removeListener:self
forPath:mCurrentDirectory];
// copy the new path
[mCurrentDirectory
release];
mCurrentDirectory = [path
copy];
// load images
[self
setIsEmpty:YES];
[mImages
removeAllObjects];
[self
addImagesInPath:mCurrentDirectory];
[mImageBrowser
reloadData];
// register with the new path
[[FSEventsListener
instance]
addListener:self
forPath:mCurrentDirectory];
}
}
-(void)addImagesInPath:(NSString *)path
{
// get the content of the directory
NSFileManager * fileManager = [NSFileManager
defaultManager];
NSURL * url = [NSURL
fileURLWithPath:path];
NSArray * content = [fileManager
contentsOfDirectoryAtURL:url
includingPropertiesForKeys:nil
options:NSDirectoryEnumerationSkipsHiddenFiles
error:nil];
// for each item, create an image object and add to the mImportedImages array
for (NSURL * url
in content)
{
[self
addImage:[url path]];
}
}
-(void)addImage:(NSString *)path
{
// error check
if ([FileUtils
isImage:path] == NO)
return;
// add the image item
ImageItem * image = [[ImageItem
alloc] init];
[image setPath:path];
[mImages
addObject:image];
[image release];
[self
setIsEmpty:NO];
}
-(void)fileWasAdded:(NSString *)file
{
[self
addImage:file];
[mImageBrowser
reloadDataAndKeepSelection];
}
-(void)fileWasRemoved:(NSString *)file
{
NSInteger index = [self
indexOfImage:file];
if (index == -1)
{
DEBUG_LOG(@"ImageDataSource - receive fileWasRemoved, "
@"but couldn‘t find the image [%@]", file);
return;
}
[mImages
removeObjectAtIndex:index];
[mImageBrowser
reloadDataAndKeepSelection];
[self
setIsEmpty:[mImages
count] > 0 ?
NO : YES];
}
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile
{
NSInteger index = [self
indexOfImage:oldFile];
if (index == -1)
{
// check if the newFile is an image, and if it‘s the case, add it.
if ([FileUtils
isImage:newFile] ==
YES)
[self
fileWasAdded:newFile];
return;
}
if ([FileUtils
isImage:newFile] ==
YES)
{
ImageItem * image = [self
imageBrowser:mImageBrowser
itemAtIndex:index];
[image setPath:newFile];
[mImageBrowser
reloadDataAndKeepSelection];
}
else
{
[self
fileWasRemoved:oldFile];
}
}
-(void)directoryWasAdded:(NSString *)directory
{
}
-(void)directoryWasRemoved:(NSString *)directory
{
}
-(void)directoryWasRenamed:(NSString *)oldDirectory to:(NSString *)newDirectory
{
}
-(NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView *)view
{
return [mImages
count];
}
-(id)imageBrowser:(IKImageBrowserView *)view itemAtIndex:(NSUInteger)index
{
return [mImages
objectAtIndex:index];
}
-(NSInteger)indexOfImage:(NSString *)image
{
NSInteger index =
0;
for (ImageItem * item
in mImages)
{
if ([[item
path] isEqualToString:image])
return index;
++index;
}
return -1;
}
-(NSArray *)imagesAtIndexes:(NSIndexSet *)indexes
{
NSMutableArray * images = [NSMutableArray
arrayWithCapacity:[indexes
count]];
NSUInteger index = [indexes
firstIndex];
while (index !=
NSNotFound)
{
[images addObject:[self
imageBrowser:nil
itemAtIndex:index]];
index = [indexes
indexGreaterThanIndex:index];
}
return images;
}
-(void)Show_ThumbnailImages:(NSString *)pic_folder
{
//NSString *path = @"/Users/mac2/Documents/test_photo/thumbnail_template_photo";
[self setCurrentDirectory:pic_folder];
}
-(void)SetSelectedAll
{
[mImageBrowser
selectAll:nil];
isSelectedAll =
TRUE;
}
-(void)SetSelectedNone
{
[mImageBrowser
deselectAll:nil];
isSelectedAll =
FALSE;
}
-(void)SetSelected_All_or_None
{
if (YES ==
isSelectedAll)
{
[self
SetSelectedNone];
}
else
{
[self
SetSelectedAll];
}
}
- (NSArray *)GetThumbnailImagesPaths:(id)sender
{
NSArray *files_selected ;
files_selected = [mImageBrowser
selectedImagesAsURLArray];
return files_selected;
}
- (NSArray *)GetThumbnailImagesTitles:(id)sender
{
NSArray *files_selected ;
files_selected = [mImageBrowser
selectedImagesAsTitelArray];
return files_selected;
}
-(void)setID
{
int images_count = (int)[mImages
count];
NSString *id_value=nil;
for (int i=0; i<images_count;i++)
{
ImageItem *image1 = [mImages
objectAtIndex:i];
id_value = image1.title;
id_value = [id_value stringByDeletingPathExtension];
[image1 setPhoto_ID:id_value];
}
}
/*
给这个函数传递当前所有的Photo的信息,然后通过给所有的ID找到实际对应在手机里的Path
*/
-(void) setImagesPath:(NSMutableArray *)data_Picture_ID
PhotoPath:(NSMutableArray *)data_Picture_Path
PhotoFileSize:(NSMutableArray *)data_File_Size
{
int images_count = (int)[mImages
count];
NSString *id_value=nil;
for (int i=0; i<images_count;i++)
{
ImageItem *image1 = [mImages
objectAtIndex:i];
id_value = image1.title;
id_value = [id_value stringByDeletingPathExtension];
id_value = [id_value stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceCharacterSet]];
//
使用id 从数组中找到
A_ImageItemStruct a_record;
a_record =[self
getPicturePath:data_Picture_ID
Picture_Path:data_Picture_Path
PhotoFileSize:data_File_Size
PictureID:id_value];
[image1 setPhoto_Path:a_record.picture_name];
[image1 setFile_Size:a_record.picture_file_size];
[image1 setTitle:[[a_record.picture_name
lastPathComponent] stringByDeletingPathExtension]];
}
[mImageBrowser
reloadData ];
}
-(A_ImageItemStruct) getPicturePath:(NSMutableArray *)data_Picture_ID
Picture_Path:(NSMutableArray *)data_Picture_Path
PhotoFileSize:(NSMutableArray *)data_File_Size
PictureID:(NSString *)strPhoto_ID
{
A_ImageItemStruct a_record;
NSString *photo_path =
nil;
NSString *photo_id =
nil;
NSString *photo_file_size =
nil;
int count =(int)[data_Picture_ID
count];
for (int i=0; i<count; i++)
{
photo_id = [data_Picture_ID objectAtIndex:i];
photo_path = [data_Picture_Path objectAtIndex:i];
photo_file_size = [data_File_Size objectAtIndex:i];
a_record.picture_file_size = photo_file_size;
a_record.picture_id = photo_id ;
a_record.picture_name = photo_path;
if (YES == [strPhoto_ID
isEqualToString:photo_id])
{
break;
}
}
return a_record;
}
-(NSArray *)get_selectedImagesAsPhotoIDArray
{
NSArray *files_selected;
files_selected = [mImageBrowser
selectedImagesAsPhotoIDArray];
return files_selected;
}
-(NSArray *)get_selectedImagesAsPhotoPathArray
{
NSArray *files_selected;
files_selected = [mImageBrowser
selectedImagesAsPhotoPathArray];
return files_selected;
}
@end
=============================================================
//ImageItem.h
#import <Cocoa/Cocoa.h>
/**
This class represents a single image.
*/
@interface ImageItem:
NSObject
{
@private
/// the path to the image file
NSString * mPath;
/// the title of the image. Usually the file name.
NSString * mTitle;
NSString *m_Photo_ID;
NSString *m_Photo_Path;
NSString *m_File_Size;
}
-(void)setPhoto_ID:(NSString *)photo_id;
-(NSString *)photo_id;
-(void)setFile_Size:(NSString *)photo_file_size;
-(NSString *)photo_file_size;
-(void)setPhoto_Path:(NSString *)photo_path;
-(NSString *)photo_path;
-(void)setPath:(NSString *)path;
-(NSString *)path;
-(void)setTitle:(NSString *)title;
-(NSString *)title;
-(NSString *)imageRepresentationType;
-(id)imageRepresentation;
-(NSString *)imageUID;
-(NSString *)imageTitle;
@end
=============================================================
//ImageItem.m
#import "ImageItem.h"
#import <Quartz/Quartz.h>
@implementation ImageItem
-(void)dealloc
{
[mPath
release];
[mTitle
release];
[m_Photo_Path
release];
[m_Photo_ID
release];
[m_File_Size
release];
[super
dealloc];
}
-(void)setPath:(NSString *)path
{
if (mPath != path)
{
[mPath
release];
[mTitle
release];
mPath
= [path retain];
mTitle
= [[mPath
lastPathComponent] copy];
}
}
-(NSString *)path
{
return
mPath;
}
-(void)setTitle:(NSString *)title
{
if (mTitle != title)
{
[mTitle
release];
mTitle = [title
copy];
}
}
-(void)setFile_Size:(NSString *)photo_file_size
{
if (m_File_Size != photo_file_size)
{
[m_File_Size
release];
m_File_Size = [photo_file_size
retain];
}
}
-(NSString *)photo_file_size
{
return
m_File_Size;
}
-(void)setPhoto_ID:(NSString *)photo_id
{
if (m_Photo_ID!= photo_id)
{
[m_Photo_ID
release];
m_Photo_ID = [photo_id
retain];
}
}
-(NSString *)photo_id
{
return
m_Photo_ID;
}
-(void)setPhoto_Path:(NSString *)photo_path
{
if (m_Photo_Path != photo_path)
{
[m_Photo_Path
release];
m_Photo_Path = [photo_path
retain];
}
}
-(NSString *)photo_path
{
return
m_Photo_Path;
}
-(NSString *)title
{
return
mTitle;
}
-(NSString *)imageRepresentationType
{
return
IKImageBrowserPathRepresentationType;
}
-(id)imageRepresentation
{
return
mPath;
}
-(NSString *)imageUID
{
return
mPath;
}
-(NSString *)imageTitle
{
if (mTitle ==
nil)
return [mPath
lastPathComponent];
return
mTitle;
}
@end
=============================================================
// FileUtils.h
#import <Cocoa/Cocoa.h>
/**
This class is responsible for interacting with the filesystem. It‘s meant
to be instanciated through a XIB file (I use awakFromNib to initialize it)
*/
@interface FileUtils:
NSObject
{
@private
NSMutableArray *
mCutItems;
NSMutableArray *
mCopiedItems;
NSString *
mDestinationDirectory;
}
@property (copy)
NSString *
destinationDirectory;
// init / deinit
-(void)awakeFromNib;
-(void)dealloc;
// global accessor
+(FileUtils *)instance;
// misc
+(BOOL)isImage:(NSString *)path;
+(BOOL)isGIF:(NSString *)path;
// delete / copy-cut / paste support
-(void)removeItemAtPath:(NSString *)path;
-(void)copyItems:(NSArray *)items;
-(void)cutItems:(NSArray *)items;
-(void)paste;
-(void)pasteTo:(NSString *)destination;
-(BOOL)canPaste;
-(void)setCanPaste:(BOOL)canPaste;
@end
=============================================================
// FileUtils.m
#import "FileUtils.h"
#import "Utils.h"
#import "SimpleProfiler.h"
@implementation FileUtils
static FileUtils * instance =
nil;
@synthesize destinationDirectory =
mDestinationDirectory;
-(void)awakeFromNib
{
instance
= self;
mDestinationDirectory
= nil;
mCutItems
= [[NSMutableArray
alloc] init];
mCopiedItems
= [[NSMutableArray alloc]
init];
}
-(void)dealloc
{
instance =
nil;
[mCutItems
release];
[mCopiedItems
release];
[mDestinationDirectory
release];
[super
dealloc];
}
+(FileUtils *)instance
{
return
instance;
}
+(BOOL)isImage:(NSString *)path
{
PROFILING_START(@"FileUtils - isImage");
NSString * extension = [[path
pathExtension] lowercaseString];
if ([extension
isEqualToString:@"jpg"] ==
YES ||
[extension isEqualToString:@"jpeg"] ==
YES ||
[extension isEqualToString:@"gif"] ==
YES ||
[extension isEqualToString:@"png"] ==
YES ||
[extension isEqualToString:@"psd"] ==
YES ||
[extension isEqualToString:@"tiff"] ==
YES ||
[extension isEqualToString:@"tif"] ==
YES ||
[extension isEqualToString:@"dng"] ==
YES ||
[extension isEqualToString:@"cr2"] ==
YES ||
[extension isEqualToString:@"raw"] ==
YES ||
[extension isEqualToString:@"pdf"] ==
YES)
{
PROFILING_STOP();
return
YES;
}
PROFILING_STOP();
return
NO;
}
+(BOOL)isGIF:(NSString *)path
{
NSString * extension = [[path
pathExtension] lowercaseString];
return [extension
isEqualToString:@"gif"];
}
-(void)removeItemAtPath:(NSString *)path
{
// check the preferences to see if we need to use the recycled bin, or
// permanently delete files
BOOL permanently =
YES;
//[[Preferences instance] boolForKey:@"permanentlyDeleteFiles"];
if (permanently ==
YES)
{
NSFileManager * fileManager = [NSFileManager
defaultManager];
[fileManager removeItemAtPath:path
error:NULL];
}
else
{
NSInteger tag =
0;
NSString * source = [path
stringByDeletingLastPathComponent];
NSArray * files = [NSArray
arrayWithObject:[path lastPathComponent]];
NSWorkspace * workspace = [NSWorkspace
sharedWorkspace];
[workspace
performFileOperation:NSWorkspaceRecycleOperation
source:source
destination:nil
files:files
tag:&tag];
}
}
/**
Private method used to clear previously copied/cut items.
*/
-(void)clear
{
[mCopiedItems
removeAllObjects];
[mCutItems
removeAllObjects];
}
-(void)copyItems:(NSArray *)items
{
[self
clear];
[mCopiedItems
addObjectsFromArray:items];
[self
setCanPaste:YES];
}
-(void)cutItems:(NSArray *)items
{
[self
clear];
[mCutItems
addObjectsFromArray:items];
[self
setCanPaste:YES];
}
-(BOOL)canPaste
{
if ([mCutItems
count] >
0 || [mCopiedItems
count] >
0)
return
YES;
return
NO;
}
-(void)setCanPaste:(BOOL)canPaste
{
// this is just used for binding : when an item is added to the copy or
// cut list, we call [self setCanPaste:whatever] to notify binded objects.
}
-(void)paste
{
if (mDestinationDirectory !=
nil)
[self
pasteTo:mDestinationDirectory];
}
-(void)pasteTo:(NSString *)destination
{
NSFileManager * fileManager = [NSFileManager
defaultManager];
// handle cut files
for (NSURL * url
in mCutItems)
{
// check if the destination folder is different from the source folder
if ([destination
isEqualToString:[[url path]
stringByDeletingLastPathComponent]])
continue;
NSURL * destinationURL = [NSURL
fileURLWithPath:destination];
destinationURL = [destinationURL
URLByAppendingPathComponent:[url lastPathComponent]];
// little hack : if the destination already exists, moving wont work,
// so I remove the destination before moving. This might be a bit
// "unsafe", but I don‘t want to bloat the code for something that will
// happen with a 0.000001% chance.
[fileManager removeItemAtURL:destinationURL
error:nil];
[fileManager moveItemAtURL:url
toURL:destinationURL
error:nil];
}
// handle copied files
for (NSURL * url
in mCopiedItems)
{
// check if the destination folder is different from the source folder
if ([destination
isEqualToString:[[url path]
stringByDeletingLastPathComponent]])
continue;
NSURL * destinationURL = [NSURL
fileURLWithPath:destination];
destinationURL = [destinationURL
URLByAppendingPathComponent:[url lastPathComponent]];
[fileManager copyItemAtURL:url
toURL:destinationURL
error:nil];
}
[self
clear];
}
@end
=============================================================
// FSEventsListener.h
#import <Foundation/Foundation.h>
/**
This defines a little protocol which should be implemented by objects that
want to be notified of file changes (objects set as delegate of the
FSEventsListener class)
*/
@protocol FSEventListenerDelegate<
NSObject >
@required
-(void)fileWasAdded:(NSString *)file;
-(void)fileWasRemoved:(NSString *)file;
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile;
-(void)directoryWasAdded:(NSString *)directory;
-(void)directoryWasRemoved:(NSString *)directory;
-(void)directoryWasRenamed:(NSString *)oldDirectory to:(NSString *)newDirectory;
@end
/**
This class is a little helper to create file system events listeners. It
allow to schedule event watching on a particular directory, and specify a
delegate which will be called on each supported event.
*/
@interface FSEventsListener
: NSObject
{
@private
NSDictionary *
mListeners;
FSEventStreamRef
mFileStream;
}
@property (assign)
NSDictionary *
listeners;
-(id)init;
-(void)dealloc;
// singleton handling
+(FSEventsListener *)instance;
+(void)destroy;
// handle listeners
-(void)addListener:(NSObject<
FSEventListenerDelegate > *)listener forPath:(NSString *)path;
-(void)removeListener:(NSObject<
FSEventListenerDelegate > *)listener forPath:(NSString *)path;
// utils
-(NSString *)formatPath:(NSString *)path;
// used to dispatch events to listeners
-(void)fileWasAdded:(NSString *)file;
-(void)fileWasRemoved:(NSString *)file;
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile;
-(void)directoryWasAdded:(NSString *)directory;
-(void)directoryWasRemoved:(NSString *)directory;
-(void)directoryWasRenamed:(NSString *)oldDirectory to:(NSString *)newDirectory;
@end
=============================================================
// FSEventsListener.m
#import "FSEventsListener.h"
#import "Utils.h"
#import "FileUtils.h"
void fsevents_callback(ConstFSEventStreamRef streamRef,
void * userData,
size_t numEvents,
void * eventPaths,
const
FSEventStreamEventFlags eventFlags[],
const
FSEventStreamEventId eventIds[]);
@implementation FSEventsListener
static FSEventsListener * instance =
nil;
@synthesize listeners
= mListeners;
-(id)init
{
self = [super
init];
if (self ==
nil)
return
nil;
mListeners = [[NSMutableDictionary
alloc]
init];
// create the context that will be associated to the stream. We pass a
// pointer to the FSEventsListener instance as user data.
FSEventStreamContext context = {
0, (void *)self,
NULL, NULL,
NULL };
// create the event stream, with a flag telling that we want to watch file
// level events. This will allow to directly retrieve the file names in the
// callback, instead of just the name of the directory
mFileStream =
FSEventStreamCreate(NULL,
&fsevents_callback,
&context,
(CFArrayRef)[NSArray
arrayWithObject:@"/"],
kFSEventStreamEventIdSinceNow,
(CFAbsoluteTime)0.2,
kFSEventStreamCreateFlagNoDefer);
// start the stream on the main event loop
FSEventStreamScheduleWithRunLoop(mFileStream,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
FSEventStreamStart(mFileStream);
// init the globally accessible instance
instance =
self;
return
self;
}
-(void)dealloc
{
// clear the instance
instance =
nil;
// stop and clean event stream
FSEventStreamStop(mFileStream);
FSEventStreamUnscheduleFromRunLoop(mFileStream,
CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
FSEventStreamInvalidate(mFileStream);
FSEventStreamRelease(mFileStream);
[mListeners
release];
[super
dealloc];
}
+(FSEventsListener *)instance
{
if (instance ==
nil)
{
[[FSEventsListener
alloc]
init];
}
return
instance;
}
+(void)destroy
{
if (instance !=
nil)
{
[instance
release];
instance =
nil;
}
}
/**
ensure pathes are always formated the same way : except for the root ‘/‘
path, every path must NOT end with a trailing ‘/‘
*/
-(NSString *)formatPath:(NSString *)path
{
if ([path
characterAtIndex:[path
length] - 1] ==
‘/‘)
{
return [path
substringToIndex:[path
length] - 1];
}
return [[path
copy] autorelease];
}
-(void)addListener:(NSObject<
FSEventListenerDelegate > *)listener forPath:(NSString *)path
{
NSString * formatedPath = [self
formatPath:path];
NSMutableArray * listeners = [mListeners
objectForKey:formatedPath];
if (listeners ==
nil)
{
[mListeners
setValue:[NSMutableArray
arrayWithObject:listener]
forKey:formatedPath];
}
else
{
[listeners addObject:listener];
}
}
-(void)removeListener:(NSObject<
FSEventListenerDelegate > *)listener forPath:(NSString *)path
{
NSString * formatedPath = [self
formatPath:path];
NSMutableArray * listeners = [mListeners
objectForKey:formatedPath];
if (listeners !=
nil)
{
[listeners removeObject:listener];
}
}
-(void)fileWasAdded:(NSString *)file
{
NSString * path = [file
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener fileWasAdded:file];
}
-(void)fileWasRemoved:(NSString *)file
{
NSString * path = [file
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener fileWasRemoved:file];
}
-(void)fileWasRenamed:(NSString *)oldFile to:(NSString *)newFile
{
NSString * path = [newFile
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener fileWasRenamed:oldFile
to:newFile];
}
-(void)directoryWasAdded:(NSString *)directory
{
NSString * path = [directory
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener directoryWasAdded:directory];
}
-(void)directoryWasRemoved:(NSString *)directory
{
NSString * path = [directory
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener directoryWasRemoved:directory];
}
-(void)directoryWasRenamed:(NSString *)oldDirectory to:(NSString *)newDirectory
{
NSString * path = [newDirectory
stringByDeletingLastPathComponent];
NSArray * listeners = [mListeners
objectForKey:path];
for (NSObject<
FSEventListenerDelegate > * listener
in listeners)
[listener directoryWasRenamed:oldDirectory
to:newDirectory];
}
@end
#define CHECK_STREAM(x, y) if (((x) & (y)) == (y)) NSLog(@" %s", #y);
void fsevents_callback(ConstFSEventStreamRef streamRef,
void * userData,
size_t numEvents,
void * eventPaths,
const
FSEventStreamEventFlags eventFlags[],
const
FSEventStreamEventId eventIds[])
{
static
NSString * previousRenamedPath = nil;
FSEventsListener * eventListener = (FSEventsListener *)userData;
size_t
i;
char ** paths
= eventPaths;
for (i =
0; i < numEvents; ++i)
{
NSString * newName = [NSString
stringWithFormat:@"%s", paths[i]];
// first, we handle events WITHOUT the renamed flag. Those are simple
// event, like "created", "removed". Note that when a device is mounted,
// or unmounted, a corresponding "created" or "removed" event is
// triggered, so we don‘t need to handle mount/unmount event.
if ((eventFlags[i] &
kFSEventStreamEventFlagUserDropped) ==
0)
{
if (eventFlags[i] &
kFSEventStreamEventFlagUserDropped)
{
// a file or directory was permanently deleted
//if (eventFlags[i] & kFSEventStreamEventFlagItemIsFile)
if (eventFlags[i])
{
[eventListener fileWasRemoved:newName];
}
else
if (eventFlags[i] &
kFSEventStreamEventFlagUnmount)
{
[eventListener directoryWasRemoved:newName];
}
}
else
if (eventFlags[i] &
kFSEventStreamEventFlagUserDropped)
{
// a file or directory was copied/created
//if (eventFlags[i] & kFSEventStreamEventFlagItemIsFile)
if (eventFlags[i])
{
[eventListener fileWasAdded:newName];
}
else
if (eventFlags[i] &
kFSEventStreamEventFlagUnmount)
{
[eventListener directoryWasAdded:newName];
}
}
}
else
{
// here, the "renamed" flag is present. From what I can guess
// through experiments, when a file is renamed, or moved, or sent
// to the trash, it triggers 2 successive renamed events. The first
// contains the source file, the second the destination file.
// So I just use a static string to store the first event path and
// detect if it‘s the first or second event.
if (previousRenamedPath ==
nil)
{
previousRenamedPath = [newName
retain];
}
else
{
NSString * newDir = [newName
stringByDeletingLastPathComponent];
NSString * oldName = previousRenamedPath;
NSString * oldDir = [oldName
stringByDeletingLastPathComponent];
//if (eventFlags[i] & kFSEventStreamEventFlagItemIsFile)
if (eventFlags[i])
{
if ([oldDir
isEqualToString:newDir])
{
// both directory are the same : file renamed
[eventListener fileWasRenamed:oldName
to:newName];
}
else
{
// directories are different, the file was moved
[eventListener fileWasAdded:newName];
[eventListener fileWasRemoved:oldName];
}
}
else
if (eventFlags[i] &
kFSEventStreamEventFlagUnmount)
{
if ([oldDir
isEqualToString:newDir])
{
// both directory are the same : renamed
[eventListener directoryWasRenamed:oldName
to:newName];
}
else
{
// directories are different, the directory was moved
[eventListener directoryWasAdded:newName];
[eventListener directoryWasRemoved:oldName];
}
}
// reset the previous renamed path.
SAFE_RELEASE(previousRenamedPath);
}
}
#if defined(DEBUG)
// NSLog(@"event [%d] [%d] [%s]", (int)eventIds[i], eventFlags[i], paths[i]);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagNone);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagMustScanSubDirs);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagUserDropped);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagKernelDropped);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagEventIdsWrapped);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagHistoryDone);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagRootChanged);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagMount);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagUnmount);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemCreated);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemRemoved);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemInodeMetaMod);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemRenamed);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemModified);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemFinderInfoMod);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemChangeOwner);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemXattrMod);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemIsFile);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemIsDir);
// CHECK_STREAM(eventFlags[i], kFSEventStreamEventFlagItemIsSymlink);
#endif // _DEBUG
}
}
=============================================================
//SimpleProfiler.h
#import <Cocoa/Cocoa.h>
@class ProfilingEntry;
@interface SimpleProfiler:
NSObject
{
@private
NSMutableDictionary *
mEntries;
}
+(SimpleProfiler *)instance;
+(void)destroyInstance;
-(id)init;
-(void)dealloc;
-(void)addEntry:(NSString *)name withTime:(double)time;
-(void)log;
@end
@interface ProfilingEntry
: NSObject
{
@private
NSString *
mName;
NSMutableArray *
mTimes;
}
@property (copy)
NSString * name;
+(ProfilingEntry *)entryWithName:(NSString *)name;
-(id)init;
-(void)dealloc;
-(double)averageTime;
-(void)addTime:(double)time;
@end
#if defined(PROFILING)
# define PROFILING_START(name) \
NSString * __name = name; \
NSDate * __date = [NSDate date]
#else
# define PROFILING_START(name)
#endif
#if defined(PROFILING)
# define PROFILING_STOP() \
[[SimpleProfiler instance] addEntry:__name \
withTime:[[NSDate date] timeIntervalSinceDate:__date]]
#else
# define PROFILING_STOP()
#endif
=============================================================
// SimpleProfiler.m
#import "SimpleProfiler.h"
static SimpleProfiler * mSimpleProfilerInstance =
nil;
@implementation SimpleProfiler
+(SimpleProfiler *)instance
{
if (mSimpleProfilerInstance ==
nil)
mSimpleProfilerInstance = [[SimpleProfiler
alloc]
init];
return
mSimpleProfilerInstance;
}
+(void)destroyInstance
{
if (mSimpleProfilerInstance !=
nil)
{
[mSimpleProfilerInstance
release];
mSimpleProfilerInstance =
nil;
}
}
-(id)init
{
self = [super
init];
if (self)
{
mEntries = [[NSMutableDictionary
alloc]
init];
}
return
self;
}
-(void)dealloc
{
[mEntries
removeAllObjects];
[mEntries
release];
[super
dealloc];
}
-(void)addEntry:(NSString *)name withTime:(double)time
{
ProfilingEntry * entry =
nil;
entry = [mEntries
objectForKey:name];
if (entry ==
nil)
{
entry = [ProfilingEntry
entryWithName:name];
[mEntries
setValue:entry forKey:name];
}
[entry addTime:time];
}
-(void)log
{
if ([mEntries
count] == 0)
return;
NSLog(@"Profiling log");
for (ProfilingEntry * entry
in [mEntries
allValues])
{
NSLog(@"%@ -- %f", [entry
name], [entry averageTime]);
}
}
@end
@implementation ProfilingEntry
@synthesize name = mName;
+(ProfilingEntry *)entryWithName:(NSString *)name
{
ProfilingEntry * entry = [[[ProfilingEntry
alloc]
init] autorelease];
[entry setName:name];
return entry;
}
-(id)init
{
self = [super
init];
if (self)
{
mName =
nil;
mTimes = [[NSMutableArray
alloc]
init];
}
return
self;
}
-(void)dealloc
{
[mName
release];
[mTimes
release];
[super
dealloc];
}
-(double)averageTime
{
double averageTime =
0.0;
for (NSNumber * number
in mTimes)
{
averageTime += [number
doubleValue];
}
return averageTime / (double)[mTimes
count];
}
-(void)addTime:(double)time
{
[mTimes
addObject:[NSNumber
numberWithDouble:time]];
}
@end
=============================================================
// SlideShow.h
#import <Foundation/Foundation.h>
@interface SlideShow
: NSObject
{
}
+(void)startSlideShow:(NSObject *)target callback:(NSString *)callback;
+(void)stopSlideShow;
+(BOOL)isRunning;
@end
=============================================================
// SlideShow.m
#import "SlideShow.h"
#import "Utils.h"
@implementation SlideShow
static NSTimer * slideshowTimer =
nil;
+(void)startSlideShow:(NSObject *)target callback:(NSString *)callback
{
if (slideshowTimer !=
nil)
[SlideShow
stopSlideShow];
// get the slideshow user preferences
NSUserDefaultsController * defaults = [NSUserDefaultsController
sharedUserDefaultsController];
BOOL loop = [[[defaults
values] valueForKey:@"slideshowLoop"]
boolValue];
float interval = [[[defaults
values] valueForKey:@"slideshowInterval"]
floatValue];
// launch the slideshow. I use a simple NSTimer with scheduledTimerWithTimeInterval.
// This method creates the timer and automatically fire it after "interval" secondes.
slideshowTimer = [NSTimer
scheduledTimerWithTimeInterval:interval
target:target
selector:NSSelectorFromString(callback)
userInfo:loop ?
@"Y" : @"N"
repeats:YES];
[slideshowTimer
setFireDate:[NSDate
dateWithTimeIntervalSinceNow:interval]];
}
+(void)stopSlideShow
{
if (slideshowTimer !=
nil)
{
[slideshowTimer
invalidate];
[slideshowTimer
release];
slideshowTimer =
nil;
}
}
+(BOOL)isRunning
{
return
slideshowTimer == nil ?
NO :
YES;
}
@end
=============================================================
// Utils.h
#import <AppKit/AppKit.h>
@interface Utils
: NSObject
{
}
+(void)bind:(id)src
keyPath:(NSString *)srcKey
to:(id)dest
keyPath:(id)destKey
continuous:(BOOL)continuous
twoWay:(BOOL)twoWay;
+(NSMutableParagraphStyle *)defaultParagraphStyle;
+(NSSize)stringSize:(NSString *)string withAttribute:(NSDictionary *)attributes;
@end
// Use this macro to output debug infos and strip them in release
#if defined(DEBUG)
# define DEBUG_LOG(...) NSLog(__VA_ARGS__)
#else
# define DEBUG_LOG(...)
#endif
// Use this macro to do something only in debug
#if defined(DEBUG)
# define DEBUG_ONLY(args) args
#else
# define DEBUG_ONLY(args)
#endif
// This macro is used when launching the ImageViewer from outside XCode :
// since we don‘t have access to the log, we need a way to debug
#if defined(DEBUG)
# define DEBUG_ALERT(...) \
{ \
NSAlert * __alert = [[[NSAlert alloc] init] autorelease]; \
[__alert setMessageText:[NSString stringWithFormat:__VA_ARGS__]]; \
[__alert runModal]; \
}
#else
# define DEBUG_ALERT(...)
#endif
// this macro is used to release an object and re-assign its value to nil, only
// if it‘s different from nil.
#if !defined(SAFE_RELEASE)
# define SAFE_RELEASE(x) if ((x) != nil) { [(x) release]; (x) = nil; }
#endif
=============================================================
// Utils.m
#import "Utils.h"
@implementation Utils
+(void)bind:(id)src
keyPath:(NSString *)srcKey
to:(id)dest
keyPath:(id)destKey
continuous:(BOOL)continuous
twoWay:(BOOL)twoWay
{
NSMutableDictionary * options =
nil;
if (continuous ==
YES)
{
options = [[NSMutableDictionary
alloc] init];
[options
setObject:[NSNumber
numberWithBool:YES]
forKey:NSContinuouslyUpdatesValueBindingOption];
}
[src bind:srcKey
toObject:dest withKeyPath:destKey
options:options];
if (twoWay ==
YES)
[dest bind:destKey
toObject:src withKeyPath:srcKey
options:options];
[options release];
}
+(NSMutableParagraphStyle *)defaultParagraphStyle
{
return [[[NSParagraphStyle
defaultParagraphStyle] mutableCopy]
autorelease];
}
+(NSSize)stringSize:(NSString *)string withAttribute:(NSDictionary *)attributes
{
NSAttributedString * attributedString = [NSAttributedString
alloc];
attributedString = [attributedString
initWithString:string];
NSSize size = [attributedString
size];
[attributedString
release];
return size;
}
@end
=============================================================
//
// Document.h
#import <Cocoa/Cocoa.h>
@interface Document :
NSPersistentDocument
@property (assign)
IBOutlet NSTextField *m_LB1;
-(void)ShowMessageInBottom:(NSString *)msg;
@end
=============================================================
//
// Document.m
// Created 2014-11-13 by DMD
// ShenZhen In China
#import "Document.h"
#import "ImageDataSource.h"
extern ImageDataSource *g_ImageDataSource;
Document *g_Document;
@implementation Document
@synthesize m_LB1;
- (id)init
{
self = [super
init];
if (self)
{
g_Document =
self;
}
return
self;
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return
@"Document";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super
windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has loaded the document‘s window.
}
+ (BOOL)autosavesInPlace
{
return
YES;
}
- (IBAction)OnBT_SelectFolder:(id)sender
{
NSOpenPanel *panel = [NSOpenPanel
openPanel];
NSString *msg=[NSString
stringWithFormat:@"Select a folder"];
//不让新打开的窗口在新窗口出现标题
[panel setMessage:msg];
[panel setPrompt:@"OK"];
[panel setCanChooseDirectories:YES];
[panel setCanCreateDirectories:YES];
[panel setCanChooseFiles:NO];
[panel beginSheetModalForWindow:[NSApp
mainWindow] completionHandler:^(NSInteger result)
{
NSString *selected_folder=@"";
if (result ==
NSFileHandlingPanelOKButton)
{
selected_folder=[[panel URL]
path];
[g_ImageDataSource
Show_ThumbnailImages:selected_folder];
}
}];
}
- (IBAction)OnBT_SelectedAll:(id)sender
{
[g_ImageDataSource
SetSelected_All_or_None];
}
- (IBAction)OnBT_ChangeTitle:(id)sender
{
//picture_id
[g_ImageDataSource
setID];
//picture_path
NSMutableArray *array_image_id = [[NSMutableArray
alloc] init];
NSMutableArray *array_image_path = [[NSMutableArray
alloc] init];
NSMutableArray *array_image_file_size = [[NSMutableArray
alloc] init];
int i=0;
int i_pic_count =
10;//file_count, need you change
NSString *picture_id=nil;
NSString *picture_path=nil;
NSString *picture_file_size =
nil;
for (; i<i_pic_count; i++)
{
picture_id =[NSString
stringWithFormat:@"ID%d",i+1];
picture_path =[NSString
stringWithFormat:@"Path%d",i+1];
picture_file_size=[NSString
stringWithFormat:@"Size%d",i+1];
[array_image_id addObject:picture_id];
[array_image_path addObject:picture_path];
[array_image_file_size addObject:picture_file_size];
}
[g_ImageDataSource
setImagesPath:array_image_id
PhotoPath:array_image_path
PhotoFileSize:array_image_file_size];
}
-(void)ShowMessageInBottom:(NSString *)msg
{
m_LB1.stringValue = msg;
}
@end
操作的时候需要注意:
=============================================================
完:
本人测试成功!
以上代码还有不完善之处,请根据自己的需要修改。
2014-11-13 Created By DMD