1/* Tools.m
2 *
3 * Copyright (C) 2004-2016 Free Software Foundation, Inc.
4 *
5 * Author: Enrico Sersale <enrico@imago.ro>
6 * Date: January 2004
7 *
8 * This file is part of the GNUstep GWorkspace application
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
23 */
24
25#import <Foundation/Foundation.h>
26#import <AppKit/AppKit.h>
27#include <math.h>
28#import "Tools.h"
29#import "Inspector.h"
30#import "IconView.h"
31#import "Functions.h"
32#import "FSNodeRep.h"
33
34#define ICNSIZE 48
35
36static NSString *nibName = @"Tools";
37
38@implementation Tools
39
40- (void)dealloc
41{
42  RELEASE (toolsBox);
43  RELEASE (errLabel);
44  RELEASE (mainBox);
45  RELEASE (insppaths);
46  RELEASE (extensions);
47  RELEASE (currentApp);
48
49  [super dealloc];
50}
51
52- (id)initForInspector:(id)insp
53{
54  self = [super init];
55
56  if (self) {
57    NSRect r;
58    id cell;
59
60    if ([NSBundle loadNibNamed: nibName owner: self] == NO) {
61      NSLog(@"failed to load %@!", nibName);
62      DESTROY (self);
63      return self;
64    }
65
66    RETAIN (mainBox);
67    RETAIN (toolsBox);
68    RELEASE (win);
69
70    inspector = insp;
71    [iconView setInspector: inspector];
72    ws = [NSWorkspace sharedWorkspace];
73
74    [scrollView setBorderType: NSBezelBorder];
75    [scrollView setHasHorizontalScroller: YES];
76    [scrollView setHasVerticalScroller: NO];
77
78  	cell = [NSButtonCell new];
79  	[cell setButtonType: NSPushOnPushOffButton];
80  	[cell setImagePosition: NSImageOnly];
81
82  	matrix = [[NSMatrix alloc] initWithFrame: NSZeroRect
83			      	  					mode: NSRadioModeMatrix prototype: cell
84		       							    			numberOfRows: 0 numberOfColumns: 0];
85    RELEASE (cell);
86		[matrix setIntercellSpacing: NSZeroSize];
87    [matrix setCellSize: NSMakeSize(64, [[scrollView contentView] bounds].size.height)];
88		[matrix setAllowsEmptySelection: YES];
89  	[matrix setTarget: self];
90  	[matrix setAction: @selector(setCurrentApplication:)];
91  	[matrix setDoubleAction: @selector(openFile:)];
92		[scrollView setDocumentView: matrix];
93    RELEASE (matrix);
94
95    r = [toolsBox bounds];
96    r.origin.y = 165;
97    r.size.height = 25;
98  	errLabel = [[NSTextField alloc] initWithFrame: r];
99  	[errLabel setAlignment: NSCenterTextAlignment];
100		[errLabel setFont: [NSFont systemFontOfSize: 18]];
101  	[errLabel setBackgroundColor: [NSColor windowBackgroundColor]];
102  	[errLabel setTextColor: [NSColor darkGrayColor]];
103  	[errLabel setBezeled: NO];
104  	[errLabel setEditable: NO];
105  	[errLabel setSelectable: NO];
106		[errLabel setStringValue: NSLocalizedString(@"No Tools Inspector", @"")];
107
108    insppaths = nil;
109		currentApp = nil;
110    extensions = nil;
111		valid = YES;
112    [okButt setEnabled: NO];
113	}
114
115	return self;
116}
117
118- (NSView *)inspView
119{
120  return mainBox;
121}
122
123- (NSString *)winname
124{
125  return NSLocalizedString(@"Tools Inspector", @"");
126}
127
128- (void)activateForPaths:(NSArray *)paths
129{
130  BOOL toolsok = YES;
131  NSInteger pathscount;
132  NSInteger i;
133
134  if (paths == nil) {
135    DESTROY (insppaths);
136    return;
137  }
138
139  [okButt setEnabled: NO];
140
141  pathscount = [paths count];
142
143  if (pathscount == 1)
144    {
145      FSNode *node = [FSNode nodeWithPath: [paths objectAtIndex: 0]];
146      NSImage *icon = [[FSNodeRep sharedInstance] iconOfSize: ICNSIZE forNode: node];
147
148      [iconView setImage: icon];
149      [titleField setStringValue: [node name]];
150    }
151  else
152    {
153      NSImage *icon = [[FSNodeRep sharedInstance] multipleSelectionIconOfSize: ICNSIZE];
154      NSString *items = NSLocalizedString(@"items", @"");
155      items = [NSString stringWithFormat: @"%li %@", (long int)pathscount, items];
156      [titleField setStringValue: items];
157      [iconView setImage: icon];
158    }
159
160  for (i = 0; i < [paths count]; i++)
161    {
162      FSNode *node = [FSNode nodeWithPath: [paths objectAtIndex: i]];
163
164      if ([node isValid])
165        {
166          if ([node isPlain] == NO)
167            {
168              toolsok = NO;
169              break;
170            }
171        }
172      else
173        {
174          toolsok = NO;
175          break;
176        }
177  }
178
179  if (toolsok == YES)
180    {
181      if (valid == NO)
182        {
183          [errLabel removeFromSuperview];
184          [mainBox addSubview: toolsBox];
185          valid = YES;
186        }
187      [self findApplicationsForPaths: paths];
188
189    }
190  else
191    {
192      if (valid == YES)
193        {
194          [toolsBox removeFromSuperview];
195          [mainBox addSubview: errLabel];
196          valid = NO;
197        }
198    }
199}
200
201- (void)findApplicationsForPaths:(NSArray *)paths
202{
203  NSMutableDictionary *extensionsAndApps;
204  NSMutableArray *commonApps;
205  NSString *s;
206  id cell;
207  BOOL appsforext;
208  NSInteger i, count;
209
210  ASSIGN (insppaths, paths);
211
212  RELEASE (extensions);
213  extensions = [NSMutableArray new];
214  extensionsAndApps = [NSMutableDictionary dictionary];
215
216  DESTROY (currentApp);
217  [defAppField setStringValue: @""];
218  [defPathField setStringValue: @""];
219
220  appsforext = YES;
221
222  for (i = 0; i < [insppaths count]; i++)
223    {
224      NSString *ext = [[insppaths objectAtIndex: i] pathExtension];
225
226      if ([extensions containsObject: ext] == NO)
227        {
228          NSDictionary *extinfo = [ws infoForExtension: ext];
229
230          if (extinfo)
231            {
232              NSMutableArray *appsnames = [NSMutableArray arrayWithCapacity: 1];
233              [appsnames addObjectsFromArray: [extinfo allKeys]];
234              [extensionsAndApps setObject: appsnames forKey: ext];
235              [extensions addObject: ext];
236            }
237          else
238            {
239              appsforext = NO;
240            }
241        }
242    }
243
244  if ([extensions count] == 1) {
245    NSString *ext = [extensions objectAtIndex: 0];
246    commonApps = [NSMutableArray arrayWithArray: [extensionsAndApps objectForKey: ext]];
247    currentApp = [ws getBestAppInRole: nil forExtension: ext];
248    RETAIN (currentApp);
249
250  }
251  else
252    {
253      NSInteger j, n;
254
255      for (i = 0; i < [extensions count]; i++)
256        {
257			NSString *ext1 = [extensions objectAtIndex: i];
258			NSMutableArray *a1 = [extensionsAndApps objectForKey: ext1];
259
260			for (j = 0; j < [extensions count]; j++) {
261				NSString *ext2 = [extensions objectAtIndex: j];
262				NSMutableArray *a2 = [extensionsAndApps objectForKey: ext2];
263
264				count = [a1 count];
265				for (n = 0; n < count; n++) {
266					NSString *s = [a1 objectAtIndex: n];
267					if ([a2 containsObject: s] == NO) {
268						[a1 removeObject: s];
269						count--;
270						n--;
271					}
272				}
273				[extensionsAndApps setObject: a1 forKey: ext1];
274			}
275		}
276
277    commonApps = [NSMutableArray array];
278
279    for (i = 0; i < [extensions count]; i++) {
280      NSString *ext = [extensions objectAtIndex: i];
281			NSArray *apps = [extensionsAndApps objectForKey: ext];
282
283			for (j = 0; j < [apps count]; j++) {
284				NSString *app = [apps objectAtIndex: j];
285				if ([commonApps containsObject: app] == NO) {
286					[commonApps addObject: app];
287				}
288			}
289    }
290
291    if ([commonApps count] != 0) {
292			BOOL iscommapp = YES;
293			NSString *ext1 = [extensions objectAtIndex: 0];
294
295			currentApp = [ws getBestAppInRole: nil forExtension: ext1];
296
297			if ([commonApps containsObject: currentApp]) {
298    		for (i = 1; i < [extensions count]; i++) {
299					NSString *ext2 = [extensions objectAtIndex: i];
300					NSString *app = [ws getBestAppInRole: nil forExtension: ext2];
301
302					if ([currentApp isEqual: app] == NO) {
303						iscommapp = NO;
304					}
305    		}
306			} else {
307				currentApp = nil;
308			}
309
310			if ((iscommapp == YES) && (currentApp != nil) && appsforext) {
311				RETAIN (currentApp);
312			} else {
313				currentApp = nil;
314			}
315		}
316  }
317
318  if (([commonApps count] != 0) && (currentApp != nil) && (appsforext == YES)) {
319 	  [okButt setEnabled: YES];
320  }	else {
321 	  [okButt setEnabled: NO];
322  }
323
324	count = [commonApps count];
325
326	[matrix renewRows: 1 columns: count];
327	[matrix sizeToCells];
328
329	if (appsforext) {
330		for (i = 0; i < count; i++) {
331			NSString *appName = [commonApps objectAtIndex: i];
332      FSNode *node = [FSNode nodeWithPath: [ws fullPathForApplication: appName]];
333      NSImage *icon = [[FSNodeRep sharedInstance] iconOfSize: ICNSIZE forNode: node];
334
335			cell = [matrix cellAtRow: 0 column: i];
336			[cell setImage: icon];
337			[cell setTitle: appName];
338		}
339
340		[matrix sizeToCells];
341	}
342
343	if (currentApp != nil) {
344		NSArray *cells = [matrix cells];
345
346		for(i = 0; i < [cells count]; i++) {
347			cell = [cells objectAtIndex: i];
348			if(cell && ([[cell title] isEqualToString: currentApp])) {
349				[matrix selectCellAtRow: 0 column: i];
350				[matrix scrollCellToVisibleAtRow: 0 column: i];
351				break;
352			}
353		}
354
355	  [defAppField setStringValue: [currentApp stringByDeletingPathExtension]];
356    s = [ws fullPathForApplication: currentApp];
357		if (s != nil) {
358    	s = relativePathFit(defPathField, s);
359		} else {
360			s = @"";
361		}
362	  [defPathField setStringValue: s];
363	}
364}
365
366- (void)setCurrentApplication:(id)sender
367{
368  NSString *s;
369
370  ASSIGN (currentApp, [[sender selectedCell] title]);
371  s = [ws fullPathForApplication: currentApp];
372  s = relativePathFit(defPathField, s);
373  [defPathField setStringValue: s];
374  [defAppField setStringValue: [currentApp stringByDeletingPathExtension]];
375}
376
377- (IBAction)setDefaultApplication:(id)sender
378{
379  NSString *ext, *app;
380  NSDictionary *changedInfo;
381  NSArray *cells;
382  NSMutableArray *newApps;
383  id cell;
384  FSNode *node;
385  NSImage *icon;
386  NSInteger i, count;
387
388  for (i = 0; i < [extensions count]; i++)
389    {
390      ext = [extensions objectAtIndex: i];
391      [ws setBestApp: currentApp inRole: nil forExtension: ext];
392    }
393
394  changedInfo = [NSDictionary dictionaryWithObjectsAndKeys:
395                                                  currentApp, @"app",
396                                                  extensions, @"exts", nil];
397
398	[[NSDistributedNotificationCenter defaultCenter]
399 				   postNotificationName: @"GWAppForExtensionDidChangeNotification"
400	 								       object: nil
401                       userInfo: changedInfo];
402
403  newApps = [NSMutableArray arrayWithCapacity: 1];
404  [newApps addObject: currentApp];
405
406  cells = [matrix cells];
407  for(i = 0; i < [cells count]; i++)
408    {
409      app = [[cells objectAtIndex: i] title];
410      if ([app isEqual: currentApp] == NO)
411        {
412          [newApps insertObject: app atIndex: [newApps count]];
413        }
414    }
415
416  count = [newApps count];
417  [matrix renewRows: 1 columns: count];
418
419  for (i = 0; i < count; i++)
420    {
421      cell = [matrix cellAtRow: 0 column: i];
422      app = [newApps objectAtIndex: i];
423      [cell setTitle: app];
424      node = [FSNode nodeWithPath: [ws fullPathForApplication: app]];
425      icon = [[FSNodeRep sharedInstance] iconOfSize: ICNSIZE forNode: node];
426      [cell setImage: icon];
427    }
428
429  [matrix scrollCellToVisibleAtRow: 0 column: 0];
430  [matrix selectCellAtRow: 0 column: 0];
431}
432
433- (void)openFile:(id)sender
434{
435  NSInteger i;
436
437  for (i = 0; i < [insppaths count]; i++)
438    {
439      NSString *fpath = [insppaths objectAtIndex: i];
440
441      NS_DURING
442        {
443          [ws openFile: fpath withApplication: [[sender selectedCell] title]];
444        }
445      NS_HANDLER
446        {
447          NSRunAlertPanel(NSLocalizedString(@"error", @""),
448                          [NSString stringWithFormat: @"%@ %@!",
449                                    NSLocalizedString(@"Can't open ", @""), [fpath lastPathComponent]],
450                          NSLocalizedString(@"OK", @""),
451                          nil,
452                          nil);
453        }
454      NS_ENDHANDLER
455        }
456}
457
458- (void)watchedPathDidChange:(NSDictionary *)info
459{
460}
461
462@end
463