1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 * Sebastian Pipping <sebastian@pipping.org>
13 *
14 ******************************************************************************/
15
16 #include <gtk/gtk.h>
17 #include <gdk/gdkkeysyms.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <sys/stat.h>
24 #include <time.h>
25 #include <libintl.h>
26 #include <errno.h>
27 #include <regex.h>
28
29 #include "isomaster.h"
30
31 extern GtkWidget* GBLmainWindow;
32 extern GtkWidget* GBLisoTreeView;
33 extern GtkListStore* GBLisoListStore;
34 extern char* GBLisoCurrentDir;
35 extern GtkWidget* GBLfsTreeView;
36 extern GtkListStore* GBLfsListStore;
37 extern char* GBLfsCurrentDir;
38 extern GtkWidget* GBLisoSizeLbl;
39 extern GtkWidget* GBLisoCurrentDirField;
40 extern GdkPixbuf* GBLdirPixbuf;
41 extern GdkPixbuf* GBLfilePixbuf;
42 extern AppSettings GBLappSettings;
43 extern GtkWidget* GBLrecentlyOpenWidgets[5];
44
45 /* info about the image being worked on */
46 VolInfo GBLvolInfo;
47 /* to know whether am working on an image */
48 bool GBLisoPaneActive = false;
49 /* to know whether any changes to the image have been requested */
50 bool GBLisoChangesProbable = false;
51 /* the size of the iso if it were written right now */
52 static bk_off_t GBLisoSize = 0;
53 /* the progress bar from the writing dialog box */
54 static GtkWidget* GBLWritingProgressBar;
55 /* the progress bar from the extracting dialog box */
56 static GtkWidget* GBLactivityProgressBar;
57 /* the column for the filename in the iso pane */
58 static GtkTreeViewColumn* GBLfilenameIsoColumn;
59 /* the window with the progress bar for writing */
60 GtkWidget* GBLwritingProgressWindow;
61 #ifdef ENABLE_SAVE_OVERWRITE
62 static char* openIsoPathAndName = NULL;
63 #endif
64 /* to really stop an operation, not just for one row */
65 static bool GBLoperationCanceled;
66
activityProgressUpdaterCbk(VolInfo * volInfo)67 void activityProgressUpdaterCbk(VolInfo* volInfo)
68 {
69 if(GBLactivityProgressBar != NULL)
70 {
71 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(GBLactivityProgressBar));
72
73 /* redraw progress bar */
74 while(gtk_events_pending())
75 gtk_main_iteration();
76 }
77 }
78
activityProgressWindowDeleteCbk(GtkWidget * widget,GdkEvent * event,gpointer user_data)79 gboolean activityProgressWindowDeleteCbk(GtkWidget* widget, GdkEvent* event,
80 gpointer user_data)
81 {
82 /* don't allow closing */
83 return TRUE;
84 }
85
acceptIsoPathCbk(GtkEntry * entry,gpointer user_data)86 void acceptIsoPathCbk(GtkEntry *entry, gpointer user_data)
87 {
88 const char* newPath;
89 char* newPathTerminated;
90
91 newPath = gtk_entry_get_text(entry);
92
93 if(newPath[strlen(newPath) - 1] == '/')
94 {
95 changeIsoDirectory((char*)newPath);
96 }
97 else
98 {
99 newPathTerminated = malloc(strlen(newPath) + 2);
100 if(newPathTerminated == NULL)
101 fatalError("newPathTerminated = malloc(strlen(newPath) + 2) failed");
102
103 strcpy(newPathTerminated, newPath);
104 strcat(newPathTerminated, "/");
105
106 changeIsoDirectory(newPathTerminated);
107
108 free(newPathTerminated);
109 }
110 }
111
addToIsoCbk(GtkButton * button,gpointer data)112 void addToIsoCbk(GtkButton *button, gpointer data)
113 {
114 GtkTreeSelection* selection;
115
116 if(!GBLisoPaneActive)
117 /* no iso open */
118 return;
119
120 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
121
122 /* CREATE and show progress bar */
123 GtkWidget* progressWindow;
124 GtkWidget* label;
125
126 /* dialog window for the progress bar */
127 progressWindow = gtk_dialog_new();
128 gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
129 gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
130 gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
131 gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
132 g_signal_connect_swapped(progressWindow, "delete-event",
133 G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
134 g_signal_connect_swapped(progressWindow, "response",
135 G_CALLBACK(cancelOperation), NULL);
136
137 label = gtk_label_new(_("Please wait while I'm adding the selected items..."));
138 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
139 gtk_widget_show(label);
140
141 if(GBLappSettings.scanForDuplicateFiles)
142 {
143 label = gtk_label_new(_("(scanning for duplicate files)"));
144 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
145 gtk_widget_show(label);
146 }
147
148 /* the progress bar */
149 GBLactivityProgressBar = gtk_progress_bar_new();
150 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
151 gtk_widget_show(GBLactivityProgressBar);
152
153 /* button to cancel adding */
154 gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
155
156 /* if i show it before i add the children, the window ends up being not centered */
157 gtk_widget_show(progressWindow);
158 /* END CREATE and show progress bar */
159
160 GBLoperationCanceled = false;
161
162 gtk_tree_selection_selected_foreach(selection, addToIsoEachRowCbk, NULL);
163
164 gtk_widget_destroy(progressWindow);
165 GBLactivityProgressBar = NULL;
166
167 if(gtk_tree_selection_count_selected_rows(selection) > 0)
168 /* reload iso view */
169 {
170 refreshIsoView();
171 }
172
173 /* iso size label */
174 char sizeStr[20];
175 GBLisoSize = 35845;
176 //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
177 GBLisoSize += 2048;
178 GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
179 formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
180 gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
181 }
182
addToIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)183 void addToIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
184 GtkTreeIter* iterator, gpointer data)
185 {
186 int fileType;
187 char* itemName;
188 char* fullItemName; /* with full path */
189 int rc;
190 GtkWidget* warningDialog;
191
192 if(GBLoperationCanceled)
193 return;
194
195 gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
196 COLUMN_FILENAME, &itemName, -1);
197
198 if(fileType == FILE_TYPE_DIRECTORY || fileType == FILE_TYPE_REGULAR ||
199 fileType == FILE_TYPE_SYMLINK)
200 {
201 fullItemName = (char*)malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1);
202 if(fullItemName == NULL)
203 fatalError("addToIsoEachRowCbk(): malloc("
204 "strlen(GBLfsCurrentDir) + strlen(itemName) + 1) failed");
205
206 strcpy(fullItemName, GBLfsCurrentDir);
207 strcat(fullItemName, itemName);
208
209 rc = bk_add(&GBLvolInfo, fullItemName, GBLisoCurrentDir, activityProgressUpdaterCbk);
210 if(rc <= 0 && rc != BKWARNING_OPER_PARTLY_FAILED)
211 {
212 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
213 GTK_DIALOG_DESTROY_WITH_PARENT,
214 GTK_MESSAGE_ERROR,
215 GTK_BUTTONS_CLOSE,
216 _("Failed to add '%s': '%s'"),
217 fullItemName,
218 bk_get_error_string(rc));
219 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
220 gtk_dialog_run(GTK_DIALOG(warningDialog));
221 gtk_widget_destroy(warningDialog);
222 }
223 else
224 GBLisoChangesProbable = true;
225
226 free(fullItemName);
227 }
228 else
229 {
230 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
231 GTK_DIALOG_DESTROY_WITH_PARENT,
232 GTK_MESSAGE_ERROR,
233 GTK_BUTTONS_CLOSE,
234 "GUI error, adding anything other than "
235 "files and directories doesn't work");
236 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
237 gtk_dialog_run(GTK_DIALOG(warningDialog));
238 gtk_widget_destroy(warningDialog);
239 }
240
241 g_free(itemName);
242 }
243
askForPermissions(const char * fullItemName,mode_t * permissions)244 bool askForPermissions(const char* fullItemName, mode_t* permissions)
245 {
246 GtkWidget* dialog;
247 GtkWidget* table;
248 GtkWidget* label;
249 int rc;
250 int count;
251 bool didChange = false;
252
253 rc = bk_get_permissions(&GBLvolInfo, fullItemName, permissions);
254 if(rc <= 0)
255 {
256 dialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
257 GTK_DIALOG_DESTROY_WITH_PARENT,
258 GTK_MESSAGE_ERROR,
259 GTK_BUTTONS_CLOSE,
260 "bk_get_permissions() failed (%s), please report bug",
261 bk_get_error_string(rc));
262 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
263 gtk_dialog_run(GTK_DIALOG(dialog));
264 gtk_widget_destroy(dialog);
265 return false;
266 }
267
268 dialog = gtk_dialog_new_with_buttons(_("Change permissions"),
269 GTK_WINDOW(GBLmainWindow),
270 GTK_DIALOG_DESTROY_WITH_PARENT,
271 GTK_STOCK_OK,
272 GTK_RESPONSE_ACCEPT,
273 GTK_STOCK_CANCEL,
274 GTK_RESPONSE_REJECT,
275 NULL);
276 g_signal_connect(dialog, "close", G_CALLBACK(rejectDialogCbk), NULL);
277 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
278
279 table = gtk_table_new(3, 11, FALSE);
280 //~ gtk_table_set_row_spacings(GTK_TABLE(table), 5);
281 //~ gtk_table_set_col_spacings(GTK_TABLE(table), 5);
282 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0);
283 gtk_widget_show(table);
284
285 label = gtk_label_new("User");
286 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 0, 1);
287 gtk_widget_show(label);
288
289 label = gtk_label_new("Group");
290 gtk_table_attach_defaults(GTK_TABLE(table), label, 4, 7, 0, 1);
291 gtk_widget_show(label);
292
293 label = gtk_label_new("Others");
294 gtk_table_attach_defaults(GTK_TABLE(table), label, 8, 11, 0, 1);
295 gtk_widget_show(label);
296
297 for(count = 0; count < 11; count++)
298 {
299 if(count == 0 || count == 4 || count == 8)
300 {
301 label = gtk_label_new("r");
302 gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
303 gtk_widget_show(label);
304 }
305 else if(count == 1 || count == 5 || count == 9)
306 {
307 label = gtk_label_new("w");
308 gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
309 gtk_widget_show(label);
310 }
311 else if(count == 2 || count == 6 || count == 10)
312 {
313 label = gtk_label_new("x");
314 gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
315 gtk_widget_show(label);
316 }
317 else
318 {
319 label = gtk_label_new("-");
320 gtk_table_attach_defaults(GTK_TABLE(table), label, count, count + 1, 1, 2);
321 gtk_widget_show(label);
322 }
323 }
324
325 /* CREATE checkboxes for permissions */
326 GtkWidget* urCbx; /* user read */
327 GtkWidget* uwCbx;
328 GtkWidget* uxCbx;
329 GtkWidget* grCbx; /* group read */
330 GtkWidget* gwCbx;
331 GtkWidget* gxCbx;
332 GtkWidget* orCbx; /* others readd */
333 GtkWidget* owCbx;
334 GtkWidget* oxCbx;
335
336 urCbx = gtk_check_button_new();
337 gtk_table_attach_defaults(GTK_TABLE(table), urCbx, 0, 1, 2, 3);
338 if(*permissions & 0400)
339 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(urCbx), TRUE);
340 gtk_widget_show(urCbx);
341
342 uwCbx = gtk_check_button_new();
343 gtk_table_attach_defaults(GTK_TABLE(table), uwCbx, 1, 2, 2, 3);
344 if(*permissions & 0200)
345 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uwCbx), TRUE);
346 gtk_widget_show(uwCbx);
347
348 uxCbx = gtk_check_button_new();
349 gtk_table_attach_defaults(GTK_TABLE(table), uxCbx, 2, 3, 2, 3);
350 if(*permissions & 0100)
351 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uxCbx), TRUE);
352 gtk_widget_show(uxCbx);
353
354 label = gtk_label_new("-");
355 gtk_table_attach_defaults(GTK_TABLE(table), label, 3, 4, 2, 3);
356 gtk_widget_show(label);
357
358 grCbx = gtk_check_button_new();
359 gtk_table_attach_defaults(GTK_TABLE(table), grCbx, 4, 5, 2, 3);
360 if(*permissions & 0040)
361 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grCbx), TRUE);
362 gtk_widget_show(grCbx);
363
364 gwCbx = gtk_check_button_new();
365 gtk_table_attach_defaults(GTK_TABLE(table), gwCbx, 5, 6, 2, 3);
366 if(*permissions & 0020)
367 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gwCbx), TRUE);
368 gtk_widget_show(gwCbx);
369
370 gxCbx = gtk_check_button_new();
371 gtk_table_attach_defaults(GTK_TABLE(table), gxCbx, 6, 7, 2, 3);
372 if(*permissions & 0010)
373 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gxCbx), TRUE);
374 gtk_widget_show(gxCbx);
375
376 label = gtk_label_new("-");
377 gtk_table_attach_defaults(GTK_TABLE(table), label, 7, 8, 2, 3);
378 gtk_widget_show(label);
379
380 orCbx = gtk_check_button_new();
381 gtk_table_attach_defaults(GTK_TABLE(table), orCbx, 8, 9, 2, 3);
382 if(*permissions & 0004)
383 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(orCbx), TRUE);
384 gtk_widget_show(orCbx);
385
386 owCbx = gtk_check_button_new();
387 gtk_table_attach_defaults(GTK_TABLE(table), owCbx, 9, 10, 2, 3);
388 if(*permissions & 0002)
389 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(owCbx), TRUE);
390 gtk_widget_show(owCbx);
391
392 oxCbx = gtk_check_button_new();
393 gtk_table_attach_defaults(GTK_TABLE(table), oxCbx, 10, 11, 2, 3);
394 if(*permissions & 0001)
395 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oxCbx), TRUE);
396 gtk_widget_show(oxCbx);
397 /* END CREATE checkboxes for permissions */
398
399 gtk_widget_show(dialog);
400
401 rc = gtk_dialog_run(GTK_DIALOG(dialog));
402 if(rc == GTK_RESPONSE_ACCEPT)
403 {
404 *permissions = 0;
405
406 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(urCbx)))
407 *permissions |= 0400;
408 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uwCbx)))
409 *permissions |= 0200;
410 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uxCbx)))
411 *permissions |= 0100;
412 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(grCbx)))
413 *permissions |= 0040;
414 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gwCbx)))
415 *permissions |= 0020;
416 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gxCbx)))
417 *permissions |= 0010;
418 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(orCbx)))
419 *permissions |= 0004;
420 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(owCbx)))
421 *permissions |= 0002;
422 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oxCbx)))
423 *permissions |= 0001;
424
425 didChange = true;
426 }
427
428 gtk_widget_destroy(dialog);
429
430 return didChange;
431 }
432
buildIsoBrowser(GtkWidget * boxToPackInto)433 void buildIsoBrowser(GtkWidget* boxToPackInto)
434 {
435 GtkWidget* scrolledWindow;
436 GtkTreeSelection *selection;
437 GtkCellRenderer* renderer;
438 GtkTreeViewColumn* column;
439
440 GBLisoListStore = gtk_list_store_new(NUM_COLUMNS,
441 GDK_TYPE_PIXBUF, /* icon */
442 G_TYPE_STRING, /* name */
443 G_TYPE_UINT, /* size (64-bit sizes not allowed on an iso) */
444 G_TYPE_UINT /* file type */
445 );
446
447 scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
448 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow),
449 GTK_POLICY_AUTOMATIC,
450 GTK_POLICY_AUTOMATIC);
451 //~ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledWindow),
452 //~ GTK_SHADOW_ETCHED_IN);
453 gtk_box_pack_start(GTK_BOX(boxToPackInto), scrolledWindow, TRUE, TRUE, 0);
454 gtk_widget_show(scrolledWindow);
455
456 /* view widget */
457 GBLisoTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(GBLisoListStore));
458 gtk_tree_view_set_search_column(GTK_TREE_VIEW(GBLisoTreeView), COLUMN_FILENAME);
459 g_object_unref(GBLisoListStore); /* destroy model automatically with view */
460 gtk_container_add(GTK_CONTAINER(scrolledWindow), GBLisoTreeView);
461 g_signal_connect(GBLisoTreeView, "row-activated", (GCallback)isoRowDblClickCbk, NULL);
462 g_signal_connect(GBLisoTreeView, "select-cursor-parent", (GCallback)isoGoUpDirTreeCbk, NULL);
463 g_signal_connect(GBLisoTreeView, "key-press-event", (GCallback)isoKeyPressedCbk, NULL);
464 /* The problem with this is that i get a popup menu before the row is selected.
465 * if i do a connect_after the handler never gets called. So no right-click menu. */
466 g_signal_connect(GBLisoTreeView, "button-press-event", (GCallback)isoButtonPressedCbk, NULL);
467 g_signal_connect(GBLisoTreeView, "button-release-event", (GCallback)isoButtonReleasedCbk, NULL);
468 gtk_widget_show(GBLisoTreeView);
469
470 /* this won't be enabled until gtk allows me to drag a multiple selection */
471 //~ GtkTargetEntry targetEntry;
472 //~ targetEntry.target = "text/plain";
473 //~ targetEntry.flags = 0;
474 //~ targetEntry.info = 0;
475 //~ gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(GBLisoTreeView), &targetEntry, 1, GDK_ACTION_COPY);
476
477 /* enable multi-line selection */
478 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
479 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
480
481 /* filename column */
482 GBLfilenameIsoColumn = gtk_tree_view_column_new();
483 gtk_tree_view_column_set_title(GBLfilenameIsoColumn, _("Name"));
484 gtk_tree_view_column_set_resizable(GBLfilenameIsoColumn, TRUE);
485
486 renderer = gtk_cell_renderer_pixbuf_new();
487 gtk_tree_view_column_pack_start(GBLfilenameIsoColumn, renderer, FALSE);
488 gtk_tree_view_column_add_attribute(GBLfilenameIsoColumn, renderer, "pixbuf", COLUMN_ICON);
489
490 renderer = gtk_cell_renderer_text_new();
491 /* this would fuck up usability beyond what my patience can handle */
492 //~ g_object_set(renderer, "editable", TRUE, NULL);
493 gtk_tree_view_column_pack_start(GBLfilenameIsoColumn, renderer, TRUE);
494 gtk_tree_view_column_add_attribute(GBLfilenameIsoColumn, renderer, "text", COLUMN_FILENAME);
495
496 gtk_tree_view_column_set_sort_column_id(GBLfilenameIsoColumn, COLUMN_FILENAME);
497 gtk_tree_view_column_set_expand(GBLfilenameIsoColumn, TRUE);
498 gtk_tree_view_append_column(GTK_TREE_VIEW(GBLisoTreeView), GBLfilenameIsoColumn);
499
500 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLisoListStore), COLUMN_FILENAME,
501 sortByName, NULL, NULL);
502
503 /* size column */
504 column = gtk_tree_view_column_new();
505 renderer = gtk_cell_renderer_text_new();
506 gtk_tree_view_column_set_title(column, _("Size"));
507 gtk_tree_view_column_pack_start(column, renderer, FALSE);
508 gtk_tree_view_column_add_attribute(column, renderer, "text", COLUMN_SIZE);
509 gtk_tree_view_column_set_cell_data_func(column, renderer, sizeCellDataFunc32, NULL, NULL);
510 gtk_tree_view_column_set_sort_column_id(column, COLUMN_SIZE);
511 gtk_tree_view_append_column(GTK_TREE_VIEW(GBLisoTreeView), column);
512
513 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLisoListStore), COLUMN_SIZE,
514 sortBySize, NULL, NULL);
515
516 /* set default sort */
517 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GBLisoListStore),
518 GBLappSettings.isoSortColumnId,
519 GBLappSettings.isoSortDirection);
520
521 gtk_widget_set_sensitive(GBLisoCurrentDirField, FALSE);
522 gtk_widget_set_sensitive(GBLisoTreeView, FALSE);
523 }
524
buildIsoLocator(GtkWidget * boxToPackInto)525 void buildIsoLocator(GtkWidget* boxToPackInto)
526 {
527 GBLisoCurrentDirField = gtk_entry_new();
528 //gtk_entry_set_editable(GTK_ENTRY(GBLisoCurrentDirField), FALSE);
529 g_signal_connect(GBLisoCurrentDirField, "activate", (GCallback)acceptIsoPathCbk, NULL);
530 gtk_box_pack_start(GTK_BOX(boxToPackInto), GBLisoCurrentDirField, FALSE, FALSE, 0);
531 gtk_widget_show(GBLisoCurrentDirField);
532 }
533
cancelOperation(GtkDialog * dialog,gint arg1,gpointer user_data)534 void cancelOperation(GtkDialog* dialog, gint arg1, gpointer user_data)
535 {
536 bk_cancel_operation(&GBLvolInfo);
537 GBLoperationCanceled = true;
538 }
539
changeIsoDirectory(const char * newDirStr)540 void changeIsoDirectory(const char* newDirStr)
541 {
542 int rc;
543 BkDir* newDir;
544 BkFileBase* child;
545 GtkTreeIter listIterator;
546 GtkTreeModel* model;
547 GtkWidget* warningDialog;
548
549 rc = bk_get_dir_from_string(&GBLvolInfo, newDirStr, &newDir);
550 if(rc <= 0)
551 {
552 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
553 GTK_DIALOG_DESTROY_WITH_PARENT,
554 GTK_MESSAGE_ERROR,
555 GTK_BUTTONS_CLOSE,
556 _("Failed to change directory: '%s'"),
557 bk_get_error_string(rc));
558 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
559 gtk_dialog_run(GTK_DIALOG(warningDialog));
560 gtk_widget_destroy(warningDialog);
561 return;
562 }
563
564 /* for improved performance disconnect the model from tree view before udating it */
565 model = gtk_tree_view_get_model(GTK_TREE_VIEW(GBLisoTreeView));
566 g_object_ref(model);
567 gtk_tree_view_set_model(GTK_TREE_VIEW(GBLisoTreeView), NULL);
568
569 /* this is the only way to disable sorting (for a huge performance boost) */
570 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
571 sortVoid, NULL, NULL);
572 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
573 sortVoid, NULL, NULL);
574
575 gtk_list_store_clear(GBLisoListStore);
576
577 #if GTK_MINOR_VERSION >= 8
578 /* to make sure width of filename column isn't bigger than needed (need gtk 2.8) */
579 gtk_tree_view_column_queue_resize(GBLfilenameIsoColumn);
580 #endif
581
582 /* add all directories to the tree */
583 child = newDir->children;
584 while(child != NULL)
585 {
586 if(IS_DIR(child->posixFileMode))
587 /* directory */
588 {
589 gtk_list_store_append(GBLisoListStore, &listIterator);
590 gtk_list_store_set(GBLisoListStore, &listIterator,
591 COLUMN_ICON, GBLdirPixbuf,
592 COLUMN_FILENAME, child->name,
593 COLUMN_SIZE, 0,
594 COLUMN_HIDDEN_TYPE, FILE_TYPE_DIRECTORY,
595 -1);
596 }
597 else if(IS_REG_FILE(child->posixFileMode))
598 {
599 gtk_list_store_append(GBLisoListStore, &listIterator);
600 gtk_list_store_set(GBLisoListStore, &listIterator,
601 COLUMN_ICON, GBLfilePixbuf,
602 COLUMN_FILENAME, child->name,
603 COLUMN_SIZE, (BK_FILE_PTR(child))->size,
604 COLUMN_HIDDEN_TYPE, FILE_TYPE_REGULAR,
605 -1);
606 }
607 else if(IS_SYMLINK(child->posixFileMode))
608 {
609 gtk_list_store_append(GBLisoListStore, &listIterator);
610 gtk_list_store_set(GBLisoListStore, &listIterator,
611 COLUMN_ICON, GBLfilePixbuf,
612 COLUMN_FILENAME, child->name,
613 COLUMN_SIZE, 0,
614 COLUMN_HIDDEN_TYPE, FILE_TYPE_SYMLINK,
615 -1);
616 }
617
618 child = child->next;
619 }
620
621 /* reconnect the model and view now */
622 gtk_tree_view_set_model(GTK_TREE_VIEW(GBLisoTreeView), model);
623 g_object_unref(model);
624
625 /* reenable sorting */
626 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_FILENAME,
627 sortByName, NULL, NULL);
628 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(GBLfsListStore), COLUMN_SIZE,
629 sortBySize, NULL, NULL);
630
631 /* set current directory string */
632 if(GBLisoCurrentDir != NULL)
633 free(GBLisoCurrentDir);
634 GBLisoCurrentDir = (char*)malloc(strlen(newDirStr) + 1);
635 if(GBLisoCurrentDir == NULL)
636 fatalError("changeIsoDirectory(): malloc(strlen(newDirStr) + 1) failed");
637 strcpy(GBLisoCurrentDir, newDirStr);
638
639 /* update the field with the path and name */
640 gtk_entry_set_text(GTK_ENTRY(GBLisoCurrentDirField), GBLisoCurrentDir);
641 }
642
changePermissionsBtnCbk(GtkMenuItem * menuitem,gpointer data)643 void changePermissionsBtnCbk(GtkMenuItem *menuitem, gpointer data)
644 {
645 GtkTreeSelection* selection;
646
647 /* do nothing if no image open */
648 if(!GBLisoPaneActive)
649 return;
650
651 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
652
653 int numSelectedRows = gtk_tree_selection_count_selected_rows(selection);
654
655 if(numSelectedRows == 1)
656 gtk_tree_selection_selected_foreach(selection, changePermissionsRowCbk, NULL);
657 else
658 {
659 GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(GBLisoTreeView));
660 GList* rowsList = gtk_tree_selection_get_selected_rows(selection, NULL);
661 mode_t permissions;
662 bool firstRow = true;
663 bool cancelled = false;
664
665 GList* row = rowsList;
666 while(row != NULL && !cancelled)
667 {
668 GtkTreeIter iter;
669 char* itemName;
670 char* fullItemName;
671
672 gtk_tree_model_get_iter(model, &iter, row->data);
673 gtk_tree_model_get(model, &iter, COLUMN_FILENAME, &itemName, -1);
674
675 fullItemName = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
676 if(fullItemName == NULL)
677 fatalError("changePermissionsRowCbk(): malloc("
678 "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
679
680 strcpy(fullItemName, GBLisoCurrentDir);
681 strcat(fullItemName, itemName);
682
683 if(firstRow)
684 {
685 cancelled = !askForPermissions(fullItemName, &permissions);
686 firstRow = false;
687 }
688
689 if(!cancelled)
690 {
691 bk_set_permissions(&GBLvolInfo, fullItemName, permissions);
692 GBLisoChangesProbable = true;
693 }
694
695 g_free(itemName);
696 free(fullItemName);
697 row = row->next;
698 }
699
700 g_list_foreach(rowsList, (GFunc)gtk_tree_path_free, NULL);
701 g_list_free(rowsList);
702 } // multiple rows
703 }
704
changePermissionsRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)705 void changePermissionsRowCbk(GtkTreeModel* model, GtkTreePath* path,
706 GtkTreeIter* iterator, gpointer data)
707 {
708 char* itemName;
709 char* fullItemName;
710 mode_t permissions;
711
712 gtk_tree_model_get(model, iterator, COLUMN_FILENAME, &itemName, -1);
713
714 fullItemName = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
715 if(fullItemName == NULL)
716 fatalError("changePermissionsRowCbk(): malloc("
717 "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
718
719 strcpy(fullItemName, GBLisoCurrentDir);
720 strcat(fullItemName, itemName);
721
722 if(askForPermissions(fullItemName, &permissions))
723 {
724 bk_set_permissions(&GBLvolInfo, fullItemName, permissions);
725 GBLisoChangesProbable = true;
726 }
727
728 g_free(itemName);
729 free(fullItemName);
730 }
731
732
closeIso(void)733 void closeIso(void)
734 {
735 if(!GBLisoPaneActive)
736 /* no image open or created, nothing to do */
737 return;
738
739 gtk_list_store_clear(GBLisoListStore);
740
741 bk_destroy_vol_info(&GBLvolInfo);
742
743 GBLisoSize = 0;
744 gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), "");
745
746 gtk_window_set_title(GTK_WINDOW(GBLmainWindow), "ISO Master");
747
748 gtk_widget_set_sensitive(GBLisoCurrentDirField, FALSE);
749 gtk_widget_set_sensitive(GBLisoTreeView, FALSE);
750
751 GBLisoPaneActive = false;
752
753 #ifdef ENABLE_SAVE_OVERWRITE
754 if(openIsoPathAndName != NULL)
755 {
756 free(openIsoPathAndName);
757 openIsoPathAndName = NULL;
758 }
759 #endif
760 }
761
confirmCloseIso(void)762 bool confirmCloseIso(void)
763 {
764 GtkWidget* warningDialog;
765 gint response;
766
767 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
768 GTK_DIALOG_DESTROY_WITH_PARENT,
769 GTK_MESSAGE_QUESTION,
770 GTK_BUTTONS_NONE,
771 _("It seems that you have made changes to the ISO but "
772 "haven't saved them. Are you sure you want to close it?"));
773 gtk_dialog_add_buttons(GTK_DIALOG(warningDialog),
774 GTK_STOCK_GO_BACK, GTK_RESPONSE_CANCEL,
775 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
776 NULL);
777 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
778 gtk_dialog_set_default_response(GTK_DIALOG(warningDialog), GTK_RESPONSE_CLOSE);
779 response = gtk_dialog_run(GTK_DIALOG(warningDialog));
780 gtk_widget_destroy(warningDialog);
781
782 if(response == GTK_RESPONSE_CLOSE)
783 return true;
784 else
785 return false;
786 }
787
deleteSelectedFromIso(void)788 void deleteSelectedFromIso(void)
789 {
790 GtkTreeSelection* selection;
791
792 if(!GBLisoPaneActive)
793 /* no iso open */
794 return;
795
796 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
797
798 gtk_tree_selection_selected_foreach(selection, deleteFromIsoEachRowCbk, NULL);
799
800 if(gtk_tree_selection_count_selected_rows(selection) > 0)
801 /* reload iso view */
802 {
803 refreshIsoView();
804 }
805
806 /* iso size label */
807 char sizeStr[20];
808 GBLisoSize = 35845;
809 //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
810 GBLisoSize += 2048;
811 GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
812 formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
813 gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
814 }
815
deleteFromIsoCbk(GtkButton * button,gpointer data)816 void deleteFromIsoCbk(GtkButton *button, gpointer data)
817 {
818 deleteSelectedFromIso();
819 }
820
deleteFromIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)821 void deleteFromIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
822 GtkTreeIter* iterator, gpointer data)
823 {
824 int fileType;
825 char* itemName;
826 char* fullItemName; /* with full path */
827 int rc;
828 GtkWidget* warningDialog;
829
830 gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
831 COLUMN_FILENAME, &itemName, -1);
832
833 if(fileType == FILE_TYPE_DIRECTORY || fileType == FILE_TYPE_REGULAR ||
834 fileType == FILE_TYPE_SYMLINK)
835 {
836 fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
837 if(fullItemName == NULL)
838 fatalError("deleteFromIsoEachRowCbk(): malloc("
839 "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed");
840
841 strcpy(fullItemName, GBLisoCurrentDir);
842 strcat(fullItemName, itemName);
843
844 rc = bk_delete(&GBLvolInfo, fullItemName);
845 if(rc <= 0)
846 {
847 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
848 GTK_DIALOG_DESTROY_WITH_PARENT,
849 GTK_MESSAGE_ERROR,
850 GTK_BUTTONS_CLOSE,
851 _("Failed to delete '%s': '%s'"),
852 itemName,
853 bk_get_error_string(rc));
854 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
855 gtk_dialog_run(GTK_DIALOG(warningDialog));
856 gtk_widget_destroy(warningDialog);
857 }
858 else
859 GBLisoChangesProbable = true;
860
861 free(fullItemName);
862 }
863 else
864 {
865 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
866 GTK_DIALOG_DESTROY_WITH_PARENT,
867 GTK_MESSAGE_ERROR,
868 GTK_BUTTONS_CLOSE,
869 _("GUI error, deleting anything other than "
870 "files and directories doesn't work"));
871 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
872 gtk_dialog_run(GTK_DIALOG(warningDialog));
873 gtk_widget_destroy(warningDialog);
874 }
875
876 g_free(itemName);
877 }
878
extractFromIsoCbk(GtkButton * button,gpointer data)879 void extractFromIsoCbk(GtkButton *button, gpointer data)
880 {
881 GtkTreeSelection* selection;
882 GtkWidget* progressWindow = NULL;
883 GtkWidget* descriptionLabel;
884
885 if(!GBLisoPaneActive)
886 /* no iso open */
887 return;
888
889 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
890
891 if(gtk_tree_selection_count_selected_rows(selection) > 0)
892 {
893 /* dialog window for the progress bar */
894 progressWindow = gtk_dialog_new();
895 gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
896 gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
897 gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
898 gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
899 g_signal_connect_swapped(progressWindow, "delete-event",
900 G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
901 g_signal_connect_swapped(progressWindow, "response",
902 G_CALLBACK(cancelOperation), NULL);
903
904 /* just some text */
905 descriptionLabel = gtk_label_new(_("Please wait while I'm extracting the selected files..."));
906 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), descriptionLabel, TRUE, TRUE, 0);
907 gtk_widget_show(descriptionLabel);
908
909 /* the progress bar */
910 GBLactivityProgressBar = gtk_progress_bar_new();
911 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
912 gtk_widget_show(GBLactivityProgressBar);
913
914 /* button to cancel extracting */
915 gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_NONE);
916
917 /* if i show it before i add the children, the window ends up being not centered */
918 gtk_widget_show(progressWindow);
919
920 GBLoperationCanceled = false;
921
922 gtk_tree_selection_selected_foreach(selection, extractFromIsoEachRowCbk, NULL);
923
924 refreshFsView();
925
926 gtk_widget_destroy(progressWindow);
927 }
928
929 GBLactivityProgressBar = NULL;
930 }
931
extractFromIsoEachRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)932 void extractFromIsoEachRowCbk(GtkTreeModel* model, GtkTreePath* path,
933 GtkTreeIter* iterator, gpointer data)
934 {
935 int fileType;
936 char* itemName;
937 char* fullItemName; /* with full path */
938 int rc;
939 GtkWidget* warningDialog;
940
941 if(GBLoperationCanceled)
942 return;
943
944 gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
945 COLUMN_FILENAME, &itemName, -1);
946
947 fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
948 if(fullItemName == NULL)
949 fatalError("extractFromIsoEachRowCbk(): malloc("
950 "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
951
952 strcpy(fullItemName, GBLisoCurrentDir);
953 strcat(fullItemName, itemName);
954
955 rc = bk_extract(&GBLvolInfo, fullItemName, GBLfsCurrentDir,
956 true, activityProgressUpdaterCbk);
957 if(rc <= 0)
958 {
959 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
960 GTK_DIALOG_DESTROY_WITH_PARENT,
961 GTK_MESSAGE_ERROR,
962 GTK_BUTTONS_CLOSE,
963 _("Failed to extract '%s': '%s'"),
964 itemName,
965 bk_get_error_string(rc));
966 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
967 gtk_dialog_run(GTK_DIALOG(warningDialog));
968 gtk_widget_destroy(warningDialog);
969 }
970
971 free(fullItemName);
972
973 g_free(itemName);
974 }
975
976 /******************************************************************************
977 * isoButtonPressedCbk()
978 * Make sure that a right-click on the view doesn't send the signal to the
979 * widget. If it did, a selection of multiple rows would be lost.
980 * I have a feeling someone did this shit in GTK just to piss on users */
isoButtonPressedCbk(GtkWidget * isoView,GdkEventButton * event,gpointer user_data)981 gboolean isoButtonPressedCbk(GtkWidget* isoView, GdkEventButton* event, gpointer user_data)
982 {
983 if(!GBLisoPaneActive)
984 /* no iso open */
985 return FALSE;
986
987 if(event->type == GDK_BUTTON_PRESS && event->button == 3)
988 {
989 /* Stop event propagation */
990 /*!! Would be nice if I could only stop event propagation if click was on
991 * the selection, I have to look into how that may be done, if at all */
992 return TRUE;
993 }
994
995 return FALSE;
996 }
997
998 /******************************************************************************
999 * isoButtonReleasedCbk()
1000 * Show context menu if releasing the right mouse button */
isoButtonReleasedCbk(GtkWidget * isoView,GdkEventButton * event,gpointer user_data)1001 gboolean isoButtonReleasedCbk(GtkWidget* isoView, GdkEventButton* event, gpointer user_data)
1002 {
1003 if(!GBLisoPaneActive)
1004 /* no iso open */
1005 return FALSE;
1006
1007 if(event->type == GDK_BUTTON_RELEASE && event->button == 3)
1008 {
1009 showIsoContextMenu(isoView, event);
1010 }
1011
1012 return FALSE;
1013 }
1014
1015 /* this is called from a button and via a treeview event so don't use the parameters */
isoGoUpDirTreeCbk(GtkButton * button,gpointer data)1016 void isoGoUpDirTreeCbk(GtkButton *button, gpointer data)
1017 {
1018 int count;
1019 bool done;
1020 char* newCurrentDir;
1021 GtkWidget* warningDialog;
1022
1023 /* do nothing if no image open */
1024 if(!GBLisoPaneActive)
1025 return;
1026
1027 /* do nothing if already at root */
1028 if(GBLisoCurrentDir[0] == '/' && GBLisoCurrentDir[1] == '\0')
1029 return;
1030
1031 /* need to allocate a new string because changeIsoDirectory() uses it
1032 * to copy from after freeing GBLisoCurrentDir */
1033 newCurrentDir = (char*)malloc(strlen(GBLisoCurrentDir) + 1);
1034 if(GBLisoCurrentDir == NULL)
1035 fatalError("isoGoUpDirTree(): malloc(strlen(GBLisoCurrentDir) + 1) failed");
1036 strcpy(newCurrentDir, GBLisoCurrentDir);
1037
1038 /* look for the second last slash */
1039 done = false;
1040 for(count = strlen(newCurrentDir) - 1; !done && count >= 0; count--)
1041 {
1042 if(newCurrentDir[count - 1] == '/')
1043 /* truncate the string */
1044 {
1045 newCurrentDir[count] = '\0';
1046 changeIsoDirectory(newCurrentDir);
1047 done = true;
1048 }
1049 }
1050
1051 if(!done)
1052 {
1053 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1054 GTK_DIALOG_DESTROY_WITH_PARENT,
1055 GTK_MESSAGE_ERROR,
1056 GTK_BUTTONS_CLOSE,
1057 "GUI error, GBLisoCurrentDir is not '/' and has "
1058 "only one slash, please report bug.");
1059 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1060 gtk_dialog_run(GTK_DIALOG(warningDialog));
1061 gtk_widget_destroy(warningDialog);
1062 }
1063
1064 free(newCurrentDir);
1065 }
1066
isoKeyPressedCbk(GtkWidget * widget,GdkEventKey * event,gpointer user_data)1067 gboolean isoKeyPressedCbk(GtkWidget* widget, GdkEventKey* event, gpointer user_data)
1068 {
1069 if(event->keyval == GDK_Delete)
1070 {
1071 deleteFromIsoCbk(NULL, NULL);
1072
1073 return TRUE;
1074 }
1075
1076 return FALSE;
1077 }
1078
isoRowDblClickCbk(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)1079 void isoRowDblClickCbk(GtkTreeView* treeview, GtkTreePath* path,
1080 GtkTreeViewColumn* col, gpointer data)
1081 {
1082 GtkTreeModel* model;
1083 GtkTreeIter iterator;
1084 char* name;
1085 char* newCurrentDir;
1086 int fileType;
1087 GtkWidget* warningDialog;
1088
1089 model = gtk_tree_view_get_model(treeview);
1090
1091 if(gtk_tree_model_get_iter(model, &iterator, path) == FALSE)
1092 {
1093 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1094 GTK_DIALOG_DESTROY_WITH_PARENT,
1095 GTK_MESSAGE_ERROR,
1096 GTK_BUTTONS_CLOSE,
1097 "GUI error: 'isoRowDblClicked(): "
1098 "gtk_tree_model_get_iter() failed'");
1099 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1100 gtk_dialog_run(GTK_DIALOG(warningDialog));
1101 gtk_widget_destroy(warningDialog);
1102 return;
1103 }
1104
1105 gtk_tree_model_get(model, &iterator, COLUMN_HIDDEN_TYPE, &fileType, -1);
1106 if(fileType == FILE_TYPE_DIRECTORY)
1107 {
1108 gtk_tree_model_get(model, &iterator, COLUMN_FILENAME, &name, -1);
1109
1110 newCurrentDir = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(name) + 2);
1111 if(newCurrentDir == NULL)
1112 fatalError("isoRowDblClicked(): malloc("
1113 "strlen(GBLisoCurrentDir) + strlen(name) + 2) failed");
1114
1115 strcpy(newCurrentDir, GBLisoCurrentDir);
1116 strcat(newCurrentDir, name);
1117 strcat(newCurrentDir, "/");
1118
1119 changeIsoDirectory(newCurrentDir);
1120
1121 free(newCurrentDir);
1122 g_free(name);
1123 }
1124 /* else do nothing (not a directory) */
1125 }
1126
1127 /* This callback is also used by an accelerator so make sure you don't use
1128 * the parameters, since they may not be the menuitem parameters */
newIsoCbk(GtkMenuItem * menuItem,gpointer data)1129 gboolean newIsoCbk(GtkMenuItem* menuItem, gpointer data)
1130 {
1131 int rc;
1132 GtkWidget* warningDialog;
1133
1134 if(GBLisoChangesProbable && !confirmCloseIso())
1135 return TRUE;
1136
1137 closeIso();
1138
1139 rc = bk_init_vol_info(&GBLvolInfo, GBLappSettings.scanForDuplicateFiles);
1140 if(rc <= 0)
1141 {
1142 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1143 GTK_DIALOG_DESTROY_WITH_PARENT,
1144 GTK_MESSAGE_ERROR,
1145 GTK_BUTTONS_CLOSE,
1146 _("Failed to initialise bkisofs: '%s'"),
1147 bk_get_error_string(rc));
1148 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1149 gtk_dialog_run(GTK_DIALOG(warningDialog));
1150 gtk_widget_destroy(warningDialog);
1151 return TRUE;
1152 }
1153
1154 GBLvolInfo.warningCbk = operationFailed;
1155
1156 GBLappSettings.filenameTypesToWrite = FNTYPE_9660 | FNTYPE_ROCKRIDGE | FNTYPE_JOLIET;
1157
1158 /* iso size label */
1159 char sizeStr[20];
1160 GBLisoSize = 35845;
1161 //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1162 GBLisoSize += 2048;
1163 GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
1164 formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
1165 gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
1166
1167 gtk_widget_set_sensitive(GBLisoCurrentDirField, TRUE);
1168 gtk_widget_set_sensitive(GBLisoTreeView, TRUE);
1169
1170 GBLisoPaneActive = true;
1171
1172 GBLisoChangesProbable = false;
1173
1174 changeIsoDirectory("/");
1175
1176 /* the accelerator callback must return true */
1177 return TRUE;
1178 }
1179
openIso(char * filename)1180 void openIso(char* filename)
1181 {
1182 int rc;
1183 GtkWidget* warningDialog;
1184
1185 /* MAYBE move around in recently open list */
1186 int alreadyInListIndex = -1;
1187 for(int i = 0; i < 5; i++)
1188 {
1189 const char* oldText = gtk_label_get_text(GTK_LABEL(
1190 gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i]))));
1191 if(strcmp(oldText, filename) == 0)
1192 alreadyInListIndex = i;
1193 }
1194 //!! flipping them is weird, what's really needed is to put the found
1195 // one up and push everything else down once, but that's too much work
1196 // so for now just add to the list if it's not already there, and do
1197 // nothing otherwise
1198 //~ if(alreadyInListIndex != -1)
1199 //~ {
1200 //~ const char* oldFirst = gtk_label_get_text(GTK_LABEL(
1201 //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))));
1202
1203 //~ // flip the two
1204 //~ printf("flip '%s' '%s'\n", oldFirst, gtk_label_get_text(GTK_LABEL(
1205 //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[alreadyInListIndex])))));
1206 //~ gtk_label_set_text(GTK_LABEL(
1207 //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[alreadyInListIndex]))),
1208 //~ oldFirst);
1209 //~ gtk_label_set_text(GTK_LABEL(
1210 //~ gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))),
1211 //~ filename);
1212 //~ }
1213 /* END MAYBE move around in recently open list */
1214
1215 /* MAYBE record recently open */
1216 if(alreadyInListIndex == -1)
1217 {
1218 // move all existing ones down once
1219 for(int i = 4; i > 0; i--)
1220 {
1221 const char* oldText = gtk_label_get_text(GTK_LABEL(
1222 gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i - 1]))));
1223 gtk_label_set_text(GTK_LABEL(
1224 gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[i]))),
1225 oldText);
1226 if(oldText[0] != '\0')
1227 gtk_widget_show(GBLrecentlyOpenWidgets[i]);
1228 }
1229 gtk_label_set_text(GTK_LABEL(
1230 gtk_bin_get_child(GTK_BIN(GBLrecentlyOpenWidgets[0]))),
1231 filename);
1232 gtk_widget_show(GBLrecentlyOpenWidgets[0]);
1233 }
1234 /* END MAYBE record recently open */
1235
1236 if(GBLisoChangesProbable && !confirmCloseIso())
1237 return;
1238
1239 closeIso();
1240
1241 rc = bk_init_vol_info(&GBLvolInfo, GBLappSettings.scanForDuplicateFiles);
1242 if(rc <= 0)
1243 {
1244 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1245 GTK_DIALOG_DESTROY_WITH_PARENT,
1246 GTK_MESSAGE_ERROR,
1247 GTK_BUTTONS_CLOSE,
1248 _("Failed to initialise bkisofs: '%s'"),
1249 bk_get_error_string(rc));
1250 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1251 gtk_dialog_run(GTK_DIALOG(warningDialog));
1252 gtk_widget_destroy(warningDialog);
1253 return;
1254 }
1255
1256 GBLvolInfo.warningCbk = operationFailed;
1257
1258 GBLappSettings.filenameTypesToWrite = FNTYPE_9660 | FNTYPE_ROCKRIDGE | FNTYPE_JOLIET;
1259
1260 rc = bk_open_image(&GBLvolInfo, filename);
1261 if(rc <= 0)
1262 {
1263 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1264 GTK_DIALOG_DESTROY_WITH_PARENT,
1265 GTK_MESSAGE_ERROR,
1266 GTK_BUTTONS_CLOSE,
1267 _("Failed to open iso file for reading: '%s'"),
1268 bk_get_error_string(rc));
1269 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1270 gtk_dialog_run(GTK_DIALOG(warningDialog));
1271 gtk_widget_destroy(warningDialog);
1272 return;
1273 }
1274
1275 rc = bk_read_vol_info(&GBLvolInfo);
1276 if(rc <= 0)
1277 {
1278 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1279 GTK_DIALOG_DESTROY_WITH_PARENT,
1280 GTK_MESSAGE_ERROR,
1281 GTK_BUTTONS_CLOSE,
1282 _("Failed to read volume info: '%s'"),
1283 bk_get_error_string(rc));
1284 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1285 gtk_dialog_run(GTK_DIALOG(warningDialog));
1286 gtk_widget_destroy(warningDialog);
1287 closeIso();
1288 return;
1289 }
1290
1291 /* CREATE and show progress bar */
1292 GtkWidget* progressWindow;
1293 GtkWidget* label;
1294
1295 /* dialog window for the progress bar */
1296 progressWindow = gtk_dialog_new();
1297 gtk_dialog_set_has_separator(GTK_DIALOG(progressWindow), FALSE);
1298 gtk_window_set_modal(GTK_WINDOW(progressWindow), TRUE);
1299 gtk_window_set_title(GTK_WINDOW(progressWindow), _("Progress"));
1300 gtk_window_set_transient_for(GTK_WINDOW(progressWindow), GTK_WINDOW(GBLmainWindow));
1301 g_signal_connect_swapped(progressWindow, "delete-event",
1302 G_CALLBACK(activityProgressWindowDeleteCbk), NULL);
1303 g_signal_connect_swapped(progressWindow, "response",
1304 G_CALLBACK(cancelOperation), NULL);
1305
1306 label = gtk_label_new(_("Please wait while I'm reading the image..."));
1307 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
1308 gtk_widget_show(label);
1309
1310 if(GBLappSettings.scanForDuplicateFiles)
1311 {
1312 label = gtk_label_new(_("(scanning for duplicate files)"));
1313 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), label, TRUE, TRUE, 0);
1314 gtk_widget_show(label);
1315 }
1316
1317 /* the progress bar */
1318 GBLactivityProgressBar = gtk_progress_bar_new();
1319 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(progressWindow)->vbox), GBLactivityProgressBar, TRUE, TRUE, 0);
1320 gtk_widget_show(GBLactivityProgressBar);
1321
1322 /* button to cancel adding */
1323 gtk_dialog_add_button(GTK_DIALOG(progressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1324
1325 /* if i show it before i add the children, the window ends up being not centered */
1326 gtk_widget_show(progressWindow);
1327 /* END CREATE and show progress bar */
1328
1329 /* READ entire directory tree */
1330 if(GBLvolInfo.filenameTypes & FNTYPE_ROCKRIDGE)
1331 rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_ROCKRIDGE, true, activityProgressUpdaterCbk);
1332 else if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1333 rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_JOLIET, false, activityProgressUpdaterCbk);
1334 else
1335 rc = bk_read_dir_tree(&GBLvolInfo, FNTYPE_9660, false, activityProgressUpdaterCbk);
1336 if(rc <= 0)
1337 {
1338 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1339 GTK_DIALOG_DESTROY_WITH_PARENT,
1340 GTK_MESSAGE_ERROR,
1341 GTK_BUTTONS_CLOSE,
1342 _("Failed to read directory tree: '%s'"),
1343 bk_get_error_string(rc));
1344 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1345 gtk_dialog_run(GTK_DIALOG(warningDialog));
1346 gtk_widget_destroy(warningDialog);
1347 }
1348 /* END READ entire directory tree */
1349
1350 gtk_widget_destroy(progressWindow);
1351 GBLactivityProgressBar = NULL;
1352
1353 if(rc <= 0)
1354 {
1355 closeIso();
1356 return;
1357 }
1358
1359 #ifdef ENABLE_SAVE_OVERWRITE
1360 openIsoPathAndName = malloc(strlen(filename) + 1);
1361 strcpy(openIsoPathAndName, filename);
1362 #endif
1363
1364 /* iso size label */
1365 char sizeStr[20];
1366 GBLisoSize = 35845;
1367 //if(GBLvolInfo.filenameTypes & FNTYPE_JOLIET)
1368 GBLisoSize += 2048;
1369
1370 /* SET WINDOW title */
1371 int filenameLen = strlen(filename);
1372
1373 char* windowTitle = malloc(filenameLen + strlen(" - ISO Master") + 1);
1374 if(windowTitle == NULL)
1375 fatalError("windowTitle = malloc(strlen(filename) + \" - ISO Master\" + 1) failed");
1376
1377 int lastSlashIndex = -1;
1378 int count;
1379 for(count = 0; count < filenameLen; count++)
1380 {
1381 if(filename[count] == '/')
1382 lastSlashIndex = count;
1383 }
1384
1385 if(lastSlashIndex == -1)
1386 strcpy(windowTitle, filename);
1387 else
1388 strcpy(windowTitle, filename + lastSlashIndex + 1);
1389 strcat(windowTitle, " - ISO Master");
1390
1391 gtk_window_set_title(GTK_WINDOW(GBLmainWindow), windowTitle);
1392
1393 free(windowTitle);
1394 /* END SET WINDOW title */
1395
1396 GBLisoSize += bk_estimate_iso_size(&GBLvolInfo, FNTYPE_9660 | FNTYPE_JOLIET | FNTYPE_ROCKRIDGE);
1397 formatSize(GBLisoSize, sizeStr, sizeof(sizeStr));
1398 gtk_label_set_text(GTK_LABEL(GBLisoSizeLbl), sizeStr);
1399
1400 gtk_widget_set_sensitive(GBLisoCurrentDirField, TRUE);
1401 gtk_widget_set_sensitive(GBLisoTreeView, TRUE);
1402
1403 changeIsoDirectory("/");
1404
1405 GBLisoPaneActive = true;
1406
1407 GBLisoChangesProbable = false;
1408 }
1409
1410 /* This callback is also used by an accelerator so make sure you don't use
1411 * the parameters, since they may not be the menuitem parameters */
openIsoCbk(GtkMenuItem * menuItem,gpointer data)1412 gboolean openIsoCbk(GtkMenuItem* menuItem, gpointer data)
1413 {
1414 GtkWidget *dialog;
1415 char* filename = NULL;
1416 GtkFileFilter* nameFilter;
1417 int dialogRespose;
1418
1419 dialog = gtk_file_chooser_dialog_new("Open File",
1420 NULL,
1421 GTK_FILE_CHOOSER_ACTION_OPEN,
1422 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1423 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1424 NULL);
1425
1426 nameFilter = gtk_file_filter_new();
1427 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[iI][sS][oO]");
1428 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("ISO Images"));
1429 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1430
1431 nameFilter = gtk_file_filter_new();
1432 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[nN][rR][gG]");
1433 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("NRG Images"));
1434 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1435
1436 nameFilter = gtk_file_filter_new();
1437 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[mM][dD][fF]");
1438 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("MDF Images"));
1439 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1440
1441 nameFilter = gtk_file_filter_new();
1442 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*");
1443 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("All files"));
1444 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1445
1446 if(GBLappSettings.lastIsoDir != NULL)
1447 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), GBLappSettings.lastIsoDir);
1448
1449 dialogRespose = gtk_dialog_run(GTK_DIALOG(dialog));
1450
1451 if(dialogRespose == GTK_RESPONSE_ACCEPT)
1452 {
1453 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1454
1455 /* RECORD last iso dir */
1456 char* lastIsoDir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
1457 if(lastIsoDir)
1458 {
1459 if(GBLappSettings.lastIsoDir != NULL && strlen(lastIsoDir) > strlen(GBLappSettings.lastIsoDir))
1460 {
1461 free(GBLappSettings.lastIsoDir);
1462 GBLappSettings.lastIsoDir = NULL;
1463 }
1464
1465 if(GBLappSettings.lastIsoDir == NULL)
1466 GBLappSettings.lastIsoDir = malloc(strlen(lastIsoDir) + 1);
1467
1468 strcpy(GBLappSettings.lastIsoDir, lastIsoDir);
1469
1470 g_free(lastIsoDir);
1471 }
1472 else /* e.g. when opening a file from the <Recently used> view */
1473 {
1474 free(GBLappSettings.lastIsoDir);
1475 GBLappSettings.lastIsoDir = NULL;
1476 }
1477 /* END RECORD last iso dir */
1478 }
1479
1480 gtk_widget_destroy(dialog);
1481
1482 if(dialogRespose == GTK_RESPONSE_ACCEPT)
1483 {
1484 openIso(filename);
1485
1486 g_free(filename);
1487 }
1488
1489 //~ openIso("image.iso");
1490
1491 /* the accelerator callback must return true */
1492 return TRUE;
1493 }
1494
openRecentIso(GtkMenuItem * menuitem,gpointer data)1495 void openRecentIso(GtkMenuItem *menuitem, gpointer data)
1496 {
1497 const char* filename = gtk_label_get_text(GTK_LABEL(
1498 gtk_bin_get_child(GTK_BIN(menuitem))));
1499 openIso((char*)filename);
1500 }
1501
operationFailed(const char * msg)1502 bool operationFailed(const char* msg)
1503 {
1504 GtkWidget* warningDialog;
1505 gint response;
1506
1507 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1508 GTK_DIALOG_DESTROY_WITH_PARENT,
1509 GTK_MESSAGE_WARNING,
1510 GTK_BUTTONS_YES_NO,
1511 _("%s\n\nDo you wish to continue?"),
1512 msg);
1513 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1514 gtk_dialog_set_default_response(GTK_DIALOG(warningDialog), GTK_RESPONSE_YES);
1515 response = gtk_dialog_run(GTK_DIALOG(warningDialog));
1516 gtk_widget_destroy(warningDialog);
1517
1518 if(response == GTK_RESPONSE_YES)
1519 return true;
1520 else
1521 {
1522 GBLoperationCanceled = true;
1523 return false;
1524 }
1525 }
1526
refreshIsoView(void)1527 void refreshIsoView(void)
1528 {
1529 char* isoCurrentDir; /* for changeIsoDirectory() */
1530
1531 isoCurrentDir = malloc(strlen(GBLisoCurrentDir) + 1);
1532 if(isoCurrentDir == NULL)
1533 fatalError("refreshIsoView(): malloc("
1534 "strlen(GBLisoCurrentDir) + 1) failed");
1535 strcpy(isoCurrentDir, GBLisoCurrentDir);
1536
1537 /* remember scroll position */
1538 GdkRectangle visibleRect;
1539 gtk_tree_view_get_visible_rect(GTK_TREE_VIEW(GBLisoTreeView), &visibleRect);
1540
1541 changeIsoDirectory(isoCurrentDir);
1542
1543 /* need the -1 because if i call this function with the same coordinates that
1544 * the view already has, the position is set to 0. think it's a gtk bug. */
1545 gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(GBLisoTreeView), visibleRect.x - 1, visibleRect.y - 1);
1546
1547 free(isoCurrentDir);
1548 }
1549
renameSelected(void)1550 void renameSelected(void)
1551 {
1552 GtkTreeSelection* selection;
1553
1554 /* do nothing if no image open */
1555 if(!GBLisoPaneActive)
1556 return;
1557
1558 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
1559
1560 if(gtk_tree_selection_count_selected_rows(selection) != 1)
1561 return;
1562
1563 /* there's just one row selected but this is the easiest way to do it */
1564 gtk_tree_selection_selected_foreach(selection, renameSelectedRowCbk, NULL);
1565
1566 /* can't put this in the callback because gtk complains */
1567 refreshIsoView();
1568 }
1569
renameSelectedRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)1570 void renameSelectedRowCbk(GtkTreeModel* model, GtkTreePath* path,
1571 GtkTreeIter* iterator, gpointer data)
1572 {
1573 GtkWidget* dialog;
1574 GtkWidget* nameField;
1575 int rc;
1576 char* itemName;
1577 char* fullItemName;
1578 GtkWidget* warningDialog;
1579
1580 gtk_tree_model_get(model, iterator, COLUMN_FILENAME, &itemName, -1);
1581
1582 fullItemName = (char*)malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
1583 if(fullItemName == NULL)
1584 fatalError("extractFromIsoEachRowCbk(): malloc("
1585 "strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed (out of memory?)");
1586
1587 strcpy(fullItemName, GBLisoCurrentDir);
1588 strcat(fullItemName, itemName);
1589
1590 dialog = gtk_dialog_new_with_buttons(_("Enter a new name:"),
1591 GTK_WINDOW(GBLmainWindow),
1592 GTK_DIALOG_DESTROY_WITH_PARENT,
1593 GTK_STOCK_OK,
1594 GTK_RESPONSE_ACCEPT,
1595 GTK_STOCK_CANCEL,
1596 GTK_RESPONSE_REJECT,
1597 NULL);
1598 g_signal_connect(dialog, "close", G_CALLBACK(rejectDialogCbk), NULL);
1599
1600 nameField = gtk_entry_new_with_max_length(NCHARS_FILE_ID_MAX_STORE);
1601 gtk_entry_set_text(GTK_ENTRY(nameField), itemName);
1602 gtk_entry_set_width_chars(GTK_ENTRY(nameField), 32);
1603 g_signal_connect(nameField, "activate", (GCallback)acceptDialogCbk, dialog);
1604 gtk_widget_show(nameField);
1605 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), nameField, TRUE, TRUE, 0);
1606
1607 gtk_widget_show(dialog);
1608
1609 rc = gtk_dialog_run(GTK_DIALOG(dialog));
1610 if(rc == GTK_RESPONSE_ACCEPT)
1611 {
1612 rc = bk_rename(&GBLvolInfo, fullItemName, gtk_entry_get_text(GTK_ENTRY(nameField)));
1613 if(rc < 0)
1614 {
1615 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1616 GTK_DIALOG_DESTROY_WITH_PARENT,
1617 GTK_MESSAGE_ERROR,
1618 GTK_BUTTONS_CLOSE,
1619 _("Failed to rename '%s': %s"),
1620 itemName,
1621 bk_get_error_string(rc));
1622 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1623 gtk_dialog_run(GTK_DIALOG(warningDialog));
1624 gtk_widget_destroy(warningDialog);
1625 }
1626 else
1627 GBLisoChangesProbable = true;
1628 }
1629
1630 gtk_widget_destroy(dialog);
1631
1632 g_free(itemName);
1633 free(fullItemName);
1634 }
1635
renameSelectedBtnCbk(GtkMenuItem * menuitem,gpointer data)1636 void renameSelectedBtnCbk(GtkMenuItem *menuitem, gpointer data)
1637 {
1638 /* because I'm lazy just call this one, it will work */
1639 renameSelected();
1640 }
1641
saveIso(char * filename)1642 void saveIso(char* filename)
1643 {
1644 int rc;
1645 GtkWidget* descriptionLabel;
1646 GtkWidget* okButton;
1647 GtkWidget* cancelButton;
1648 GtkWidget* warningDialog;
1649
1650 /* dialog window for the progress bar */
1651 GBLwritingProgressWindow = gtk_dialog_new();
1652 gtk_dialog_set_has_separator(GTK_DIALOG(GBLwritingProgressWindow), FALSE);
1653 gtk_window_set_modal(GTK_WINDOW(GBLwritingProgressWindow), TRUE);
1654 gtk_window_set_title(GTK_WINDOW(GBLwritingProgressWindow), _("Progress"));
1655 gtk_window_set_transient_for(GTK_WINDOW(GBLwritingProgressWindow), GTK_WINDOW(GBLmainWindow));
1656 g_signal_connect_swapped(GBLwritingProgressWindow, "delete-event",
1657 G_CALLBACK(writingProgressWindowDeleteCbk), NULL);
1658 g_signal_connect_swapped(GBLwritingProgressWindow, "response",
1659 G_CALLBACK(writingProgressResponse), GBLwritingProgressWindow);
1660 g_signal_connect_swapped(GBLwritingProgressWindow, "destroy",
1661 G_CALLBACK(writingProgressWindowDestroyedCbk), NULL);
1662
1663 /* just some text */
1664 descriptionLabel = gtk_label_new(_("Please wait while I'm saving the new image to disk..."));
1665 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(GBLwritingProgressWindow)->vbox), descriptionLabel, TRUE, TRUE, 0);
1666 gtk_widget_show(descriptionLabel);
1667
1668 /* the progress bar */
1669 GBLWritingProgressBar = gtk_progress_bar_new();
1670 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(GBLwritingProgressWindow)->vbox), GBLWritingProgressBar, TRUE, TRUE, 0);
1671 gtk_widget_show(GBLWritingProgressBar);
1672
1673 /* button to close the dialog (disabled until writing finished) */
1674 okButton = gtk_dialog_add_button(GTK_DIALOG(GBLwritingProgressWindow), GTK_STOCK_OK, GTK_RESPONSE_OK);
1675 gtk_widget_set_sensitive(okButton, FALSE);
1676
1677 /* button to cancel writing */
1678 cancelButton = gtk_dialog_add_button(GTK_DIALOG(GBLwritingProgressWindow), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1679
1680 /* if i show it before i add the children, the window ends up being not centered */
1681 gtk_widget_show(GBLwritingProgressWindow);
1682
1683 /* write new image */
1684 rc = bk_write_image(filename, &GBLvolInfo, time(NULL), GBLappSettings.filenameTypesToWrite,
1685 writingProgressUpdaterCbk);
1686 if(rc < 0)
1687 {
1688 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1689 GTK_DIALOG_DESTROY_WITH_PARENT,
1690 GTK_MESSAGE_ERROR,
1691 GTK_BUTTONS_CLOSE,
1692 _("Failed to write image to '%s': '%s'"),
1693 filename,
1694 bk_get_error_string(rc));
1695 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1696 gtk_dialog_run(GTK_DIALOG(warningDialog));
1697 gtk_widget_destroy(warningDialog);
1698 if(GBLWritingProgressBar != NULL)
1699 gtk_widget_destroy(GBLwritingProgressWindow);
1700 }
1701 else
1702 GBLisoChangesProbable = false;
1703
1704 if(GBLWritingProgressBar != NULL)
1705 /* progress window hasn't been destroyed */
1706 {
1707 /* enable the ok button so the user can close the progress window */
1708 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(GBLWritingProgressBar), 1.0);
1709 gtk_widget_set_sensitive(okButton, TRUE);
1710 gtk_widget_grab_focus(okButton);
1711 gtk_widget_set_sensitive(cancelButton, FALSE);
1712 }
1713 }
1714
1715 /* This callback is also used by an accelerator so make sure you don't use
1716 * the parameters, since they may not be the menuitem parameters */
saveIsoCbk(GtkWidget * widget,GdkEvent * event)1717 gboolean saveIsoCbk(GtkWidget *widget, GdkEvent *event)
1718 {
1719 GtkWidget *dialog;
1720 char* filename = NULL;
1721 int dialogResponse;
1722 GtkFileFilter* nameFilter;
1723 GtkWidget* addExtensionCheckbox;
1724 bool askedToAddExtension;
1725
1726 /* do nothing if no image open */
1727 if(!GBLisoPaneActive)
1728 return TRUE;
1729
1730 dialog = gtk_file_chooser_dialog_new(_("Save File"),
1731 NULL,
1732 GTK_FILE_CHOOSER_ACTION_SAVE,
1733 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1734 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1735 NULL);
1736 // gtk problem? enter doesn't work
1737 //g_signal_connect(dialog, "key-press-event", (GCallback), NULL);
1738
1739 nameFilter = gtk_file_filter_new();
1740 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*.[iI][sS][oO]");
1741 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("ISO Images"));
1742 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1743
1744 nameFilter = gtk_file_filter_new();
1745 gtk_file_filter_add_pattern(GTK_FILE_FILTER(nameFilter), "*");
1746 gtk_file_filter_set_name(GTK_FILE_FILTER(nameFilter), _("All files"));
1747 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), GTK_FILE_FILTER(nameFilter));
1748
1749 addExtensionCheckbox = gtk_check_button_new_with_label(_("Add extension automatically"));
1750 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), addExtensionCheckbox);
1751 if(GBLappSettings.appendExtension)
1752 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox), TRUE);
1753 else
1754 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox), FALSE);
1755 gtk_widget_show(addExtensionCheckbox);
1756
1757 if(GBLappSettings.lastIsoDir != NULL)
1758 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), GBLappSettings.lastIsoDir);
1759
1760 dialogResponse = gtk_dialog_run(GTK_DIALOG(dialog));
1761
1762 if(dialogResponse == GTK_RESPONSE_ACCEPT)
1763 {
1764 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1765
1766 /* RECORD last iso dir */
1767 char* lastIsoDir = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
1768 if(lastIsoDir)
1769 {
1770 if(GBLappSettings.lastIsoDir != NULL && strlen(lastIsoDir) > strlen(GBLappSettings.lastIsoDir))
1771 {
1772 free(GBLappSettings.lastIsoDir);
1773 GBLappSettings.lastIsoDir = NULL;
1774 }
1775
1776 if(GBLappSettings.lastIsoDir == NULL)
1777 GBLappSettings.lastIsoDir = malloc(strlen(lastIsoDir) + 1);
1778
1779 strcpy(GBLappSettings.lastIsoDir, lastIsoDir);
1780
1781 g_free(lastIsoDir);
1782 }
1783 else /* e.g. when opening a file from the <Recently used> view */
1784 {
1785 free(GBLappSettings.lastIsoDir);
1786 GBLappSettings.lastIsoDir = NULL;
1787 }
1788 /* END RECORD last iso dir */
1789
1790 askedToAddExtension = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(addExtensionCheckbox));
1791 }
1792
1793 gtk_widget_destroy(dialog);
1794
1795 if(dialogResponse == GTK_RESPONSE_ACCEPT)
1796 {
1797 char* nameWithExtension;
1798
1799 nameWithExtension = malloc(strlen(filename) + 5);
1800 if(nameWithExtension == NULL)
1801 fatalError("saveIsoCbk(): malloc(strlen(filename) + 5) failed");
1802
1803 strcpy(nameWithExtension, filename);
1804 g_free(filename);
1805
1806 if(askedToAddExtension)
1807 {
1808 regex_t extensionRegex;
1809
1810 regcomp(&extensionRegex, ".*\\.[iI][sS][oO]$", 0);
1811
1812 if(regexec(&extensionRegex, nameWithExtension, 0, NULL, 0) != 0)
1813 /* doesn't already end with .iso */
1814 strcat(nameWithExtension, ".iso");
1815
1816 GBLappSettings.appendExtension = true;
1817 }
1818 else
1819 GBLappSettings.appendExtension = false;
1820
1821 saveIso(nameWithExtension);
1822
1823 free(nameWithExtension);
1824 }
1825
1826 //~ saveIso("/home/andrei/out.iso");
1827
1828 /* the accelerator callback must return true */
1829 return TRUE;
1830 }
1831
1832 #ifdef ENABLE_SAVE_OVERWRITE
1833 #define TEMPFILENAME "/tmp/isomaster-temp.iso"
saveOverwriteIsoCbk(GtkWidget * widget,GdkEvent * event)1834 gboolean saveOverwriteIsoCbk(GtkWidget *widget, GdkEvent *event)
1835 {
1836 int sourceFile;
1837 int destFile;
1838 int numBytesRead;
1839 char line[1024];
1840 GtkWidget* warningDialog;
1841
1842 saveIso(TEMPFILENAME);
1843
1844 printf("moving %s to %s\n", TEMPFILENAME, openIsoPathAndName);
1845
1846 sourceFile = open(TEMPFILENAME, O_RDONLY);
1847 if(sourceFile == -1)
1848 {
1849 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1850 GTK_DIALOG_DESTROY_WITH_PARENT,
1851 GTK_MESSAGE_ERROR,
1852 GTK_BUTTONS_CLOSE,
1853 "Failed to open %s for reading",
1854 TEMPFILENAME);
1855 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1856 gtk_dialog_run(GTK_DIALOG(warningDialog));
1857 gtk_widget_destroy(warningDialog);
1858 if(GBLWritingProgressBar != NULL)
1859 gtk_widget_destroy(GBLwritingProgressWindow);
1860 }
1861
1862 destFile = open(openIsoPathAndName, O_WRONLY | O_CREAT);
1863 if(destFile == -1)
1864 {
1865 warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
1866 GTK_DIALOG_DESTROY_WITH_PARENT,
1867 GTK_MESSAGE_ERROR,
1868 GTK_BUTTONS_CLOSE,
1869 "Failed to open %s for writing",
1870 openIsoPathAndName);
1871 gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
1872 gtk_dialog_run(GTK_DIALOG(warningDialog));
1873 gtk_widget_destroy(warningDialog);
1874 if(GBLWritingProgressBar != NULL)
1875 gtk_widget_destroy(GBLwritingProgressWindow);
1876 }
1877
1878 while((numBytesRead = read(sourceFile, line, sizeof(line))) > 0)
1879 write(destFile, line, numBytesRead);
1880
1881 close(sourceFile);
1882 close(destFile);
1883
1884 return FALSE;
1885 }
1886 #endif
1887
showIsoContextMenu(GtkWidget * isoView,GdkEventButton * event)1888 void showIsoContextMenu(GtkWidget* isoView, GdkEventButton* event)
1889 {
1890 GtkWidget* menu;
1891 GtkWidget* menuItem;
1892 GtkTreeSelection* selection;
1893 gint numSelectedRows;
1894 GtkAccelGroup* accelGroup;
1895
1896 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
1897
1898 numSelectedRows = gtk_tree_selection_count_selected_rows(selection);
1899 if(numSelectedRows == 0)
1900 return;
1901
1902 /* have this here just so that the shortcut keys show in the context menu */
1903 accelGroup = gtk_accel_group_new();
1904 gtk_window_add_accel_group(GTK_WINDOW(GBLmainWindow), accelGroup);
1905
1906 menu = gtk_menu_new();
1907 gtk_menu_set_accel_group(GTK_MENU(menu), accelGroup);
1908
1909 menuItem = gtk_image_menu_item_new_with_label(_("Rename"));
1910 g_signal_connect(menuItem, "activate",
1911 (GCallback)renameSelectedBtnCbk, NULL);
1912 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Rename");
1913 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1914 gtk_widget_show_all(menu);
1915 if(numSelectedRows > 1)
1916 gtk_widget_set_sensitive(menuItem, FALSE);
1917
1918 menuItem = gtk_image_menu_item_new_with_label(_("View"));
1919 g_signal_connect(menuItem, "activate",
1920 (GCallback)viewSelectedBtnCbk, NULL);
1921 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/View");
1922 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1923 gtk_widget_show_all(menu);
1924
1925 menuItem = gtk_image_menu_item_new_with_label(_("Edit"));
1926 g_signal_connect(menuItem, "activate",
1927 (GCallback)editSelectedBtnCbk, NULL);
1928 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuItem), "<ISOMaster>/Contextmenu/Edit");
1929 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1930 gtk_widget_show_all(menu);
1931
1932 menuItem = gtk_image_menu_item_new_with_label(_("Change permissions"));
1933 g_signal_connect(menuItem, "activate",
1934 (GCallback)changePermissionsBtnCbk, NULL);
1935 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuItem);
1936 gtk_widget_show_all(menu);
1937 //~ if(numSelectedRows > 1)
1938 //~ gtk_widget_set_sensitive(menuItem, FALSE);
1939
1940 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1941 event->button, gdk_event_get_time((GdkEvent*)event));
1942 }
1943
1944 /* this handles the ok and cancel buttons in the progress window */
writingProgressResponse(GtkDialog * dialog,gint arg1,gpointer user_data)1945 void writingProgressResponse(GtkDialog* dialog, gint arg1, gpointer user_data)
1946 {
1947 if(arg1 == GTK_RESPONSE_CANCEL)
1948 bk_cancel_operation(&GBLvolInfo);
1949 else if(arg1 == GTK_RESPONSE_OK)
1950 gtk_widget_destroy(GBLwritingProgressWindow);
1951 }
1952
writingProgressUpdaterCbk(VolInfo * volInfo,double percentComplete)1953 void writingProgressUpdaterCbk(VolInfo* volInfo, double percentComplete)
1954 {
1955 if(GBLWritingProgressBar != NULL)
1956 {
1957 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(GBLWritingProgressBar), percentComplete / 100);
1958
1959 /* redraw progress bar */
1960 while(gtk_events_pending())
1961 gtk_main_iteration();
1962 }
1963 }
1964
writingProgressWindowDeleteCbk(GtkWidget * widget,GdkEvent * event,gpointer user_data)1965 gboolean writingProgressWindowDeleteCbk(GtkWidget* widget, GdkEvent* event,
1966 gpointer user_data)
1967 {
1968 /* don't allow closing */
1969 return TRUE;
1970 }
1971
writingProgressWindowDestroyedCbk(void)1972 void writingProgressWindowDestroyedCbk(void)
1973 {
1974 GBLwritingProgressWindow = NULL;
1975 GBLWritingProgressBar = NULL;
1976 }
1977