diff options
Diffstat (limited to 'mat-gui')
| -rwxr-xr-x | mat-gui | 93 |
1 files changed, 50 insertions, 43 deletions
| @@ -1,7 +1,7 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -* | 2 | # -*- coding: utf-8 -* |
| 3 | 3 | ||
| 4 | ''' Metadata anonymisation toolkit - GUI edition ''' | 4 | """ Metadata anonymisation toolkit - GUI edition """ |
| 5 | 5 | ||
| 6 | from gi.repository import GObject, Gtk, GLib | 6 | from gi.repository import GObject, Gtk, GLib |
| 7 | from gi.repository import Gdk, GdkPixbuf | 7 | from gi.repository import Gdk, GdkPixbuf |
| @@ -22,17 +22,19 @@ logging.basicConfig(level=mat.LOGGING_LEVEL) | |||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | class CFile(GObject.Object): | 24 | class CFile(GObject.Object): |
| 25 | ''' Contain the "parser" class of the file "filename" | 25 | """ Contain the "parser" class of the file "filename" |
| 26 | This class exist just to be "around" my parser.Generic_parser class, | 26 | This class exist just to be "around" my parser.Generic_parser class, |
| 27 | since the Gtk.ListStore does not accept it because it does not | 27 | since the Gtk.ListStore does not accept it because it does not |
| 28 | extends Gobject.Object | 28 | extends Gobject.Object |
| 29 | ''' | 29 | """ |
| 30 | |||
| 30 | def __init__(self, filename, **kwargs): | 31 | def __init__(self, filename, **kwargs): |
| 31 | self.file = mat.create_class_file(filename, 0, **kwargs) | 32 | self.file = mat.create_class_file(filename, 0, **kwargs) |
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | class GUI(object): | 35 | class GUI(object): |
| 35 | ''' Main GUI class ''' | 36 | """ Main GUI class """ |
| 37 | |||
| 36 | def __init__(self): | 38 | def __init__(self): |
| 37 | # Preferences | 39 | # Preferences |
| 38 | self.add2archive = False | 40 | self.add2archive = False |
| @@ -67,7 +69,7 @@ class GUI(object): | |||
| 67 | self.window.show_all() | 69 | self.window.show_all() |
| 68 | 70 | ||
| 69 | def __init_supported_popup(self): | 71 | def __init_supported_popup(self): |
| 70 | ''' Initialise the "supported formats" popup ''' | 72 | """ Initialise the "supported formats" popup """ |
| 71 | self.supported_dict = mat.XMLParser() | 73 | self.supported_dict = mat.XMLParser() |
| 72 | xml_parser = xml.sax.make_parser() | 74 | xml_parser = xml.sax.make_parser() |
| 73 | xml_parser.setContentHandler(self.supported_dict) | 75 | xml_parser.setContentHandler(self.supported_dict) |
| @@ -89,7 +91,7 @@ class GUI(object): | |||
| 89 | self.cb_update_supported_popup(supported_cbox) # to initially fill the dialog | 91 | self.cb_update_supported_popup(supported_cbox) # to initially fill the dialog |
| 90 | 92 | ||
| 91 | def __set_drag_treeview(self): | 93 | def __set_drag_treeview(self): |
| 92 | ''' Setup the drag'n'drop handling by the treeview ''' | 94 | """ Setup the drag'n'drop handling by the treeview """ |
| 93 | self.treeview.drag_dest_set( | 95 | self.treeview.drag_dest_set( |
| 94 | Gtk.DestDefaults.MOTION | | 96 | Gtk.DestDefaults.MOTION | |
| 95 | Gtk.DestDefaults.HIGHLIGHT | | 97 | Gtk.DestDefaults.HIGHLIGHT | |
| @@ -99,17 +101,18 @@ class GUI(object): | |||
| 99 | targets.add_uri_targets(80) | 101 | targets.add_uri_targets(80) |
| 100 | self.treeview.drag_dest_set_target_list(targets) | 102 | self.treeview.drag_dest_set_target_list(targets) |
| 101 | 103 | ||
| 102 | def cb_hide_widget(self, widget, _): | 104 | @staticmethod |
| 103 | ''' This function is a little hack to hide instead | 105 | def cb_hide_widget(widget, _): |
| 106 | """ This function is a little hack to hide instead | ||
| 104 | of close re-usable popups, like supported-fileformats, | 107 | of close re-usable popups, like supported-fileformats, |
| 105 | popup-metadata, ...''' | 108 | popup-metadata, ...""" |
| 106 | widget.hide() | 109 | widget.hide() |
| 107 | return False | 110 | return False |
| 108 | 111 | ||
| 109 | def cb_update_supported_popup(self, window): | 112 | def cb_update_supported_popup(self, window): |
| 110 | ''' Fill GtkEntries of the supported_format_popups | 113 | """ Fill GtkEntries of the supported_format_popups |
| 111 | with corresponding data. | 114 | with corresponding data. |
| 112 | ''' | 115 | """ |
| 113 | index = window.get_model()[window.get_active_iter()][0] | 116 | index = window.get_model()[window.get_active_iter()][0] |
| 114 | support = self.builder.get_object('supported_support') | 117 | support = self.builder.get_object('supported_support') |
| 115 | support.set_text(self.supported_dict.list[index]['support']) | 118 | support.set_text(self.supported_dict.list[index]['support']) |
| @@ -120,15 +123,16 @@ class GUI(object): | |||
| 120 | remaining = self.builder.get_object('supported_remaining').get_buffer() | 123 | remaining = self.builder.get_object('supported_remaining').get_buffer() |
| 121 | remaining.set_text(self.supported_dict.list[index]['remaining']) | 124 | remaining.set_text(self.supported_dict.list[index]['remaining']) |
| 122 | 125 | ||
| 123 | def cb_close_application(self, _): | 126 | @staticmethod |
| 124 | ''' Close the application ''' | 127 | def cb_close_application(_): |
| 128 | """ Close the application """ | ||
| 125 | Gtk.main_quit() | 129 | Gtk.main_quit() |
| 126 | 130 | ||
| 127 | def cb_add_files(self, button): | 131 | def cb_add_files(self, button): |
| 128 | ''' Add the files chosen by the filechooser ("Add" button) ''' | 132 | """ Add the files chosen by the filechooser ("Add" button) """ |
| 129 | chooser = Gtk.FileChooserDialog(title=_('Choose files'), | 133 | chooser = Gtk.FileChooserDialog(title=_('Choose files'), |
| 130 | parent=self.window, action=Gtk.FileChooserAction.OPEN, | 134 | parent=self.window, action=Gtk.FileChooserAction.OPEN, |
| 131 | buttons=(Gtk.STOCK_OK, 0, Gtk.STOCK_CANCEL, 1)) | 135 | buttons=(Gtk.STOCK_OK, 0, Gtk.STOCK_CANCEL, 1)) |
| 132 | chooser.set_default_response(0) | 136 | chooser.set_default_response(0) |
| 133 | chooser.set_select_multiple(True) | 137 | chooser.set_select_multiple(True) |
| 134 | 138 | ||
| @@ -151,9 +155,9 @@ class GUI(object): | |||
| 151 | chooser.destroy() | 155 | chooser.destroy() |
| 152 | 156 | ||
| 153 | def cb_popup_metadata(self, widget, row, col): | 157 | def cb_popup_metadata(self, widget, row, col): |
| 154 | ''' Popup that display on double-click | 158 | """ Popup that display on double-click |
| 155 | metadata from a file | 159 | metadata from a file |
| 156 | ''' | 160 | """ |
| 157 | metadataPopupListStore = self.builder.get_object('MetadataPopupListStore') | 161 | metadataPopupListStore = self.builder.get_object('MetadataPopupListStore') |
| 158 | metadataPopupListStore.clear() | 162 | metadataPopupListStore.clear() |
| 159 | if self.liststore[row][0].file.is_clean(): | 163 | if self.liststore[row][0].file.is_clean(): |
| @@ -171,7 +175,7 @@ class GUI(object): | |||
| 171 | popup_metadata.hide() | 175 | popup_metadata.hide() |
| 172 | 176 | ||
| 173 | def cb_about_popup(self, button): | 177 | def cb_about_popup(self, button): |
| 174 | ''' About popup ''' | 178 | """ About popup """ |
| 175 | w = Gtk.AboutDialog() | 179 | w = Gtk.AboutDialog() |
| 176 | w.set_authors(['Julien (jvoisin) Voisin', ]) | 180 | w.set_authors(['Julien (jvoisin) Voisin', ]) |
| 177 | w.set_artists(['Marine Benoît', ]) | 181 | w.set_artists(['Marine Benoît', ]) |
| @@ -187,26 +191,26 @@ class GUI(object): | |||
| 187 | w.destroy() | 191 | w.destroy() |
| 188 | 192 | ||
| 189 | def cb_supported_popup(self, w): | 193 | def cb_supported_popup(self, w): |
| 190 | ''' Show the "supported formats" popup''' | 194 | """ Show the "supported formats" popup""" |
| 191 | dialog = self.builder.get_object('SupportedWindow') | 195 | dialog = self.builder.get_object('SupportedWindow') |
| 192 | dialog.show_all() | 196 | dialog.show_all() |
| 193 | dialog.run() | 197 | dialog.run() |
| 194 | dialog.hide() | 198 | dialog.hide() |
| 195 | 199 | ||
| 196 | def cb_clear_list(self, _): | 200 | def cb_clear_list(self, _): |
| 197 | ''' Clear the file list ''' | 201 | """ Clear the file list """ |
| 198 | self.liststore.clear() | 202 | self.liststore.clear() |
| 199 | 203 | ||
| 200 | def cb_mat_check(self, button): | 204 | def cb_mat_check(self, button): |
| 201 | ''' Callback for checking files ''' | 205 | """ Callback for checking files """ |
| 202 | self.__process_files(self.__mat_check) | 206 | self.__process_files(self.__mat_check) |
| 203 | 207 | ||
| 204 | def cb_mat_clean(self, button): | 208 | def cb_mat_clean(self, button): |
| 205 | ''' Callback for cleaning files ''' | 209 | """ Callback for cleaning files """ |
| 206 | self.__process_files(self.__mat_clean) | 210 | self.__process_files(self.__mat_clean) |
| 207 | 211 | ||
| 208 | def cb_preferences_popup(self, button): | 212 | def cb_preferences_popup(self, button): |
| 209 | ''' Preferences popup ''' | 213 | """ Preferences popup """ |
| 210 | dialog = Gtk.Dialog(_('Preferences'), self.window, 0, (Gtk.STOCK_OK, 0)) | 214 | dialog = Gtk.Dialog(_('Preferences'), self.window, 0, (Gtk.STOCK_OK, 0)) |
| 211 | dialog.connect('delete-event', self.cb_hide_widget) | 215 | dialog.connect('delete-event', self.cb_hide_widget) |
| 212 | dialog.set_resizable(False) | 216 | dialog.set_resizable(False) |
| @@ -242,15 +246,15 @@ non-anonymised) file to output archive')) | |||
| 242 | dialog.hide() | 246 | dialog.hide() |
| 243 | 247 | ||
| 244 | def cb_drag_data_received(self, widget, context, x, y, selection, target_type, timestamp): | 248 | def cb_drag_data_received(self, widget, context, x, y, selection, target_type, timestamp): |
| 245 | ''' This function is called when something is | 249 | """ This function is called when something is |
| 246 | drag'n'droped into mat. | 250 | drag'n'droped into mat. |
| 247 | It basically add files. | 251 | It basically add files. |
| 248 | ''' | 252 | """ |
| 249 | 253 | ||
| 250 | def clean_path(url): | 254 | def clean_path(url): |
| 251 | ''' Since the dragged urls are ugly, | 255 | """ Since the dragged urls are ugly, |
| 252 | we need to process them | 256 | we need to process them |
| 253 | ''' | 257 | """ |
| 254 | url = urllib2.unquote(url) # unquote url | 258 | url = urllib2.unquote(url) # unquote url |
| 255 | url = url.decode('utf-8') # decode in utf-8 | 259 | url = url.decode('utf-8') # decode in utf-8 |
| 256 | if url.startswith('file:\\\\\\'): # windows | 260 | if url.startswith('file:\\\\\\'): # windows |
| @@ -265,7 +269,7 @@ non-anonymised) file to output archive')) | |||
| 265 | GLib.idle_add(self.populate(cleaned_urls).next) # asynchronous processing | 269 | GLib.idle_add(self.populate(cleaned_urls).next) # asynchronous processing |
| 266 | 270 | ||
| 267 | def __add_file_to_treeview(self, filename): | 271 | def __add_file_to_treeview(self, filename): |
| 268 | ''' Add a file to the list if its format is supported ''' | 272 | """ Add a file to the list if its format is supported """ |
| 269 | cf = CFile(filename, add2archive=self.add2archive, low_pdf_quality=self.pdf_quality) | 273 | cf = CFile(filename, add2archive=self.add2archive, low_pdf_quality=self.pdf_quality) |
| 270 | if cf.file and cf.file.is_writable: | 274 | if cf.file and cf.file.is_writable: |
| 271 | self.liststore.append([cf, cf.file.basename, _('Unknown')]) | 275 | self.liststore.append([cf, cf.file.basename, _('Unknown')]) |
| @@ -273,7 +277,7 @@ non-anonymised) file to output archive')) | |||
| 273 | return True | 277 | return True |
| 274 | 278 | ||
| 275 | def __process_files(self, func): | 279 | def __process_files(self, func): |
| 276 | ''' Launch the function "func" in a asynchronous way ''' | 280 | """ Launch the function "func" in a asynchronous way """ |
| 277 | iterator = self.treeview.get_selection().get_selected_rows()[1] | 281 | iterator = self.treeview.get_selection().get_selected_rows()[1] |
| 278 | if not iterator: # if nothing is selected : select everything | 282 | if not iterator: # if nothing is selected : select everything |
| 279 | iterator = range(len(self.liststore)) | 283 | iterator = range(len(self.liststore)) |
| @@ -281,14 +285,14 @@ non-anonymised) file to output archive')) | |||
| 281 | GLib.idle_add(task.next) | 285 | GLib.idle_add(task.next) |
| 282 | 286 | ||
| 283 | def __invert(self, button, name): | 287 | def __invert(self, button, name): |
| 284 | ''' Invert a preference state ''' | 288 | """ Invert a preference state """ |
| 285 | if name == 'pdf_quality': | 289 | if name == 'pdf_quality': |
| 286 | self.pdf_quality = not self.pdf_quality | 290 | self.pdf_quality = not self.pdf_quality |
| 287 | elif name == 'add2archive': | 291 | elif name == 'add2archive': |
| 288 | self.add2archive = not self.add2archive | 292 | self.add2archive = not self.add2archive |
| 289 | 293 | ||
| 290 | def populate(self, filenames): | 294 | def populate(self, filenames): |
| 291 | ''' Append selected files by add_file to the self.liststore ''' | 295 | """ Append selected files by add_file to the self.liststore """ |
| 292 | not_supported = [] | 296 | not_supported = [] |
| 293 | for filename in filenames: # filenames : all selected files/folders | 297 | for filename in filenames: # filenames : all selected files/folders |
| 294 | if os.path.isdir(filename): # if "filename" is a directory | 298 | if os.path.isdir(filename): # if "filename" is a directory |
| @@ -308,11 +312,11 @@ non-anonymised) file to output archive')) | |||
| 308 | yield False | 312 | yield False |
| 309 | 313 | ||
| 310 | def __popup_non_supported(self, filelist): | 314 | def __popup_non_supported(self, filelist): |
| 311 | ''' Popup that warn the user about the unsupported files | 315 | """ Popup that warn the user about the unsupported files |
| 312 | that he want to process | 316 | that he want to process |
| 313 | ''' | 317 | """ |
| 314 | dialog = Gtk.Dialog(title=_('Not-supported'), parent=self.window, | 318 | dialog = Gtk.Dialog(title=_('Not-supported'), parent=self.window, |
| 315 | flags=Gtk.DialogFlags.MODAL, buttons=(Gtk.STOCK_OK, 0)) | 319 | flags=Gtk.DialogFlags.MODAL, buttons=(Gtk.STOCK_OK, 0)) |
| 316 | dialog.set_size_request(220, 180) | 320 | dialog.set_size_request(220, 180) |
| 317 | vbox = Gtk.VBox(spacing=5) | 321 | vbox = Gtk.VBox(spacing=5) |
| 318 | sc = Gtk.ScrolledWindow() | 322 | sc = Gtk.ScrolledWindow() |
| @@ -345,12 +349,12 @@ non-anonymised) file to output archive')) | |||
| 345 | dialog.destroy() | 349 | dialog.destroy() |
| 346 | 350 | ||
| 347 | def __popup_archive(self, file_name, files_list): | 351 | def __popup_archive(self, file_name, files_list): |
| 348 | ''' Popup that shows the user what files | 352 | """ Popup that shows the user what files |
| 349 | are not going to be include into to outputed | 353 | are not going to be include into to outputed |
| 350 | archive | 354 | archive |
| 351 | ''' | 355 | """ |
| 352 | dialog = Gtk.Dialog(title=_('Non-supported files in archive'), parent=self.window, | 356 | dialog = Gtk.Dialog(title=_('Non-supported files in archive'), parent=self.window, |
| 353 | flags=Gtk.DialogFlags.MODAL, buttons=(_('Clean'), 0)) | 357 | flags=Gtk.DialogFlags.MODAL, buttons=(_('Clean'), 0)) |
| 354 | dialog.set_size_request(220, 180) | 358 | dialog.set_size_request(220, 180) |
| 355 | vbox = Gtk.VBox(spacing=5) | 359 | vbox = Gtk.VBox(spacing=5) |
| 356 | sc = Gtk.ScrolledWindow() | 360 | sc = Gtk.ScrolledWindow() |
| @@ -360,7 +364,7 @@ non-anonymised) file to output archive')) | |||
| 360 | dialog.get_content_area().pack_start(sc, True, True, 0) | 364 | dialog.get_content_area().pack_start(sc, True, True, 0) |
| 361 | store = Gtk.ListStore(bool, str) | 365 | store = Gtk.ListStore(bool, str) |
| 362 | for i in files_list: # store.extend is not supported, wtf?! | 366 | for i in files_list: # store.extend is not supported, wtf?! |
| 363 | store.append([0,os.path.basename(i)]) | 367 | store.append([0, os.path.basename(i)]) |
| 364 | 368 | ||
| 365 | treeview = Gtk.TreeView(store) | 369 | treeview = Gtk.TreeView(store) |
| 366 | column_toggle = Gtk.TreeViewColumn(_('Include')) | 370 | column_toggle = Gtk.TreeViewColumn(_('Include')) |
| @@ -375,15 +379,17 @@ non-anonymised) file to output archive')) | |||
| 375 | cellrenderer_toggle = Gtk.CellRendererToggle() | 379 | cellrenderer_toggle = Gtk.CellRendererToggle() |
| 376 | column_toggle.pack_start(cellrenderer_toggle, True) | 380 | column_toggle.pack_start(cellrenderer_toggle, True) |
| 377 | column_toggle.add_attribute(cellrenderer_toggle, 'active', 0) | 381 | column_toggle.add_attribute(cellrenderer_toggle, 'active', 0) |
| 382 | |||
| 378 | def cell_toggled(widget, path, model): | 383 | def cell_toggled(widget, path, model): |
| 379 | model[path][0] = not model[path][0] | 384 | model[path][0] = not model[path][0] |
| 385 | |||
| 380 | cellrenderer_toggle.connect('toggled', cell_toggled, store) | 386 | cellrenderer_toggle.connect('toggled', cell_toggled, store) |
| 381 | 387 | ||
| 382 | vbox.pack_start(Gtk.Label(_('MAT is not able to clean the' | 388 | vbox.pack_start(Gtk.Label(_('MAT is not able to clean the' |
| 383 | ' following files, found in the %s archive') % file_name), False, False, 0) | 389 | ' following files, found in the %s archive') % file_name), False, False, 0) |
| 384 | label = Gtk.Label() | 390 | label = Gtk.Label() |
| 385 | label.set_markup('Select the files you want to <b>include</b>' | 391 | label.set_markup('Select the files you want to <b>include</b>' |
| 386 | ' in the cleaned up archive anyway.') | 392 | ' in the cleaned up archive anyway.') |
| 387 | vbox.pack_start(label, False, False, 0) | 393 | vbox.pack_start(label, False, False, 0) |
| 388 | vbox.pack_start(treeview, True, True, 0) | 394 | vbox.pack_start(treeview, True, True, 0) |
| 389 | 395 | ||
| @@ -393,7 +399,7 @@ non-anonymised) file to output archive')) | |||
| 393 | return [i[1] for i in store if i[0]] | 399 | return [i[1] for i in store if i[0]] |
| 394 | 400 | ||
| 395 | def __mat_check(self, iterator): | 401 | def __mat_check(self, iterator): |
| 396 | ''' Check elements in iterator are clean ''' | 402 | """ Check elements in iterator are clean """ |
| 397 | for line in iterator: # for each file in selection | 403 | for line in iterator: # for each file in selection |
| 398 | msg = _('Checking %s') % self.liststore[line][1].decode('utf-8', 'replace') | 404 | msg = _('Checking %s') % self.liststore[line][1].decode('utf-8', 'replace') |
| 399 | logging.info(msg) | 405 | logging.info(msg) |
| @@ -408,7 +414,7 @@ non-anonymised) file to output archive')) | |||
| 408 | yield False | 414 | yield False |
| 409 | 415 | ||
| 410 | def __mat_clean(self, iterator): | 416 | def __mat_clean(self, iterator): |
| 411 | ''' Clean elements in iterator ''' | 417 | """ Clean elements in iterator """ |
| 412 | for line in iterator: # for each file in selection | 418 | for line in iterator: # for each file in selection |
| 413 | msg = _('Cleaning %s') % self.liststore[line][1].decode('utf-8', 'replace') | 419 | msg = _('Cleaning %s') % self.liststore[line][1].decode('utf-8', 'replace') |
| 414 | logging.info(msg) | 420 | logging.info(msg) |
| @@ -430,6 +436,7 @@ non-anonymised) file to output archive')) | |||
| 430 | self.statusbar.push(0, _('Ready')) | 436 | self.statusbar.push(0, _('Ready')) |
| 431 | yield False | 437 | yield False |
| 432 | 438 | ||
| 439 | |||
| 433 | if __name__ == '__main__': | 440 | if __name__ == '__main__': |
| 434 | gettext.install('MAT', unicode=True) | 441 | gettext.install('MAT', unicode=True) |
| 435 | 442 | ||
