diff options
| -rw-r--r-- | gui.py | 148 |
1 files changed, 142 insertions, 6 deletions
| @@ -19,14 +19,13 @@ __author__ = 'jvoisin' | |||
| 19 | logging.basicConfig(level=mat.LOGGING_LEVEL) | 19 | logging.basicConfig(level=mat.LOGGING_LEVEL) |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | class CFile(gobject.GObject): | 22 | class CFile(object): |
| 23 | ''' | 23 | ''' |
| 24 | Contain the class-file of the file "path" | 24 | Contain the class-file of the file "path" |
| 25 | This class exist just to be "around" my parser.Generic_parser class, | 25 | This class exist just to be "around" my parser.Generic_parser class, |
| 26 | since gtk.ListStore does not accept it. | 26 | since gtk.ListStore does not accept it. |
| 27 | ''' | 27 | ''' |
| 28 | def __init__(self, path, backup, add2archive): | 28 | def __init__(self, path, backup, add2archive): |
| 29 | gobject.GObject.__init__(self) | ||
| 30 | try: | 29 | try: |
| 31 | self.file = mat.create_class_file(path, backup, add2archive) | 30 | self.file = mat.create_class_file(path, backup, add2archive) |
| 32 | except: | 31 | except: |
| @@ -60,7 +59,7 @@ class ListStoreApp: | |||
| 60 | vbox.pack_start(content, True, True, 0) | 59 | vbox.pack_start(content, True, True, 0) |
| 61 | 60 | ||
| 62 | # parser.class - name - type - cleaned | 61 | # parser.class - name - type - cleaned |
| 63 | self.liststore = gtk.ListStore(CFile, str, str, str) | 62 | self.liststore = gtk.ListStore(object, str, str, str) |
| 64 | 63 | ||
| 65 | treeview = gtk.TreeView(model=self.liststore) | 64 | treeview = gtk.TreeView(model=self.liststore) |
| 66 | treeview.set_search_column(1) # name column is searchable | 65 | treeview.set_search_column(1) # name column is searchable |
| @@ -99,7 +98,7 @@ class ListStoreApp: | |||
| 99 | toolbutton = gtk.ToolButton(gtk.STOCK_PRINT_WARNING) | 98 | toolbutton = gtk.ToolButton(gtk.STOCK_PRINT_WARNING) |
| 100 | toolbutton.set_label('Brute Clean') | 99 | toolbutton.set_label('Brute Clean') |
| 101 | toolbutton.set_tooltip_text('Clean selected files with possible data \ | 100 | toolbutton.set_tooltip_text('Clean selected files with possible data \ |
| 102 | loss') | 101 | loss') |
| 103 | toolbar.add(toolbutton) | 102 | toolbar.add(toolbutton) |
| 104 | 103 | ||
| 105 | toolbutton = gtk.ToolButton(gtk.STOCK_FIND) | 104 | toolbutton = gtk.ToolButton(gtk.STOCK_FIND) |
| @@ -126,6 +125,9 @@ class ListStoreApp: | |||
| 126 | filename_column = gtk.CellRendererText() | 125 | filename_column = gtk.CellRendererText() |
| 127 | column = gtk.TreeViewColumn(j, filename_column, text=i + 1) | 126 | column = gtk.TreeViewColumn(j, filename_column, text=i + 1) |
| 128 | column.set_sort_column_id(i + 1) | 127 | column.set_sort_column_id(i + 1) |
| 128 | if i is 0: | ||
| 129 | tips = TreeViewTooltips(column) | ||
| 130 | tips.add_view(treeview) | ||
| 129 | treeview.append_column(column) | 131 | treeview.append_column(column) |
| 130 | 132 | ||
| 131 | def create_menu_item(self, name, func, menu, pix): | 133 | def create_menu_item(self, name, func, menu, pix): |
| @@ -226,8 +228,8 @@ class ListStoreApp: | |||
| 226 | ''' | 228 | ''' |
| 227 | cf = CFile(item, self.backup, self.add2archive) | 229 | cf = CFile(item, self.backup, self.add2archive) |
| 228 | if cf.file is not None: | 230 | if cf.file is not None: |
| 229 | self.liststore.append([cf, cf.file.filename, | 231 | self.liststore.append([cf, cf.file.basename, cf.file.mime, |
| 230 | cf.file.mime, 'unknow']) | 232 | 'unknow']) |
| 231 | 233 | ||
| 232 | def about(self, _): | 234 | def about(self, _): |
| 233 | ''' | 235 | ''' |
| @@ -404,6 +406,140 @@ non-anonymised) file to outputed archive') | |||
| 404 | self.liststore[i][3] = 'clean' | 406 | self.liststore[i][3] = 'clean' |
| 405 | 407 | ||
| 406 | 408 | ||
| 409 | class TreeViewTooltips(object): | ||
| 410 | ''' | ||
| 411 | A dirty hack losely based on treeviewtooltip from Daniel J. Popowich | ||
| 412 | (dpopowich AT astro dot umass dot edu), to display differents tooltips | ||
| 413 | for each cell of the first row of the GUI. | ||
| 414 | ''' | ||
| 415 | # Copyright (c) 2006, Daniel J. Popowich | ||
| 416 | # | ||
| 417 | # Permission is hereby granted, free of charge, to any person | ||
| 418 | # obtaining a copy of this software and associated documentation files | ||
| 419 | # (the "Software"), to deal in the Software without restriction, | ||
| 420 | # including without limitation the rights to use, copy, modify, merge, | ||
| 421 | # publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 422 | # and to permit persons to whom the Software is furnished to do so, | ||
| 423 | # subject to the following conditions: | ||
| 424 | # | ||
| 425 | # The above copyright notice and this permission notice shall be | ||
| 426 | # included in all copies or substantial portions of the Software. | ||
| 427 | def __init__(self, namecol): | ||
| 428 | ''' | ||
| 429 | Initialize the tooltip. | ||
| 430 | window: the popup window that holds the tooltip text, an | ||
| 431 | instance of gtk.Window. | ||
| 432 | label: a gtk.Label that is packed into the window. The | ||
| 433 | tooltip text is set in the label with the | ||
| 434 | set_label() method, so the text can be plain or | ||
| 435 | markup text. | ||
| 436 | ''' | ||
| 437 | # create the window | ||
| 438 | self.window = window = gtk.Window(gtk.WINDOW_POPUP) | ||
| 439 | window.set_name('gtk-tooltips') | ||
| 440 | window.set_resizable(False) | ||
| 441 | window.set_border_width(4) | ||
| 442 | window.set_app_paintable(True) | ||
| 443 | window.connect("expose-event", self.__on_expose_event) | ||
| 444 | |||
| 445 | # create the label | ||
| 446 | self.label = label = gtk.Label() | ||
| 447 | label.set_line_wrap(True) | ||
| 448 | label.set_alignment(0.5, 0.5) | ||
| 449 | label.show() | ||
| 450 | window.add(label) | ||
| 451 | |||
| 452 | self.namecol = namecol | ||
| 453 | self.__save = None # saves the current cell | ||
| 454 | self.__next = None # the timer id for the next tooltip to be shown | ||
| 455 | self.__shown = False # flag on whether the tooltip window is shown | ||
| 456 | |||
| 457 | def __show(self, tooltip, x, y): | ||
| 458 | ''' | ||
| 459 | show the tooltip | ||
| 460 | ''' | ||
| 461 | self.label.set_label(tooltip) # set label | ||
| 462 | self.window.move(x, y) # move the window | ||
| 463 | self.window.show() # show it | ||
| 464 | self.__shown = True | ||
| 465 | |||
| 466 | def __hide(self): | ||
| 467 | ''' | ||
| 468 | hide the tooltip | ||
| 469 | ''' | ||
| 470 | self.__queue_next() | ||
| 471 | self.window.hide() | ||
| 472 | self.__shown = False | ||
| 473 | |||
| 474 | def __motion_handler(self, view, event): | ||
| 475 | ''' | ||
| 476 | as the pointer moves across the view, show a tooltip | ||
| 477 | ''' | ||
| 478 | path = view.get_path_at_pos(int(event.x), int(event.y)) | ||
| 479 | if path: | ||
| 480 | path, col, x, y = path | ||
| 481 | tooltip = self.get_tooltip(view, col, path) | ||
| 482 | if tooltip: | ||
| 483 | tooltip = str(tooltip).strip() | ||
| 484 | self.__queue_next((path, col), tooltip, int(event.x_root), | ||
| 485 | int(event.y_root)) | ||
| 486 | return | ||
| 487 | self.__hide() | ||
| 488 | |||
| 489 | def __queue_next(self, *args): | ||
| 490 | ''' | ||
| 491 | queue next request to show a tooltip | ||
| 492 | if args is non-empty it means a request was made to show a | ||
| 493 | tooltip. if empty, no request is being made, but any | ||
| 494 | pending requests should be cancelled anyway | ||
| 495 | ''' | ||
| 496 | cell = None | ||
| 497 | |||
| 498 | if args: # if called with args, break them out | ||
| 499 | cell, tooltip, x, y = args | ||
| 500 | |||
| 501 | # if it's the same cell as previously shown, just return | ||
| 502 | if self.__save == cell: | ||
| 503 | return | ||
| 504 | |||
| 505 | if self.__next: # if we have something queued up, cancel it | ||
| 506 | gobject.source_remove(self.__next) | ||
| 507 | self.__next = None | ||
| 508 | |||
| 509 | if cell: # if there was a request | ||
| 510 | if self.__shown: # if tooltip is already shown show the new one | ||
| 511 | self.__show(tooltip, x, y) | ||
| 512 | else: # else queue it up in 1/2 second | ||
| 513 | self.__next = gobject.timeout_add(500, self.__show, | ||
| 514 | tooltip, x, y) | ||
| 515 | self.__save = cell # save this cell | ||
| 516 | |||
| 517 | def __on_expose_event(self, window, event): | ||
| 518 | ''' | ||
| 519 | this magic is required so the window appears with a 1-pixel | ||
| 520 | black border (default gtk Style). | ||
| 521 | ''' | ||
| 522 | w, h = window.size_request() | ||
| 523 | window.style.paint_flat_box(window.window, gtk.STATE_NORMAL, | ||
| 524 | gtk.SHADOW_OUT, None, window, 'tooltip', 0, 0, w, h) | ||
| 525 | |||
| 526 | def add_view(self, view): | ||
| 527 | ''' | ||
| 528 | add a gtk.TreeView to the tooltip | ||
| 529 | ''' | ||
| 530 | view.connect("motion-notify-event", self.__motion_handler) | ||
| 531 | view.connect("leave-notify-event", lambda i, j: self.__hide()) | ||
| 532 | |||
| 533 | def get_tooltip(self, view, column, path): | ||
| 534 | ''' | ||
| 535 | See the module doc string for a description of this method | ||
| 536 | ''' | ||
| 537 | if column is self.namecol: | ||
| 538 | model = view.get_model() | ||
| 539 | name = model[path][0] | ||
| 540 | return name.file.filename | ||
| 541 | |||
| 542 | |||
| 407 | if __name__ == '__main__': | 543 | if __name__ == '__main__': |
| 408 | ListStoreApp() | 544 | ListStoreApp() |
| 409 | gtk.main() | 545 | gtk.main() |
