/*
        Controller.m

	Controller.m : This file is part of SlideShow

	Copyright (C) 2004 Fabien VALLON
	Additional copyrights here

	Authors: Fabien VALLON <fabien.vallon@fr.alcove.com>
	Date:	17 August 2004

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License as
	published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program 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 General Public License for more details.

	You should have received a copy of the GNU General Public
	License along with this program; if not, write to:

		Free Software Foundation, Inc.
		59 Temple Place - Suite 330
		Boston, MA  02111-1307, USA
*/

#include "Controller.h"
#include "ConvertKeys.h"


#include <Foundation/NSArray.h>
#include <Foundation/NSConnection.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSPathUtilities.h>
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSValue.h>

#include <AppKit/NSApplication.h>
#include <AppKit/NSBrowser.h>
#include <AppKit/NSBezierPath.h>
#include <AppKit/NSBrowserCell.h>
#include <AppKit/NSButton.h>
#include <AppKit/NSEvent.h>
#include <AppKit/NSImage.h>
#include <AppKit/NSImageView.h>
#include <AppKit/NSMatrix.h>
#include <AppKit/NSOpenPanel.h>
#include <AppKit/NSPasteboard.h>
#include <AppKit/NSPopUpButton.h>
#include <AppKit/NSScreen.h>
#include <AppKit/NSTextField.h>
 

static NSString *IMAGEWINDOWFRAME = @"IMAGEWINDOWFRAME";
static NSString *BROWSERWINDOWFRAME = @"BROWSERWINDOWFRAME";




@interface MarkView : NSView
@end

@implementation MarkView

-(BOOL) isOpaque
{
  return NO;
}

- (void)drawRect:(NSRect)aRect
{
   NSColor *transparentYellow;
   transparentYellow = [NSColor colorWithCalibratedRed: 1.0
				green: 1.0
				blue: 0.0
				alpha: 0.333];
   [transparentYellow set];
   [NSBezierPath fillRect: aRect];
}

@end


/*
 * Controller categories : 
 * Files management: add/remove files (used form NSOpenPanel) and set/get the last
 * directory  OpenPanel should show
 */

@interface Controller (FilesManagment)
-(NSString *) _currentDirectory;
-(void) _setCurrentDirectory:(NSString *) directrory;
-(void) _addImagesFromList:(NSArray*) paths;
-(void) _addImagesFromDirectory: (NSString*) path;
@end



/*
 * Controller categories: 
 * Display and mantain marks
 */

@interface Controller (Marks)
-(void) _markForCurrentSlide;
-(void) _drawMark;
@end


/*
 * Controller categories: Services provider
 * open images files / directory and slide show them from services ( with NSFilenamesPboardType )
 * see SlideShowInfo.plist too
 */ 
@interface Controller (Services)
- (void) slideShowWithPaths: (NSPasteboard *) pboard
		   userData: (NSString *) userData
		      error: (NSString **) error;
- (void) slideShowWithDirectory: (NSPasteboard *) pboard
		       userData: (NSString *) userData
			  error: (NSString **) error;
@end



/*
* Controller (SlideShowCommands)
*/
@interface Controller (SlideShowCommands)
-(void) _updateUI;
-(void) _displaySlide;
-(void) _nextImage;
-(void) _previousImage;
-(void) _showSlideShowMenu;
-(void) _startSlideShow;
-(void) _quitFullScreen;
-(void) _defaultsChanged:(NSNotification *) aNotification;
@end






@implementation Controller (FilesManagment)

//Get the directory from defaults, if it does not extists 
//return homeDirectory
-(NSString *) _currentDirectory
{
  NSFileManager *fileManager = [NSFileManager defaultManager];
  BOOL isDir;
  NSString *path;
  
  if (( path =  [[NSUserDefaults standardUserDefaults] objectForKey:@"OPENSAVEDIRECTORY"] ))
    {
      if ( ( [fileManager fileExistsAtPath:path isDirectory:&isDir] ) && ( isDir ) )
	{
	  return path;
	}
    }

  return NSHomeDirectory ();
}


//Save the directory to defaults if exists
-(void) _setCurrentDirectory:(NSString *) directory
{
  if ( ! directory ) 
    return;
  else
    {
      NSFileManager *fileManager = [NSFileManager defaultManager];
      BOOL isDir;

      if ( ( [fileManager fileExistsAtPath:directory isDirectory:&isDir] ) && ( isDir ) )
	{
	  [[NSUserDefaults standardUserDefaults] setObject: directory forKey:@"OPENSAVEDIRECTORY"];
	}
    }
}

//Add Images from an array of paths
-(void) _addImagesFromList:(NSArray*) paths
{
  if ( ! (paths) || ([paths count] == 0) ) 
    return;
  else
    {
      unsigned int i,count = [paths count];
      BOOL isFirstAdded = YES;
      NSString *filePath;
      NSArray *imageFileTypes = [NSImage imageFileTypes];
      NSMutableArray *files = [[NSMutableArray alloc] init];
    
      if ( [_backend count] > 0 ) 
	isFirstAdded = NO;

      for (i=0; i<count; i++)
	{
	  filePath = [paths objectAtIndex:i];
	  if ( ( ! filePath )  || ( ! [imageFileTypes containsObject:[filePath pathExtension]] ) )
	    continue;
	  else
	    {
	      id slide=[[SlideObject alloc] init];
	      [slide setPath: filePath];
	      [_backend addObject:slide];
	      [files addObject: filePath];
	    }
	}

      if ( [files count] > 0 )
	{
	  [cacheEngine addImagePaths:files];
	  [self _updateUI];
	}
      if ( isFirstAdded ) 
	{
	  [browser selectRow:0 inColumn:0];
	  _current = 0;
	  [self _displaySlide];
	  [browserWindow makeKeyAndOrderFront:self];
	}
    }
}

-(void) _addImagesFromDirectory: (NSString*) path
{
  NSDirectoryEnumerator *dirEnum;

  //TODO check if path exists & isDir ? 
  if  ( ! path ) 
    return;

  else
    {
      NSMutableArray *filesArray = [[NSMutableArray alloc] init];
      id object;
      dirEnum = [[NSDirectoryEnumerator alloc]
                  initWithDirectoryPath: path
                  recurseIntoSubdirectories: YES
                  followSymlinks: NO
                  justContents: NO];
      
      while ( ( object = [dirEnum nextObject] ) )
	{
	  [filesArray addObject:[path stringByAppendingPathComponent:object]];
	}

      [self _addImagesFromList: filesArray];      
    }
}


@end


@implementation Controller (Marks)

-(void)_markForCurrentSlide 
{
  SlideObject *slide = [_backend objectAtIndex:_current];

  if (  [_marksArray containsObject:slide] )
      [_marksArray removeObject:slide];
  else
      [_marksArray addObject:slide];

  [self _drawMark];
}

-(void) _drawMark
{
  if ( [[[_slideShow contentView] subviews] containsObject: markView] )
    {
      [[_slideShow contentView] removeSubview:markView];
    }
  
  if ( [_marksArray containsObject:[_backend objectAtIndex:_current]] )
    {
      markView = [[MarkView alloc] initWithFrame:NSMakeRect(10,10,60,60)];
      [[_slideShow contentView] addSubview:markView];
    }
  else
    [[_slideShow contentView] setNeedsDisplay: YES];
}

@end


@implementation Controller (Services)

- (void) slideShowWithPaths: (NSPasteboard *) pboard
		   userData: (NSString *) userData
		      error: (NSString **) error
{
  NSFileManager *manager;
  BOOL isDir;
  NSArray *allFiles, *allTypes;
  NSMutableArray *files;
  NSEnumerator *enumerator;
  NSString *aFile;
  
  NSAutoreleasePool *pool;

  pool = [[NSAutoreleasePool alloc] init];
  manager = [NSFileManager defaultManager];
  files = [[NSMutableArray alloc] init];

  allTypes = [pboard types];

  if ( ! [allTypes containsObject: NSFilenamesPboardType] )
    {
      *error = @"No filenames supplied on pasteboard";
      RELEASE(pool);
      return;
    }

  allFiles = [pboard propertyListForType: NSFilenamesPboardType];

  if (! allFiles )
    {
      *error = @"No files supplied on pasteboard";
      RELEASE(pool);
      return;
    }


  enumerator = [allFiles objectEnumerator];
  
  while ( (aFile = [enumerator nextObject]) )
    {
      if ( ( [manager fileExistsAtPath: aFile  isDirectory: &isDir])  || ( !isDir)  )
        {
	  [files addObject: aFile];
	}
    }
  
  [self _addImagesFromList:files];
  if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"FULLSCREENFROMSERVICES"] ) 
    [self _startSlideShow];

  RELEASE(pool);
}


- (void) slideShowWithDirectory: (NSPasteboard *) pboard
		       userData: (NSString *) userData
 			  error: (NSString **) error
{
  NSFileManager *manager;
  BOOL isDir;
  NSArray *allFiles, *allTypes;
  NSMutableArray *files;
  NSEnumerator *enumerator;
  NSString *aFile;
  
  NSAutoreleasePool *pool;

  pool = [[NSAutoreleasePool alloc] init];
  manager = [NSFileManager defaultManager];
  files = [[NSMutableArray alloc] init];

  allTypes = [pboard types];

  if ( ! [allTypes containsObject: NSFilenamesPboardType] )
    {
      *error = @"No filenames supplied on pasteboard";
      RELEASE(pool);
      return;
    }

  allFiles = [pboard propertyListForType: NSFilenamesPboardType];

  if (! allFiles )
    {
      *error = @"No files supplied on pasteboard";
      RELEASE(pool);
      return;
    }


  enumerator = [allFiles objectEnumerator];
  
  while ( (aFile = [enumerator nextObject]) )
    {
      if ( ( [manager fileExistsAtPath: aFile  isDirectory: &isDir])  || (isDir)  )
        {
	  [files addObject: aFile];
	}
    }
  
  [self _addImagesFromDirectory:[files objectAtIndex:0]];
  if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"FULLSCREENFROMSERVICES"] ) 
    [self _startSlideShow];
  RELEASE(pool);
}

@end


@implementation Controller (SlideShowCommands)

-(void) _updateUI
{

  [browser reloadColumn:0];


  if ( [_backend count] > 0 )
    {
      [fullScreenButton setEnabled: YES];
      [markSwitch setEnabled: YES];
    }
  else
    {
      [fullScreenButton setEnabled: NO];
      [markSwitch setEnabled: NO];
    }

  if ( [_backend count] > 1 )
    [slideShowSwitch setEnabled: YES];
  else
    {
      [slideShowSwitch setEnabled: NO];
      [slideShowTextField setEnabled: NO];
      [slideShowTextField setSelectable: NO];
      [slideShowTextField setEditable: NO];
      [secondLabel setEnabled: NO];
      [startButton setEnabled: NO];
      [stopButton setEnabled: NO];
    }



  
  if ( [_marksArray count] > 0 )
    [showPopUp setEnabled:YES];
  else
    [showPopUp setEnabled: NO];  
}

-(void) _displaySlide 
{
  if ( [_slideShow isVisible] ) 
    {
      NSImage *image; 
      NSString *path = [[_backend objectAtIndex:_current] path];
      image = [[NSImage alloc] initWithData:[cacheEngine imageForPath:path]];
      [cacheEngine userUsePath:path];

      if ( ! image  ) 
	{
#warning inform the user
	  return;
	}  

      [_imageView setImage: image];
      [image autorelease];
      [self _drawMark];
    }
  else
    {
      NSImage *image = [[NSImage alloc] initWithContentsOfFile: [[_backend objectAtIndex:_current] path]];
      if (! image ) 
	{
	  NSLog(@"WARNING cannot openImage is  for this object WARNING :TODO Warm the user");
	  return;
	}

      [imageView setImage: image];
      [image autorelease];
      [imageWindow setTitle:[[[_backend objectAtIndex:_current] shortName] 
			       stringByDeletingPathExtension]];
    }
}

-(void) _nextImage
{
  //Display slide if this is not the end of the list
  if ( _current == ( [_backend count] -1 )) 
    {
      if  ( _timer )
      {
	if  ( [_timer isValid] ) 
	  [_timer invalidate];
	[stopButton setEnabled: NO];
	[startButton setEnabled: YES];
      }
      
      return;
    }

  _current++;
  [self _displaySlide];

  //refresh browser (TODO : maybye check if visible)
  [[browser matrixInColumn:0] deselectAllCells];
  [browser selectRow:_current inColumn:0];
}


-(void) _previousImage
{
  //Display slide if this is not the beggining of the list
  if ( _current <= 0 ) 
    return;

  _current--;
  [self _displaySlide];
  
  //refresh browser (TODO : maybye check if visible)
  [[browser matrixInColumn:0] deselectAllCells];
  [browser selectRow:_current inColumn:0];
}




-(void) _showSlideShowMenu
{
  if (  slideShowMenu ) 
    {
      [slideShowMenu removeFromSuperview];
      slideShowMenu = nil;
    }
  else
    {
      slideShowMenu = [[SlideShowMenu alloc] initWithFrame:NSMakeRect(300,300,400,100)];
      [[_slideShow contentView] addSubview: slideShowMenu];
      
      [slideShowMenu addItemAtIndex:0
		     withImage: [NSImage imageNamed:@"arrowLeft"]
		     alternateImage: nil
		     target:self
		     selector:@selector(showPreviousImage:)];

      [slideShowMenu addItemAtIndex:1
		     withImage: [NSImage imageNamed:@"arrowRight"]
		     alternateImage: nil
		     target:self
		     selector:@selector(showNextImage:)];


      [slideShowMenu addItemAtIndex:2
		     withImage: [NSImage imageNamed:@"addmark"]
		     alternateImage: nil
		     target:self
		     selector:@selector(mark:)];

      [slideShowMenu addItemAtIndex:3
		     withImage: [NSImage imageNamed:@"quit"]
		     alternateImage: nil
		     target:self
		     selector:@selector(fullscreenAction:)];


      [slideShowMenu addItemAtIndex:4
		     withImage: [NSImage imageNamed:@"rotateLeft"]
		     alternateImage: nil
		     target:self
		     selector:NULL];

      [slideShowMenu addItemAtIndex:5
		     withImage: [NSImage imageNamed:@"rotateRight"]
		     alternateImage: nil
		     target:self
		     selector:NULL];

      [slideShowMenu addItemAtIndex:6
		     withImage: [NSImage imageNamed:@"hideSlideShowMenu"]
		     alternateImage: nil
		     target:self
		     selector:@selector(_showSlideShowMenu:)];

      [[_slideShow contentView] setNeedsDisplay:YES];
    }
}


-(void) _startSlideShow
{
  if ( [_backend count] == 0 ) 
    return;
  
  if ( ! _slideShow ) 
    {
      if ( ! (_slideShow = [SlideShowWindow sharedSlideShowWindow]) ) 
	return;
      else
	{
	  NSColor * aColor =nil;
	  NSData *theData=[[NSUserDefaults standardUserDefaults] dataForKey:@"BGCOLOR"];

	  if ( theData )
	    aColor =(NSColor *)[NSUnarchiver unarchiveObjectWithData:theData];
	  else
	    aColor = [NSColor blackColor];
	  
	  if ( _slideShow )
	    [_slideShow setBackgroundColor: aColor];

	  [_slideShow setDelegate:self];
	  
	  [_slideShow setBackgroundColor:aColor];
	}
    }
  
  [_slideShow makeKeyAndOrderFront:self];


  if ( ! _imageView ) 
    {
      _imageView = [[NSImageView alloc] initWithFrame:[_slideShow frame]];
      [_imageView setImageScaling: NSScaleNone ];
      [_imageView setEditable:NO];
      [[_slideShow contentView] addSubview: _imageView];
    }
  
  int tag = [browser selectedRowInColumn:0];
  if ( tag == -1  ) 
    tag = 0;
    
  _current = tag;
  [self _displaySlide];
}


-(void) _quitFullScreen
{
  if ( ! _slideShow ) 
    return;
  else
    {
      id image;
      [_slideShow orderOut:self];

      //mark
      [browser reloadColumn:0];
      [browser selectRow:_current inColumn:0];
      
      image = [[NSImage alloc] initWithContentsOfFile:[[_backend objectAtIndex:_current] path]];
      
      if ( ! image  ) 
	{
#warning inform the user
	  NSLog(@"Cannot open image");
	  return;
	}  
      
      if ( imageView ) 
	{
	  [imageView setImage: image];
	  [image autorelease];
	}
      
    }
}


-(void) _defaultsChanged:(NSNotification *) aNotification
{
  NSColor * aColor =nil;
  NSData *theData=[[NSUserDefaults standardUserDefaults] dataForKey:@"BGCOLOR"];
  if ( theData )
    aColor =(NSColor *)[NSUnarchiver unarchiveObjectWithData:theData];
    
  if ( _slideShow )
    [_slideShow setBackgroundColor: aColor];

#warning todo update marks
}


@end //Controller (Private)



/*
 * Controller implementation
 */

@implementation Controller

-(void) applicationDidFinishLaunching:(NSNotification*) notification
{
  [NSApp setServicesProvider: self];
}

-(void) awakeFromNib
{
  //alloc/init some ivars
  {
    _backend = [[NSMutableArray alloc] init];
    _marksArray = [[NSMutableArray alloc] init];
    _current =0;
    markView = [[MarkView alloc] initWithFrame:NSMakeRect(10,10,60,60)];
    
  }

  // Start Cache Engine  
  {
    NSPort *port1;
    NSPort *port2;
    NSArray *portArray;
    
    port1 = [NSPort port];
    port2 = [NSPort port];

    kitConnection = [[NSConnection alloc] initWithReceivePort:port1
					  sendPort:port2];
    [kitConnection setRootObject:self];

    /* Ports switched here. */
    portArray = [NSArray arrayWithObjects:port2, port1, nil];
    [NSThread detachNewThreadSelector:@selector(connectWithPorts:)
	      toTarget:[CacheEngine class] withObject:portArray];
    
  }

  //check NSUserDefaults notifications 
  //TODO maybye we should have our own notifications
  {
    [[NSNotificationCenter defaultCenter] addObserver:self 
					  selector: @selector(_defaultsChanged:)
					  name:NSUserDefaultsDidChangeNotification
					  object:nil];
  }
  
  {
    [NSApp registerServicesMenuSendTypes:[[NSArray alloc] initWithObjects:NSFilenamesPboardType,nil] 
	   returnTypes:nil];
  }

  //UI settings
  {
    
    //Image Panel
    [self _updateUI];
    [browserWindow setFrameAutosaveName: BROWSERWINDOWFRAME];
    [imageWindow setFrameAutosaveName:IMAGEWINDOWFRAME];

  }
}


- (void)setServer:(id)anObject
{
  [anObject setProtocolForProxy:@protocol(CacheEngineMethods)];
  cacheEngine = (id <CacheEngineMethods>)[anObject retain];
}


-(void) dealloc
{
  if  ( _timer ) 
    {
      if ( [_timer isValid] ) 
	{
	  NSLog(@"Invalidate");
	  [_timer invalidate];
	}
      [_timer release];
    }
  if ( _marksArray ) 
    [_marksArray release];
  if ( _backend ) 
    [_backend release];
  [super dealloc];
}


-(void) setShowState:(SlideShowShowState) flag
{
  _slideShowShowState = flag;
}

-(SlideShowShowState) showState
{
  return _slideShowShowState;
}

/*
 * IBActions
 * Menu Actions 
 */
-(IBAction) showPreferences:(id) sender
{
  if ( ! preferences ) 
    preferences = [PreferencesController sharedPreferences];
  
  [[preferences window] makeKeyAndOrderFront: self];
}

-(IBAction) showAction:(id) sender
{
  unsigned int tag = [[sender selectedItem]tag];
  
  if ( ( tag < ShowAll ) || ( tag > ShowMarkedAndModified ) ) 
    return;
  else
    {
      [self setShowState:tag];
      [browser reloadColumn:0];
    }
}
  


//Call both for directory & images 
-(IBAction) addImages: (id) sender
{
  BOOL isDir;

  if ( [sender tag] == 0 )  
    isDir = NO;
  else if ( [sender tag] == 1 )
    isDir = YES;
  else
    return;

  {
    int result;
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];
    [openPanel setCanChooseDirectories:isDir];
    [openPanel setCanChooseFiles:(! isDir) ];
    [openPanel setAllowsMultipleSelection:YES];
    
    result = [openPanel runModalForDirectory:[self _currentDirectory] 
			file:nil
			types:nil];
    
    if ( result == NSOKButton ) 
      {
	if ( isDir ) 
	  [self _addImagesFromDirectory:[[openPanel filenames] objectAtIndex:0]];
	else
	  [self _addImagesFromList:[openPanel filenames]];
	if ( isDir ) 
	  [self _setCurrentDirectory: [[openPanel filenames] objectAtIndex:0]];
	else
	  [self _setCurrentDirectory: 
		  [[[openPanel filenames] objectAtIndex:0]stringByDeletingLastPathComponent]];      
      }
  }
}


-(IBAction) removeImages:(id) sender
{
  if ( [browser selectedRowInColumn:0] == -1 ) 
    return;
  else 
    {
      unsigned int i,cellsCount;
      unsigned int selectedRow  = [browser selectedRowInColumn:0];

      NSArray *cells = [browser selectedCells];
      cellsCount = [cells count];
      
      if ( selectedRow <  ( [_backend count] - 1 )  ) 
	{
	  _current = (selectedRow - cellsCount ) + 1;
	} 
      else 
	{ 
	  _current = (selectedRow - cellsCount);
	} 

      for ( i=0; i<cellsCount; i++)
	{
	  //remove the slideObject from the _backend
	  id slide = [[cells objectAtIndex:i] representedObject];
	  [cacheEngine removePath:[slide path]];
	  [_backend removeObject: slide];
	}
    }

  [self _updateUI];

  if ( _current >= 0 )
    {
      [[browser matrixInColumn:0] deselectAllCells];
      [browser selectRow:_current inColumn:0];
      [self _displaySlide];
    }
}


-(IBAction) slideShowSwitchAction:(id) sender
{
  if ( [_backend count] == 0 ) 
    return;


  if ( [slideShowSwitch state] == NSOnState ) 
    {
      [slideShowTextField setEnabled:YES];
      [slideShowTextField setSelectable:YES];
      [slideShowTextField setEditable: YES];
      [startButton setEnabled: YES];
      [secondLabel setEnabled:YES];
    }
  else
    {
      [slideShowTextField setEnabled:NO];
      [slideShowTextField setSelectable:NO];
      [slideShowTextField setEditable: NO];
      [slideShowSwitch setEnabled: NO];
      [startButton setEnabled: NO];
      [secondLabel setEnabled:NO];
    }
}
  
-(IBAction) startSlideShowAction:(id) sender
{
  _timer = [NSTimer scheduledTimerWithTimeInterval:2.0
		    target:self
		    selector:@selector(showNextImage:) 
		    userInfo:nil
		    repeats:YES];
  [startButton setEnabled: NO];
  [stopButton setEnabled: YES];
}

-(IBAction) stopSlideShowAction:(id) sender
{
  if (  _timer ) 
    {
      if ( [_timer isValid] ) 
	[_timer invalidate];
    }
  
  [startButton setEnabled: YES];
  [stopButton setEnabled: NO];

}


-(void) mark:(id) sender
{
  [self _markForCurrentSlide];
}

-(IBAction) showPreviousImage: (id) sender
{
  [self _previousImage];
}


-(IBAction) showNextImage: (id) sender
{
  [self _nextImage];
}


-(IBAction) addMarkAction: (id) sender
{
#warning TODO : Add / REMOVE + BrowserCells Are deselected !!! 
  if ( [self showState] == ShowOnlyMarked )
    return;
  

  unsigned int i,count;
  id slide;
  NSArray *selectedCells = [browser selectedCells];
  count = [selectedCells count];
  
  for (i=0;i<count;i++)
    {
      slide = [[selectedCells objectAtIndex:i] representedObject];
      if ( ! slide ) 
	continue;

      if ( [_marksArray containsObject:slide] )
	{
	  [_marksArray removeObject:slide];
	}
      else
	{
	  [_marksArray addObject:slide];
	}
    }
  [self _updateUI];
  [browser reloadColumn:0];
}


-(IBAction) rotateLeftAction:(id) sender
{
  NSLog(@"rotateLeftAction");
}


-(IBAction) rotateRightAction:(id) sender
{
  NSLog(@"rotateRightAction");
}



-(IBAction) fullscreenAction:(id)sender
{
  if ( [_slideShow isVisible] ) 
    [self _quitFullScreen];
  else
    [self _startSlideShow];
}


//Validate Menu : 
- (BOOL) validateMenuItem: (id)menuItem
{
  SEL action = [menuItem action];
  
  if ( sel_eq(action,@selector(removeImages:)) ) 
    {
      if ((  [_backend count] == 0 ) || ( ! [browser selectedCells] ) )
	return NO;
    }
  if ( sel_eq(action,@selector(showNextImage:)) )
    {
      if (  (  ( _current + 1 ) == [_backend count] ) || ( [_backend count] == 0 )  )
	return NO;
    }
  else if ( sel_eq(action,@selector(showPreviousImage:)) )
    {
      if ( [_backend count] == 0 ) 
	return NO;
    }
  else if ( sel_eq(action,@selector(fullscreenAction:)) )
    {
      if ( [_backend count]  == 0 ) 
	return NO;
    }
  else if ( sel_eq(action,@selector(addMarkAction:)) ) 
    {
      if ( (  [self showState] == ShowOnlyMarked ) ||  ([_backend count] == 0 ) )
	return NO;
    }
  else if ( sel_eq(action,@selector(showMarkAction:)) ) 
    {
      if ( [_backend count] == 0  )
	return NO;
    }

  return YES;
}


- (id)validRequestorForSendType:(NSString *)sendType
		     returnType:(NSString *)returnType
{
  if ( ( [sendType isEqualToString: NSFilenamesPboardType] ) && ( [browser selectedCells] ) )
      return self;
  else
    return nil;
}


- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteBoard
			     types:(NSArray *)types
{
  NSArray *pbTypeArray = [[NSArray alloc] initWithObjects:NSFilenamesPboardType,nil];

  [pasteBoard declareTypes:pbTypeArray owner:nil];

  if ( [types containsObject : NSFilenamesPboardType] ) 
    {
      unsigned int i, count = [[browser selectedCells] count];
      NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
      
      for ( i=0;i<count;i++ ) 
	[array addObject: [[[[browser selectedCells] objectAtIndex:i] representedObject] path]];
       
      if ( [pasteBoard setPropertyList: array forType: NSFilenamesPboardType] )
	return YES;
    }

  return NO;
}

-(void) markAction:(id) sender
{
  [browser reloadColumn:0];
}

@end

@implementation Controller (Browser)

-(IBAction) browserAction: (id) sender
{
  int tag = [browser selectedRowInColumn:0];
  if ( tag < 0 ) 
    return;
  _current = tag;
  [self _displaySlide];
}


//
// (NSBrowser delegate methods  
//

- (int)browser:(NSBrowser *)sender numberOfRowsInColumn:(int)column
{
  if ( [self showState] == ShowAll) 
    return [_backend count];
  else if ( [self showState] == ShowOnlyMarked ) 
    return [_marksArray count];    
  //TODO
  else if ( [self showState] ==   ShowOnlyModified ) 
    return 0;
  //TODO
  else if ( [self showState] ==   ShowMarkedAndModified) 
    return 0;
  else
    return 0;

}

- (void)browser:(NSBrowser *)sender willDisplayCell:(id)cell atRow:(int)row column:(int)column
{
  if ( ( sender != browser ) || (column > 0 ))
    return;

  if ( [self showState] == ShowAll ) 
    {
      SlideObject *slideObject = [_backend objectAtIndex:row];
      [cell setRepresentedObject: slideObject];
      [cell setStringValue: [slideObject shortName]];
      if ( [_marksArray containsObject: slideObject] ) 
	[cell setFont:[NSFont boldSystemFontOfSize:0]];
    }
  else if ( [self showState] == ShowOnlyMarked ) 
    {
      id slideObject = [_marksArray objectAtIndex:row];
      [cell setRepresentedObject: slideObject];
      [cell setStringValue: [slideObject description]];
    }

  [cell setLeaf: YES];
}

@end //Controller (BrowserDelegate)


@implementation Controller (Event)

-(void) mouseDown:(NSEvent *) theEvent
{
  if ( _slideShow )
    return;
  else
    [self _showSlideShowMenu];
}


-(void)scrollWheelEvent : (NSEvent*)theEvent
{
  if ( [theEvent deltaY] == -1.00000)
    [self _nextImage];
  else if ( [theEvent deltaY] == 1.00000)
    [self _previousImage];
}

-(void) keyEvent: (NSEvent*) theEvent
{
  NSString *key;
  SEL action = NULL;
  
  NSString *characters = [theEvent charactersIgnoringModifiers];
  if ([characters length] == 1) 
    {
      unichar c;
      c = [characters characterAtIndex: 0];
      key = [NSInputManager describeKeyStroke: c
		      withModifiers: [theEvent modifierFlags]];
    }

  action = [[Shortcuts sharedShortcuts] actionForKey:key];

  if ( action != NULL ) 

    {
      NSLog(@"GO %@", NSStringFromSelector(action));
      [self performSelector:action];
    }
  else 
    NSLog(@"Nothing TODO");
  

}

@end


