OSDN Git Service

MacGui: Re-locate logic for encode done notifications as per user preferences.
[handbrake-jp/handbrake-jp-git.git] / macosx / Controller.m
index 7dba8fe..5bba38c 100644 (file)
@@ -83,7 +83,7 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     fPreferencesController = [[HBPreferencesController alloc] init];
     /* Lets report the HandBrake version number here to the activity log and text log file */
     NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
-    [self writeToActivityLog: "%s", [versionStringFull UTF8String]];    
+    [self writeToActivityLog: "%s", [versionStringFull UTF8String]];
     
     return self;
 }
@@ -122,12 +122,22 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     [fPresetsOutlineView setAutosaveExpandedItems:YES];
     
     dockIconProgress = 0;
-
+    
+    /* Init QueueFile .plist */
+    [self loadQueueFile];
+    /* Run hbInstances to get any info on other instances as well as set the
+     * pid number for this instance in the case of multi-instance encoding. */ 
+    hbInstanceNum = [self hbInstances];
+    
     /* Call UpdateUI every 1/2 sec */
+    
     [[NSRunLoop currentRunLoop] addTimer:[NSTimer
-                                          scheduledTimerWithTimeInterval:0.5 target:self
-                                          selector:@selector(updateUI:) userInfo:nil repeats:YES]
-                                 forMode:NSDefaultRunLoopMode];
+                                          scheduledTimerWithTimeInterval:0.5 
+                                          target:self
+                                          selector:@selector(updateUI:) 
+                                          userInfo:nil repeats:YES]
+                                          forMode:NSDefaultRunLoopMode];
+                             
 
     // Open debug output window now if it was visible when HB was closed
     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"])
@@ -165,11 +175,11 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
         /* We check to see if there is already another instance of hb running.
          * Note: hbInstances == 1 means we are the only instance of HandBrake.app
          */
-        if ([self hbInstances] > 1)
+        if (hbInstanceNum > 1)
         {
-        alertTitle = [NSString stringWithFormat:
-                         NSLocalizedString(@"There is already an instance of HandBrake running.", @"")];
-        NSBeginCriticalAlertSheet(
+            alertTitle = [NSString stringWithFormat:
+                          NSLocalizedString(@"There is already an instance of HandBrake running.", @"")];
+            NSBeginCriticalAlertSheet(
                                       alertTitle,
                                       NSLocalizedString(@"Reload Queue", nil),
                                       nil,
@@ -180,29 +190,48 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
         }
         else
         {
-            if (fWorkingCount > 0)
+            if (fWorkingCount > 0 || fPendingCount > 0)
             {
-                alertTitle = [NSString stringWithFormat:
-                              NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item and %d Pending Item(s) In Your Queue.", @""),
-                              fWorkingCount,fPendingCount];
+                if (fWorkingCount > 0)
+                {
+                    alertTitle = [NSString stringWithFormat:
+                                  NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item(s) and %d Pending Item(s) In Your Queue.", @""),
+                                  fWorkingCount,fPendingCount];
+                }
+                else
+                {
+                    alertTitle = [NSString stringWithFormat:
+                                  NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""),
+                                  fPendingCount];
+                }
+                
+                NSBeginCriticalAlertSheet(
+                                          alertTitle,
+                                          NSLocalizedString(@"Reload Queue", nil),
+                                          nil,
+                                          NSLocalizedString(@"Empty Queue", nil),
+                                          fWindow, self,
+                                          nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
+                                          NSLocalizedString(@" Do you want to reload them ?", nil));
             }
             else
             {
-                alertTitle = [NSString stringWithFormat:
-                              NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""),
-                              fPendingCount];
+                /* Since we addressed any pending or previously encoding items above, we go ahead and make sure the queue
+                 * is empty of any finished items or cancelled items */
+                [self clearQueueAllItems];
+                /* We show whichever open source window specified in LaunchSourceBehavior preference key */
+                if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
+                {
+                    [self browseSources:nil];
+                }
+                
+                if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
+                {
+                    [self browseSources:(id)fOpenSourceTitleMMenu];
+                }
             }
             
-            NSBeginCriticalAlertSheet(
-                                      alertTitle,
-                                      NSLocalizedString(@"Reload Queue", nil),
-                                      nil,
-                                      NSLocalizedString(@"Empty Queue", nil),
-                                      fWindow, self,
-                                      nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
-                                      NSLocalizedString(@" Do you want to reload them ?", nil));
         }
-        
     }
     else
     {
@@ -217,29 +246,62 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
             [self browseSources:(id)fOpenSourceTitleMMenu];
         }
     }
+    currentQueueEncodeNameString = @"";
 }
 
+#pragma mark -
+#pragma mark Multiple Instances
+
+/* hbInstances checks to see if other instances of HB are running and also sets the pid for this instance for multi-instance queue encoding */
+ /* Note for now since we are in early phases of multi-instance I have put in quite a bit of logging. Can be removed as we see fit. */
 - (int) hbInstances
 {
     /* check to see if another instance of HandBrake.app is running */
     NSArray *runningAppDictionaries = [[NSWorkspace sharedWorkspace] launchedApplications];
-    NSDictionary *aDictionary;
+    NSDictionary *runningAppsDictionary;
     int hbInstances = 0;
-    for (aDictionary in runningAppDictionaries)
+    NSString * thisInstanceAppPath = [[NSBundle mainBundle] bundlePath];
+    NSString * runningInstanceAppPath;
+    int runningInstancePidNum;
+    [self writeToActivityLog: "hbInstances path to this instance: %s", [thisInstanceAppPath UTF8String]];
+    for (runningAppsDictionary in runningAppDictionaries)
        {
-        if ([[aDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"])
+        if ([[runningAppsDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"])
                {
+            /*Report the path to each active instances app path */
+            runningInstancePidNum = [[runningAppsDictionary valueForKey:@"NSApplicationProcessIdentifier"] intValue];
+            runningInstanceAppPath = [runningAppsDictionary valueForKey:@"NSApplicationPath"];
+            [self writeToActivityLog: "hbInstance found instance pidnum:%d at path: %s", runningInstancePidNum, [runningInstanceAppPath UTF8String]];
+            /* see if this is us by comparing the app path */
+            if ([runningInstanceAppPath isEqualToString: thisInstanceAppPath])
+            {
+                /* If so this is our pidnum */
+                [self writeToActivityLog: "hbInstance MATCH FOUND, our pidnum is:%d", runningInstancePidNum];
+                /* Get the PID number for this hb instance, used in multi instance encoding */
+                pidNum = runningInstancePidNum;
+                /* Report this pid to the activity log */
+                [self writeToActivityLog: "Pid for this instance:%d", pidNum];
+                /* Tell fQueueController what our pidNum is */
+                [fQueueController setPidNum:pidNum];
+            }
             hbInstances++;
-               }
+        }
        }
     return hbInstances;
 }
 
+#pragma mark -
+
 - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
 {
+    
+    [self writeToActivityLog: "didDimissReloadQueue number of hb instances:%d", hbInstanceNum];
     if (returnCode == NSAlertOtherReturn)
     {
+        [self writeToActivityLog: "didDimissReloadQueue NSAlertOtherReturn Chosen"];
         [self clearQueueAllItems];
+        
         /* We show whichever open source window specified in LaunchSourceBehavior preference key */
         if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
         {
@@ -253,8 +315,10 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     }
     else
     {
-        if ([self hbInstances] == 1)
+        [self writeToActivityLog: "didDimissReloadQueue First Button Chosen"];
+        if (hbInstanceNum == 1)
         {
+            
             [self setQueueEncodingItemsAsPending];
         }
         [self showQueueWindow:NULL];
@@ -302,7 +366,7 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
 
 - (void)applicationWillTerminate:(NSNotification *)aNotification
 {
-    
+    [currentQueueEncodeNameString release];
     [browsedSourceDisplayName release];
     [outputPanel release];
        [fQueueController release];
@@ -336,9 +400,6 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     
     /* Init UserPresets .plist */
        [self loadPresets];
-    
-    /* Init QueueFile .plist */
-    [self loadQueueFile];
        
     fRipIndicatorShown = NO;  // initially out of view in the nib
     
@@ -490,8 +551,6 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
        [self getDefaultPresets:nil];
        /* lets initialize the current successful scancount here to 0 */
        currentSuccessfulScanCount = 0;
-    
-    
 }
 
 - (void) enableUI: (bool) b
@@ -758,10 +817,10 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                        break;
         }
 #undef p
-
+            
             
 #define p s.param.working
-        
+            
         case HB_STATE_SEARCHING:
                {
             NSMutableString * string;
@@ -808,7 +867,7 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
             break;  
         }
             
-
+            
         case HB_STATE_WORKING:
         {
             NSMutableString * string;
@@ -840,8 +899,12 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
             }
             
             [fStatusField setStringValue: string];
-            /* Set the status string in fQueueController as well */
-            [fQueueController setQueueStatusString: string];
+            /* Set the status string in fQueueController as well but add currentQueueEncodeNameString to delineate
+             * which encode is being worked on by this instance in a multiple instance situation
+             */
+            NSString * queueStatusString = [NSString stringWithFormat:@"%@ -> %@",string,currentQueueEncodeNameString];
+            [fQueueController setQueueStatusString:queueStatusString];
+            
             /* Update slider */
             CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
             [fRipIndicator setIndeterminate: NO];
@@ -862,14 +925,14 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                 fRipIndicatorShown = YES;
                 
             }
-
+            
             /* Update dock icon */
             if( dockIconProgress < 100.0 * progress_total )
             {
                 [self UpdateDockIcon: progress_total];
                 dockIconProgress += 5;
             }
-
+            
             break;
         }
 #undef p
@@ -940,62 +1003,39 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                 pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"];
                 
                 /* Both the Growl Alert and Sending to MetaX can be done as encodes roll off the queue */
-                /* Growl alert */
-                [self showGrowlDoneNotification:pathOfFinishedEncode];
-                /* Send to MetaX */
-                [self sendToMetaX:pathOfFinishedEncode];
-                
-                /* since we have successfully completed an encode, we increment the queue counter */
-                [self incrementQueueItemDone:nil]; 
-                
-                /* all end of queue actions below need to be done after all queue encodes have finished 
-                 * and there are no pending jobs left to process
-                 */
-                if (fPendingCount == 0)
+                if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || 
+                    [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
                 {
-                    /* If Alert Window or Window and Growl has been selected */
-                    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
-                       [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] )
+                    /* If Play System Alert has been selected in Preferences */
+                    if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES )
                     {
-                        /*On Screen Notification*/
-                        int status;
                         NSBeep();
-                        status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil);
-                        [NSApp requestUserAttention:NSCriticalRequest];
                     }
-                    
-                    /* If sleep has been selected */
-                    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] )
-                    {
-                        /* Sleep */
-                        NSDictionary* errorDict;
-                        NSAppleEventDescriptor* returnDescriptor = nil;
-                        NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
-                                                       @"tell application \"Finder\" to sleep"];
-                        returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
-                        [scriptObject release];
-                    }
-                    /* If Shutdown has been selected */
-                    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
-                    {
-                        /* Shut Down */
-                        NSDictionary* errorDict;
-                        NSAppleEventDescriptor* returnDescriptor = nil;
-                        NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
-                                                       @"tell application \"Finder\" to shut down"];
-                        returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
-                        [scriptObject release];
-                    }
-                    
+                    [self showGrowlDoneNotification:pathOfFinishedEncode];
                 }
                 
+                /* Send to MetaX */
+                [self sendToMetaX:pathOfFinishedEncode];
                 
+                /* since we have successfully completed an encode, we increment the queue counter */
+                [self incrementQueueItemDone:currentQueueEncodeIndex]; 
+
             }
             
             break;
         }
     }
     
+    /* Since we can use multiple instance off of the same queue file it is imperative that we keep the QueueFileArray updated off of the QueueFile.plist
+     * so we go ahead and do it in this existing timer as opposed to using a new one */
+    
+    NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile];
+    [QueueFileArray setArray:tempQueueArray];
+    [tempQueueArray release]; 
+    /* Send Fresh QueueFileArray to fQueueController to update queue window */
+    [fQueueController setQueueArray: QueueFileArray];
+    [self getQueueStats];
+    
 }
 
 /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/
@@ -1351,23 +1391,19 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
 -(void)showGrowlDoneNotification:(NSString *) filePath
 {
     /* This end of encode action is called as each encode rolls off of the queue */
+    /* Setup the Growl stuff ... */
     NSString * finishedEncode = filePath;
     /* strip off the path to just show the file name */
     finishedEncode = [finishedEncode lastPathComponent];
-    if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || 
-        [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
-    {
-        NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode];
-        [GrowlApplicationBridge 
-         notifyWithTitle:@"Put down that cocktail..." 
-         description:growlMssg 
-         notificationName:SERVICE_NAME
-         iconData:nil 
-         priority:0 
-         isSticky:1 
-         clickContext:nil];
-    }
-    
+    NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode];
+    [GrowlApplicationBridge 
+     notifyWithTitle:@"Put down that cocktail..." 
+     description:growlMssg 
+     notificationName:SERVICE_NAME
+     iconData:nil 
+     priority:0 
+     isSticky:1 
+     clickContext:nil];
 }
 -(void)sendToMetaX:(NSString *) filePath
 {
@@ -1385,6 +1421,49 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
         
     }
 }
+
+- (void) queueCompletedAlerts
+{
+    /* If Play System Alert has been selected in Preferences */
+    if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES )
+    {
+        NSBeep();
+    }
+    
+    /* If Alert Window or Window and Growl has been selected */
+    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
+       [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] )
+    {
+        /*On Screen Notification*/
+        int status;
+        status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil);
+        [NSApp requestUserAttention:NSCriticalRequest];
+    }
+    
+    /* If sleep has been selected */
+    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] )
+    {
+        /* Sleep */
+        NSDictionary* errorDict;
+        NSAppleEventDescriptor* returnDescriptor = nil;
+        NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
+                                       @"tell application \"Finder\" to sleep"];
+        returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
+        [scriptObject release];
+    }
+    /* If Shutdown has been selected */
+    if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
+    {
+        /* Shut Down */
+        NSDictionary* errorDict;
+        NSAppleEventDescriptor* returnDescriptor = nil;
+        NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
+                                       @"tell application \"Finder\" to shut down"];
+        returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
+        [scriptObject release];
+    }
+}
+
 #pragma mark -
 #pragma mark Get New Source
 
@@ -1887,53 +1966,38 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
        /*We define the location of the user presets file */
     QueueFile = @"~/Library/Application Support/HandBrake/Queue.plist";
        QueueFile = [[QueueFile stringByExpandingTildeInPath]retain];
-    /* We check for the presets.plist */
+    /* We check for the Queue.plist */
        if ([fileManager fileExistsAtPath:QueueFile] == 0)
        {
                [fileManager createFileAtPath:QueueFile contents:nil attributes:nil];
        }
-
+    
        QueueFileArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile];
        /* lets check to see if there is anything in the queue file .plist */
     if (nil == QueueFileArray)
        {
         /* if not, then lets initialize an empty array */
                QueueFileArray = [[NSMutableArray alloc] init];
-        
-     /* Initialize our curQueueEncodeIndex to 0
-     * so we can use it to track which queue
-     * item is to be used to track our encodes */
-     /* NOTE: this should be changed if and when we
-      * are able to get the last unfinished encode
-      * in the case of a crash or shutdown */
-    
-       }
+    }
     else
     {
-    [self clearQueueEncodedItems];
+        /* ONLY clear out encoded items if we are single instance */
+        if (hbInstanceNum == 1)
+        {
+            [self clearQueueEncodedItems];
+        }
     }
-    currentQueueEncodeIndex = 0;
 }
 
 - (void)addQueueFileItem
 {
-        [QueueFileArray addObject:[self createQueueFileItem]];
-        [self saveQueueFileItem];
-
+    [QueueFileArray addObject:[self createQueueFileItem]];
+    [self saveQueueFileItem];
+    
 }
 
 - (void) removeQueueFileItem:(int) queueItemToRemove
 {
-   
-   /* Find out if the item we are removing is a cancelled (3) or a finished (0) item*/
-   if ([[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 3 || [[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 0)
-    {
-    /* Since we are removing a cancelled or finished item, WE need to decrement the currentQueueEncodeIndex
-     * by one to keep in sync with the queue array
-     */
-    currentQueueEncodeIndex--;
-
-    }
     [QueueFileArray removeObjectAtIndex:queueItemToRemove];
     [self saveQueueFileItem];
 
@@ -1977,7 +2041,13 @@ fWorkingCount = 0;
                if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded
                {
                        fWorkingCount++;
-            fEncodingQueueItem = i;    
+            fEncodingQueueItem = i;
+            /* check to see if we are the instance doing this encoding */
+            if ([thisQueueDict objectForKey:@"EncodingPID"] && [[thisQueueDict objectForKey:@"EncodingPID"] intValue] == pidNum)
+            {
+                currentQueueEncodeIndex = i;
+            }
+               
                }
         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending         
         {
@@ -2003,6 +2073,30 @@ fWorkingCount = 0;
     [fQueueStatus setStringValue:string];
 }
 
+/* Used to get the next pending queue item index and return it if found */
+- (int)getNextPendingQueueIndex
+{
+    /* initialize nextPendingIndex to -1, this value tells incrementQueueItemDone that there are no pending items in the queue */
+    int nextPendingIndex = -1;
+       BOOL nextPendingFound = NO;
+    NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
+       id tempObject;
+    int i = 0;
+       while (tempObject = [enumerator nextObject])
+       {
+               NSDictionary *thisQueueDict = tempObject;
+        if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2 && nextPendingFound == NO) // pending               
+        {
+                       nextPendingFound = YES;
+            nextPendingIndex = [QueueFileArray indexOfObject: tempObject];
+            [self writeToActivityLog: "getNextPendingQueueIndex next pending encod index is:%d", nextPendingIndex];
+               }
+        i++;
+       }
+    return nextPendingIndex;
+}
+
+
 /* This method will set any item marked as encoding back to pending
  * currently used right after a queue reload
  */
@@ -2015,15 +2109,19 @@ fWorkingCount = 0;
     /* we look here to see if the preset is we move on to the next one */
     while ( tempObject = [enumerator nextObject] )  
     {
-        /* If the queue item is marked as "encoding" (1)
-         * then change its status back to pending (2) which effectively
-         * puts it back into the queue to be encoded
-         */
-        if ([[tempObject objectForKey:@"Status"] intValue] == 1)
+        /* We want to keep any queue item that is pending or was previously being encoded */
+        if ([[tempObject objectForKey:@"Status"] intValue] == 1 || [[tempObject objectForKey:@"Status"] intValue] == 2)
         {
-            [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"];
+            /* If the queue item is marked as "encoding" (1)
+             * then change its status back to pending (2) which effectively
+             * puts it back into the queue to be encoded
+             */
+            if ([[tempObject objectForKey:@"Status"] intValue] == 1)
+            {
+                [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"];
+            }
+            [tempArray addObject:tempObject];
         }
-        [tempArray addObject:tempObject];
     }
     
     [QueueFileArray setArray:tempArray];
@@ -2401,8 +2499,8 @@ fWorkingCount = 0;
 
 - (void) incrementQueueItemDone:(int) queueItemDoneIndexNum
 {
-    int i = currentQueueEncodeIndex;
-    [[QueueFileArray objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Status"];
+    /* Mark the encode just finished as done (status 0)*/
+    [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:0] forKey:@"Status"];
        
     /* We save all of the Queue data here */
     [self saveQueueFileItem];
@@ -2411,25 +2509,43 @@ fWorkingCount = 0;
      * we can go ahead and increment currentQueueEncodeIndex 
      * so that if there is anything left in the queue we can
      * go ahead and move to the next item if we want to */
-    currentQueueEncodeIndex++ ;
     int queueItems = [QueueFileArray count];
-    /* If we still have more items in our queue, lets go to the next one */
-    if (currentQueueEncodeIndex < queueItems)
-    {
+    /* Check to see if there are any more pending items in the queue */
+    int newQueueItemIndex = [self getNextPendingQueueIndex];
+    /* If we still have more pending items in our queue, lets go to the next one */
+    if (newQueueItemIndex >= 0 && newQueueItemIndex < queueItems)
+    {
+        /*Set our currentQueueEncodeIndex now to the newly found Pending encode as we own it */
+        currentQueueEncodeIndex = newQueueItemIndex;
+        /* now we mark the queue item as Status = 1 ( being encoded ) so another instance can not come along and try to scan it while we are scanning */
+        [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:1] forKey:@"Status"];
+        [self writeToActivityLog: "incrementQueueItemDone new pending items found: %d", currentQueueEncodeIndex];
+        [self saveQueueFileItem];
+        /* now we can go ahead and scan the new pending queue item */
         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
+
     }
     else
     {
-        [self writeToActivityLog: "incrementQueueItemDone the %d item queue is complete", currentQueueEncodeIndex - 1];
+        [self writeToActivityLog: "incrementQueueItemDone there are no more pending encodes"];
+        /*Since there are no more items to encode, go to queueCompletedAlerts for user specified alerts after queue completed*/
+        [self queueCompletedAlerts];
     }
 }
 
 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
 - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
 {
-   /* Tell HB to output a new activity log file for this encode */
+    /* Tell HB to output a new activity log file for this encode */
     [outputPanel startEncodeLog:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]];
     
+    /* We now flag the queue item as being owned by this instance of HB using the PID */
+    [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:pidNum] forKey:@"EncodingPID"];
+    /* Get the currentQueueEncodeNameString from the queue item to display in the status field */
+    currentQueueEncodeNameString = [[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"] lastPathComponent]retain];
+    /* We save all of the Queue data here */
+    [self saveQueueFileItem];
+    
     /* use a bool to determine whether or not we can decrypt using vlc */
     BOOL cancelScanDecrypt = 0;
     /* set the bool so that showNewScan knows to apply the appropriate queue
@@ -2597,8 +2713,6 @@ fWorkingCount = 0;
     [self doRip];
 }
 
-
-
 #pragma mark -
 #pragma mark Queue Item Editing
 
@@ -3960,7 +4074,7 @@ bool one_burned = FALSE;
 
 
 /* addToQueue: puts up an alert before ultimately calling doAddToQueue
-*/
+ */
 - (IBAction) addToQueue: (id) sender
 {
        /* We get the destination directory from the destination field here */
@@ -4010,7 +4124,7 @@ bool one_burned = FALSE;
     }
     else if (fileExistsInQueue == YES)
     {
-    NSBeginCriticalAlertSheet( NSLocalizedString( @"There is already a queue item for this destination.", @"" ),
+        NSBeginCriticalAlertSheet( NSLocalizedString( @"There is already a queue item for this destination.", @"" ),
                                   NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
                                   @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
                                   NULL, NULL, [NSString stringWithFormat:
@@ -4062,6 +4176,7 @@ bool one_burned = FALSE;
     // If there are pending jobs in the queue, then this is a rip the queue
     if (fPendingCount > 0)
     {
+        currentQueueEncodeIndex = [self getNextPendingQueueIndex];
         /* here lets start the queue with the first pending item */
         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
         
@@ -4099,6 +4214,7 @@ bool one_burned = FALSE;
         }
         
         /* go right to processing the new queue encode */
+        currentQueueEncodeIndex = [self getNextPendingQueueIndex];
         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
         
     }
@@ -4236,23 +4352,29 @@ bool one_burned = FALSE;
     // and as always, save it in the queue .plist...
     /* We save all of the Queue data here */
     [self saveQueueFileItem];
-    // so now lets move to 
-    currentQueueEncodeIndex++ ;
+    
     // ... and see if there are more items left in our queue
     int queueItems = [QueueFileArray count];
     /* If we still have more items in our queue, lets go to the next one */
-    if (currentQueueEncodeIndex < queueItems)
-    {
-    [self writeToActivityLog: "doCancelCurrentJob currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
-    [self writeToActivityLog: "doCancelCurrentJob moving to the next job"];
-    
-    [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
+    /* Check to see if there are any more pending items in the queue */
+    int newQueueItemIndex = [self getNextPendingQueueIndex];
+    /* If we still have more pending items in our queue, lets go to the next one */
+    if (newQueueItemIndex >= 0 && newQueueItemIndex < queueItems)
+    {
+        /*Set our currentQueueEncodeIndex now to the newly found Pending encode as we own it */
+        currentQueueEncodeIndex = newQueueItemIndex;
+        /* now we mark the queue item as Status = 1 ( being encoded ) so another instance can not come along and try to scan it while we are scanning */
+        [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:1] forKey:@"Status"];
+        [self writeToActivityLog: "incrementQueueItemDone new pending items found: %d", currentQueueEncodeIndex];
+        [self saveQueueFileItem];
+        /* now we can go ahead and scan the new pending queue item */
+        [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
+
     }
     else
     {
-        [self writeToActivityLog: "doCancelCurrentJob the item queue is complete"];
+        [self writeToActivityLog: "incrementQueueItemDone there are no more pending encodes"];
     }
-
 }
 
 - (void) doCancelCurrentJobAndStop
@@ -6986,14 +7108,36 @@ return YES;
                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
                 if (job->keep_ratio == 1)
                 {
+                    int height = fTitle->height;
+
+                    if ( job->height && job->height < fTitle->height )
+                        height = job->height;
+
                     hb_fix_aspect( job, HB_KEEP_WIDTH );
-                    if( job->height > fTitle->height )
+                    // Make sure the resulting height is less than
+                    // the title height and less than the height
+                    // requested in the preset.
+                    if( job->height > height )
                     {
-                        job->height = fTitle->height;
+                        job->height = height;
                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
                     }
                 }
                 job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
+                if ( job->anamorphic.mode > 0 )
+                {
+                    int w, h, par_w, par_h;
+
+                    job->anamorphic.par_width = fTitle->pixel_aspect_width;
+                    job->anamorphic.par_height = fTitle->pixel_aspect_height;
+                    job->maxWidth = job->width;
+                    job->maxHeight = job->height;
+                    hb_set_anamorphic_size( job, &w, &h, &par_w, &par_h );
+                    job->maxWidth = 0;
+                    job->maxHeight = 0;
+                    job->width = w;
+                    job->height = h;
+                }
                 
             }
             
@@ -7168,6 +7312,18 @@ return YES;
 }
 
 
+- (IBAction) addPresetPicDropdownChanged: (id) sender
+{
+    if ([fPresetNewPicSettingsPopUp indexOfSelectedItem] == 1)
+    {
+        [fPresetNewPicWidthHeightBox setHidden:NO];  
+    }
+    else
+    {
+        [fPresetNewPicWidthHeightBox setHidden:YES];
+    }
+}
+
 - (IBAction) showAddPresetPanel: (id) sender
 {
     /* Deselect the currently selected Preset if there is one*/
@@ -7176,7 +7332,7 @@ return YES;
     /* Populate the preset picture settings popup here */
     [fPresetNewPicSettingsPopUp removeAllItems];
     [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"];
-    [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"];
+    [fPresetNewPicSettingsPopUp addItemWithTitle:@"Custom"];
     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"];
     [fPresetNewPicSettingsPopUp selectItemAtIndex: 0]; 
     /* Uncheck the preset use filters checkbox */
@@ -7186,6 +7342,12 @@ return YES;
     /* Erase info from the input fields*/
        [fPresetNewName setStringValue: @""];
        [fPresetNewDesc setStringValue: @""];
+    
+    /* Initialize custom height and width settings to current values */
+    
+       [fPresetNewPicWidth setStringValue: [NSString stringWithFormat:@"%d",fTitle->job->width]];
+       [fPresetNewPicHeight setStringValue: [NSString stringWithFormat:@"%d",fTitle->job->height]];
+    [self addPresetPicDropdownChanged:nil];
        /* Show the panel */
        [NSApp beginSheet:fAddPresetPanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
 }
@@ -7318,11 +7480,11 @@ return YES;
         [preset setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
         /*Picture Settings*/
         hb_job_t * job = fTitle->job;
+        
         /* Picture Sizing */
-        /* Use Max Picture settings for whatever the dvd is.*/
         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
-        [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
-        [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
+        [preset setObject:[NSNumber numberWithInt:[fPresetNewPicWidth intValue]] forKey:@"PictureWidth"];
+        [preset setObject:[NSNumber numberWithInt:[fPresetNewPicHeight intValue]] forKey:@"PictureHeight"];
         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
         [preset setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"];
         [preset setObject:[NSNumber numberWithInt:fTitle->job->modulus] forKey:@"PictureModulus"];