diff options
Diffstat (limited to '')
-rw-r--r-- | etc/portato.cfg | 3 | ||||
-rw-r--r-- | portato/gui/gtk/TreeViewTooltips.py | 423 | ||||
-rw-r--r-- | portato/gui/gtk/glade/portato.glade | 557 | ||||
-rw-r--r-- | portato/gui/gtk/usetips.py | 76 | ||||
-rw-r--r-- | portato/gui/gtk/windows.py | 57 | ||||
-rw-r--r-- | portato/gui/gui_helper.py | 4 |
6 files changed, 842 insertions, 278 deletions
diff --git a/etc/portato.cfg b/etc/portato.cfg index 62367e2..12a3a92 100644 --- a/etc/portato.cfg +++ b/etc/portato.cfg @@ -47,6 +47,7 @@ useperversion = True # [Gtk] -; empty +; control whether usetips are shown for a package in the Queue - boolean values +showusetips = on # vim:ts=4:sw=4:ft=cfg diff --git a/portato/gui/gtk/TreeViewTooltips.py b/portato/gui/gtk/TreeViewTooltips.py new file mode 100644 index 0000000..1112d3e --- /dev/null +++ b/portato/gui/gtk/TreeViewTooltips.py @@ -0,0 +1,423 @@ +# Copyright (c) 2006, Daniel J. Popowich +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Send bug reports and contributions to: +# +# dpopowich AT astro dot umass dot edu +# + +''' +TreeViewTooltips.py + +Provides TreeViewTooltips, a class which presents tooltips for cells, +columns and rows in a gtk.TreeView. + +------------------------------------------------------------ + This file includes a demo. Just execute the file: + + python TreeViewTooltips.py +------------------------------------------------------------ + +To use, first subclass TreeViewTooltips and implement the get_tooltip() +method; see below. Then add any number of gtk.TreeVew widgets to a +TreeViewTooltips instance by calling the add_view() method. Overview +of the steps: + + # 1. subclass TreeViewTooltips + class MyTooltips(TreeViewTooltips): + + # 2. overriding get_tooltip() + def get_tooltip(...): + ... + + # 3. create an instance + mytips = MyTooltips() + + # 4. Build up your gtk.TreeView. + myview = gtk.TreeView() + ...# create columns, set the model, etc. + + # 5. Add the view to the tooltips + mytips.add_view(myview) + +How it works: the add_view() method connects the TreeView to the +"motion-notify" event with the callback set to a private method. +Whenever the mouse moves across the TreeView the callback will call +get_tooltip() with the following arguments: + + get_tooltip(view, column, path) + +where, + + view: the gtk.TreeView instance. + column: the gtk.TreeViewColumn instance that the mouse is + currently over. + path: the path to the row that the mouse is currently over. + +Based on whether or not column and path are checked for specific +values, get_tooltip can return tooltips for a cell, column, row or the +whole view: + + Column Checked Path Checked Tooltip For... + Y Y cell + Y N column + N Y row + N N view + +get_tooltip() should return None if no tooltip should be displayed. +Otherwise the return value will be coerced to a string (with the str() +builtin) and stripped; if non-empty, the result will be displayed as +the tooltip. By default, the tooltip popup window will be displayed +centered and just below the pointer and will remain shown until the +pointer leaves the cell (or column, or row, or view, depending on how +get_tooltip() is implemented). + +''' + + +import pygtk +pygtk.require('2.0') + +import gtk +import gtk.gdk +import gobject + +if gtk.gtk_version < (2, 8): + import warnings + + msg = ('''This module was developed and tested with version 2.8.18 of gtk. You are using version %d.%d.%d. Your milage may vary.''' + % gtk.gtk_version) + warnings.warn(msg) + + +# major, minor, patch +version = 1, 0, 0 + +class TreeViewTooltips: + + def __init__(self): + + ''' + Initialize the tooltip. After initialization there are two + attributes available for advanced control: + + window: the popup window that holds the tooltip text, an + instance of gtk.Window. + label: a gtk.Label that is packed into the window. The + tooltip text is set in the label with the + set_label() method, so the text can be plain or + markup text. + + Be default, the tooltip is enabled. See the enabled/disabled + methods. + ''' + + # create the window + self.window = window = gtk.Window(gtk.WINDOW_POPUP) + window.set_name('gtk-tooltips') + window.set_resizable(False) + window.set_border_width(4) + window.set_app_paintable(True) + window.connect("expose-event", self.__on_expose_event) + + + # create the label + self.label = label = gtk.Label() + label.set_line_wrap(True) + label.set_alignment(0.5, 0.5) + label.set_use_markup(True) + label.show() + window.add(label) + + # by default, the tooltip is enabled + self.__enabled = True + # saves the current cell + self.__save = None + # the timer id for the next tooltip to be shown + self.__next = None + # flag on whether the tooltip window is shown + self.__shown = False + + def enable(self): + 'Enable the tooltip' + + self.__enabled = True + + def disable(self): + 'Disable the tooltip' + + self.__enabled = False + + def __show(self, tooltip, x, y): + + '''show the tooltip popup with the text/markup given by + tooltip. + + tooltip: the text/markup for the tooltip. + x, y: the coord. (root window based) of the pointer. + ''' + + window = self.window + + # set label + self.label.set_label(tooltip) + # resize window + w, h = window.size_request() + # move the window + window.move(*self.location(x,y,w,h)) + # show it + window.show() + self.__shown = True + + def __hide(self): + 'hide the tooltip' + + self.__queue_next() + self.window.hide() + self.__shown = False + + def __leave_handler(self, view, event): + 'when the pointer leaves the view, hide the tooltip' + + self.__hide() + + def __motion_handler(self, view, event): + 'As the pointer moves across the view, show a tooltip.' + + path = view.get_path_at_pos(int(event.x), int(event.y)) + + if self.__enabled and path: + path, col, x, y = path + tooltip = self.get_tooltip(view, col, path) + if tooltip is not None: + tooltip = str(tooltip).strip() + if tooltip: + self.__queue_next((path, col), tooltip, + int(event.x_root), + int(event.y_root)) + return + + self.__hide() + + def __queue_next(self, *args): + + 'queue next request to show a tooltip' + + # if args is non-empty it means a request was made to show a + # tooltip. if empty, no request is being made, but any + # pending requests should be cancelled anyway. + + cell = None + + # if called with args, break them out + if args: + cell, tooltip, x, y = args + + # if it's the same cell as previously shown, just return + if self.__save == cell: + return + + # if we have something queued up, cancel it + if self.__next: + gobject.source_remove(self.__next) + self.__next = None + + # if there was a request... + if cell: + # if the tooltip is already shown, show the new one + # immediately + if self.__shown: + self.__show(tooltip, x, y) + # else queue it up in 1/2 second + else: + self.__next = gobject.timeout_add(500, self.__show, + tooltip, x, y) + + # save this cell + self.__save = cell + + + def __on_expose_event(self, window, event): + + # this magic is required so the window appears with a 1-pixel + # black border (default gtk Style). This code is a + # transliteration of the C implementation of gtk.Tooltips. + w, h = window.size_request() + window.style.paint_flat_box(window.window, gtk.STATE_NORMAL, + gtk.SHADOW_OUT, None, window, + 'tooltip', 0, 0, w, h) + + def location(self, x, y, w, h): + + '''Given the x,y coordinates of the pointer and the width and + height (w,h) demensions of the tooltip window, return the x, y + coordinates of the tooltip window. + + The default location is to center the window on the pointer + and 4 pixels below it. + ''' + + return x - w/2, y + 4 + + def add_view(self, view): + + 'add a gtk.TreeView to the tooltip' + + assert isinstance(view, gtk.TreeView), \ + ('This handler should only be connected to ' + 'instances of gtk.TreeView') + + view.connect("motion-notify-event", self.__motion_handler) + view.connect("leave-notify-event", self.__leave_handler) + + def get_tooltip(self, view, column, path): + 'See the module doc string for a description of this method' + + raise NotImplemented, 'Subclass must implement get_tooltip()' + + +if __name__ == '__main__': + + ############################################################ + # DEMO + ############################################################ + + # First, subclass TreeViewTooltips + + class DemoTips(TreeViewTooltips): + + def __init__(self, customer_column): + # customer_column is an instance of gtk.TreeViewColumn and + # is being used in the gtk.TreeView to show customer names. + self.cust_col = customer_column + + # call base class init + TreeViewTooltips.__init__(self) + + def get_tooltip(self, view, column, path): + + # we have a two column view: customer, phone; we'll make + # tooltips cell-based for the customer column, but generic + # column-based for the phone column. + + # customer + if column is self.cust_col: + + # By checking both column and path we have a + # cell-based tooltip. + model = view.get_model() + customer = model[path][2] + return '<big>%s %s</big>\n<i>%s</i>' % (customer.fname, + customer.lname, + customer.notes) + # phone + else: + return ('<big><u>Generic Column Tooltip</u></big>\n' + 'Unless otherwise noted, all\narea codes are 888') + + def XX_location(self, x, y, w, h): + # rename me to "location" so I override the base class + # method. This will demonstrate being able to change + # where the tooltip window popups, relative to the + # pointer. + + # this will place the tooltip above and to the right + return x + 10, y - (h + 10) + + # Here's our customer + class Customer: + + def __init__(self, fname, lname, phone, notes): + self.fname = fname + self.lname = lname + self.phone = phone + self.notes = notes + + # create a bunch of customers + customers = [] + for fname, lname, phone, notes in [ + ('Joe', 'Schmoe', '555-1212', 'Likes to Morris dance.'), + ('Jane', 'Doe', '555-2323', + 'Wonders what the hell\nMorris dancing is.'), + ('Phred', 'Phantastic', '900-555-1212', 'Dreams of Betty.'), + ('Betty', 'Boop', '555-3434', 'Dreams in b&w.'), + ('Red Sox', 'Fan', '555-4545', + "Still livin' 2004!\nEspecially after 2006.")]: + customers.append(Customer(fname, lname, phone, notes)) + + # Build our model and view + model = gtk.ListStore(str, str, object) + for c in customers: + model.append(['%s %s' % (c.fname, c.lname), c.phone, c]) + + view = gtk.TreeView(model) + view.get_selection().set_mode(gtk.SELECTION_NONE) + + # two columns, name and phone + cell = gtk.CellRendererText() + cell.set_property('xpad', 20) + namecol = gtk.TreeViewColumn('Customer Name', cell, text=0) + namecol.set_min_width(200) + view.append_column(namecol) + + cell = gtk.CellRendererText() + phonecol = gtk.TreeViewColumn('Phone', cell, text=1) + view.append_column(phonecol) + + # finally, connect the tooltip, specifying the name column as the + # column we want the tooltip to popup over. + tips = DemoTips(namecol) + tips.add_view(view) + + # We're going to demonstrate enable/disable. First we need a + # callback function to connect to the toggled signal. + def toggle(button): + if button.get_active(): + tips.disable() + else: + tips.enable() + + # create a checkbutton and connect our handler + check = gtk.CheckButton('Check to disable view tooltips') + check.connect('toggled', toggle) + + # a standard gtk.Tooltips to compare to + tt = gtk.Tooltips() + tt.set_tip(check, ('This is a standard gtk tooltip.\n' + 'Compare me to the tooltips above.')) + + # create a VBox to pack the view and checkbutton + vbox = gtk.VBox() + vbox.pack_start(view) + vbox.pack_start(check, False) + vbox.show_all() + + # pack the vbox into a simple dialog and run it + dialog = gtk.Dialog('TreeViewTooltips Demo') + close = dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_NONE) + + # add a tooltip for the close button + tt.set_tip(close, 'Click to end the demo.') + + dialog.set_default_size(400,400) + dialog.vbox.pack_start(vbox) + dialog.run() diff --git a/portato/gui/gtk/glade/portato.glade b/portato/gui/gtk/glade/portato.glade index 7307dbc..9dc48c4 100644 --- a/portato/gui/gtk/glade/portato.glade +++ b/portato/gui/gtk/glade/portato.glade @@ -90,19 +90,30 @@ <widget class="GtkMenu" id="menu2"> <property name="visible">True</property> <child> - <widget class="GtkMenuItem" id="emergeItem"> + <widget class="GtkImageMenuItem" id="emergeItem"> <property name="visible">True</property> <property name="label" translatable="yes">E_merge</property> <property name="use_underline">True</property> <signal name="activate" handler="cb_emerge_clicked"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image9"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> + <property name="stock">gtk-go-forward</property> + </widget> + </child> </widget> </child> <child> - <widget class="GtkMenuItem" id="unmergeItem"> + <widget class="GtkImageMenuItem" id="unmergeItem"> <property name="visible">True</property> <property name="label" translatable="yes">_Unmerge</property> <property name="use_underline">True</property> - <signal name="activate" handler="cb_unmerge_clicked"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image10"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> + <property name="stock">gtk-go-back</property> + </widget> + </child> </widget> </child> <child> @@ -119,19 +130,30 @@ </widget> </child> <child> - <widget class="GtkMenuItem" id="syncItem"> + <widget class="GtkImageMenuItem" id="syncItem"> <property name="visible">True</property> <property name="label" translatable="yes">_Sync</property> <property name="use_underline">True</property> - <signal name="activate" handler="cb_sync_clicked"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image11"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> + <property name="stock">gtk-refresh</property> + </widget> + </child> </widget> </child> <child> - <widget class="GtkMenuItem" id="saveFlagsItem"> + <widget class="GtkImageMenuItem" id="saveFlagsItem"> <property name="visible">True</property> <property name="label" translatable="yes">Save _Flags</property> <property name="use_underline">True</property> <signal name="activate" handler="cb_save_flags_clicked"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image12"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property> + <property name="stock">gtk-save</property> + </widget> + </child> </widget> </child> <child> @@ -147,6 +169,76 @@ <signal name="activate" handler="cb_kill_clicked"/> <accelerator key="K" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image13"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="stock">gtk-stop</property> + <property name="icon_size">1</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="hiddenQueueMenu"> + <property name="sensitive">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">_Queue</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="queuePopup"> + <property name="visible">True</property> + <child> + <widget class="GtkMenuItem" id="oneShotItem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Oneshot</property> + <signal name="activate" handler="cb_oneshot_clicked"/> + <accelerator key="1" modifiers="GDK_CONTROL_MASK" signal="activate"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="hiddenConsoleMenu"> + <property name="sensitive">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">_Console</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="consolePopup"> + <property name="visible">True</property> + <child> + <widget class="GtkImageMenuItem" id="copyItem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Copy</property> + <property name="use_underline">True</property> + <signal name="activate" handler="cb_copy_clicked"/> + <accelerator key="C" modifiers="GDK_CONTROL_MASK" signal="activate"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image8"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="stock">gtk-copy</property> + <property name="icon_size">1</property> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="killItemPopup"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Kill Emerge</property> + <property name="use_underline">True</property> + <signal name="activate" handler="cb_kill_clicked"/> + <accelerator key="K" modifiers="GDK_CONTROL_MASK" signal="activate"/> + <child internal-child="image"> <widget class="GtkImage" id="image25"> <property name="visible">True</property> <property name="xalign">0</property> @@ -295,50 +387,74 @@ <property name="n_rows">4</property> <property name="n_columns">2</property> <child> - <widget class="GtkHBox" id="checkHB"> + <widget class="GtkScrolledWindow" id="useListScroll"> <property name="visible">True</property> - <property name="spacing">1</property> - <property name="homogeneous">True</property> - <child> - <widget class="GtkCheckButton" id="installedCheck"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Installed</property> - <property name="draw_indicator">True</property> - <signal name="button_press_event" handler="cb_button_pressed"/> - </widget> - <packing> - <property name="fill">False</property> - </packing> - </child> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <child> - <widget class="GtkCheckButton" id="maskedCheck"> + <widget class="GtkTreeView" id="useList"> <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Masked</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="cb_masked_toggled"/> </widget> - <packing> - <property name="fill">False</property> - <property name="position">1</property> - </packing> </child> + </widget> + <packing> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_padding">5</property> + <property name="y_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="comboVB"> + <property name="visible">True</property> <child> - <widget class="GtkCheckButton" id="testingCheck"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Testing</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="cb_testing_toggled"/> - </widget> - <packing> - <property name="fill">False</property> - <property name="position">2</property> - </packing> + <placeholder/> </child> </widget> <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> + <property name="x_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="descLabel"> + <property name="visible">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">True</property> + </widget> + <packing> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + <property name="y_padding">10</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="missingLabel"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes"><span foreground='red'><b>MISSING KEYWORD</b></span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="notInSysLabel"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes"><b>Installed, but not in portage anymore</b></property> + <property name="use_markup">True</property> + </widget> + <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> <property name="top_attach">1</property> @@ -390,79 +506,55 @@ </packing> </child> <child> - <widget class="GtkLabel" id="notInSysLabel"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes"><b>Installed, but not in portage anymore</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="missingLabel"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes"><span foreground='red'><b>MISSING KEYWORD</b></span></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="descLabel"> - <property name="visible">True</property> - <property name="justify">GTK_JUSTIFY_CENTER</property> - <property name="wrap">True</property> - </widget> - <packing> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - <property name="y_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkVBox" id="comboVB"> + <widget class="GtkHBox" id="checkHB"> <property name="visible">True</property> + <property name="spacing">1</property> + <property name="homogeneous">True</property> <child> - <placeholder/> + <widget class="GtkCheckButton" id="installedCheck"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Installed</property> + <property name="draw_indicator">True</property> + <signal name="button_press_event" handler="cb_button_pressed"/> + </widget> + <packing> + <property name="fill">False</property> + </packing> </child> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options">GTK_FILL</property> - <property name="x_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkScrolledWindow" id="useListScroll"> - <property name="visible">True</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <child> - <widget class="GtkTreeView" id="useList"> + <widget class="GtkCheckButton" id="maskedCheck"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Masked</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="cb_masked_toggled"/> + </widget> + <packing> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkCheckButton" id="testingCheck"> <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Testing</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="cb_testing_toggled"/> </widget> + <packing> + <property name="fill">False</property> + <property name="position">2</property> + </packing> </child> </widget> <packing> + <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> </packing> </child> </widget> @@ -701,10 +793,25 @@ <property name="visible">True</property> <property name="left_padding">12</property> <child> - <widget class="GtkCheckButton" id="debugCheck"> + <widget class="GtkVBox" id="generalVB"> <property name="visible">True</property> - <property name="label" translatable="yes">Debug</property> - <property name="draw_indicator">True</property> + <child> + <widget class="GtkCheckButton" id="debugCheck"> + <property name="visible">True</property> + <property name="label" translatable="yes">Debug</property> + <property name="draw_indicator">True</property> + </widget> + </child> + <child> + <widget class="GtkCheckButton" id="useTipsCheck"> + <property name="visible">True</property> + <property name="label" translatable="yes">Turn Use-Tips on</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> </widget> </child> </widget> @@ -846,186 +953,186 @@ <placeholder/> </child> <child> - <widget class="GtkEntry" id="useFileEdit"> + <widget class="GtkLabel" id="maskLabel"> <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Masking Keywords</i></u></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="y_padding">5</property> </packing> </child> <child> - <widget class="GtkLabel" id="useEditLabel"> + <widget class="GtkLabel" id="testLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.use is a directory: </property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Testing Keywords</i></u></property> + <property name="use_markup">True</property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_padding">5</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="usePerVersionCheck"> + <widget class="GtkLabel" id="useLabel"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.use</property> - <property name="draw_indicator">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Use-Flags</i></u></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_padding">6</property> + </packing> + </child> + <child> + <widget class="GtkEventBox" id="hintEB"> + <property name="visible">True</property> + <child> + <widget class="GtkFrame" id="hintFrame"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <child> + <widget class="GtkLabel" id="hintLabel"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes"><u>You may use the following placeholders:</u> + + <i>$(cat)</i>: category + <i>$(pkg)</i>: package name + <i>$(cat-1)/$(cat-2)</i>: first/second part of the category</property> + <property name="use_markup">True</property> + </widget> + </child> + <child> + <placeholder/> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + </child> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="testPerVersionCheck"> + <widget class="GtkCheckButton" id="maskPerVersionCheck"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.keywords</property> + <property name="label" translatable="yes">Add only exact version to package.mask/package.unmask</property> <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> </packing> </child> <child> - <widget class="GtkLabel" id="testEditLabel"> + <widget class="GtkLabel" id="maskEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.keywords is a directory: </property> + <property name="label" translatable="yes">File name to use, if package.mask/package.unmask is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> </packing> </child> <child> - <widget class="GtkEntry" id="testFileEdit"> + <widget class="GtkEntry" id="maskFileEdit"> <property name="visible">True</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> </packing> </child> <child> - <widget class="GtkEntry" id="maskFileEdit"> + <widget class="GtkEntry" id="testFileEdit"> <property name="visible">True</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> </packing> </child> <child> - <widget class="GtkLabel" id="maskEditLabel"> + <widget class="GtkLabel" id="testEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.mask/package.unmask is a directory: </property> + <property name="label" translatable="yes">File name to use, if package.keywords is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="maskPerVersionCheck"> + <widget class="GtkCheckButton" id="testPerVersionCheck"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.mask/package.unmask</property> + <property name="label" translatable="yes">Add only exact version to package.keywords</property> <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">8</property> - <property name="bottom_attach">9</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> </packing> </child> <child> - <widget class="GtkEventBox" id="hintEB"> + <widget class="GtkCheckButton" id="usePerVersionCheck"> <property name="visible">True</property> - <child> - <widget class="GtkFrame" id="hintFrame"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">GTK_SHADOW_OUT</property> - <child> - <widget class="GtkLabel" id="hintLabel"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><u>You may use the following placeholders:</u> - - <i>$(cat)</i>: category - <i>$(pkg)</i>: package name - <i>$(cat-1)/$(cat-2)</i>: first/second part of the category</property> - <property name="use_markup">True</property> - </widget> - </child> - <child> - <placeholder/> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - </child> + <property name="label" translatable="yes">Add only exact version to package.use</property> + <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> </packing> </child> <child> - <widget class="GtkLabel" id="useLabel"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Use-Flags</i></u></property> - <property name="use_markup">True</property> - <property name="single_line_mode">True</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_padding">6</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="testLabel"> + <widget class="GtkLabel" id="useEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Testing Keywords</i></u></property> - <property name="use_markup">True</property> + <property name="label" translatable="yes">File name to use, if package.use is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_padding">5</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> </packing> </child> <child> - <widget class="GtkLabel" id="maskLabel"> + <widget class="GtkEntry" id="useFileEdit"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Masking Keywords</i></u></property> - <property name="use_markup">True</property> - <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> - <property name="y_padding">5</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> </packing> </child> </widget> @@ -1079,54 +1186,4 @@ </widget> </child> </widget> - <widget class="GtkMenu" id="queuePopup"> - <property name="visible">True</property> - <child> - <widget class="GtkMenuItem" id="oneShotItem"> - <property name="visible">True</property> - <property name="label" translatable="yes">oneshot</property> - <signal name="activate" handler="cb_oneshot_clicked"/> - <accelerator key="1" modifiers="GDK_CONTROL_MASK" signal="activate"/> - </widget> - </child> - </widget> - <widget class="GtkMenu" id="consolePopup"> - <property name="visible">True</property> - <child> - <widget class="GtkImageMenuItem" id="copyItem"> - <property name="visible">True</property> - <property name="label" translatable="yes">Copy</property> - <property name="use_underline">True</property> - <signal name="activate" handler="cb_copy_clicked"/> - <accelerator key="C" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image52"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="stock">gtk-copy</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="killItem"> - <property name="visible">True</property> - <property name="label" translatable="yes">Kill Process</property> - <property name="use_underline">True</property> - <signal name="activate" handler="cb_kill_clicked"/> - <accelerator key="K" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image51"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="stock">gtk-stop</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - </widget> </glade-interface> diff --git a/portato/gui/gtk/usetips.py b/portato/gui/gtk/usetips.py new file mode 100644 index 0000000..6611e09 --- /dev/null +++ b/portato/gui/gtk/usetips.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# +# File: portato/gui/gtk/usetips.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2007 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann <necoro@necoro.net> + +from portato.backend import Package +from portato.backend.flags import invert_use_flag + +from TreeViewTooltips import TreeViewTooltips + +class UseTips (TreeViewTooltips): + """This class handles the display of the so called use-tips, + i.e. the tooltips showing the actual use-flags.""" + + def __init__ (self, colno, cfg = None): + """Constructor. + + @param colno: the number of the column to check + @type colno: int + @param cfg: a config to look in, whether we should show the tips or not + @type cfg: Config""" + + self.colno = colno + self.cfg = cfg + + TreeViewTooltips.__init__(self) + + def get_tooltip(self, view, column, path): + + # check config + if self.cfg is not None: + if not self.cfg.get_boolean("useTips_opt", section = self.cfg.const["gtk_sec"]): + return None + + store = view.get_model() + it = store.get_iter(path) + + if store.iter_parent(it) is not None: + return self.__get_flags(store.get_value(it, self.colno)) + else: # top items - ignore them + return None + + def __get_flags(self, cpv): + pkg = Package(cpv) + enabled = [] + disabled = [] + + pkg_flags = pkg.get_all_use_flags() + if len(pkg_flags) == 0: # no flags - stop here + return None + + pkg_flags.sort() + for use in pkg_flags: + if pkg.is_use_flag_enabled(use): + enabled.append(use) + else: + disabled.append(use) + + string = "" + + if len(enabled) > 0: + string = "<b>+"+"\n+".join(enabled)+"</b>" + if len(disabled) > 0: + string = string + "\n" + + if len(disabled) > 0: + string = string+"<i>- " + "\n- ".join(disabled) + "</i>" + + return string diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py index fb663e0..64ff8a1 100644 --- a/portato/gui/gtk/windows.py +++ b/portato/gui/gtk/windows.py @@ -28,12 +28,14 @@ from portato.backend.exceptions import * from portato.gui.gui_helper import Database, Config, EmergeQueue from dialogs import * from wrapper import GtkTree, GtkConsole +from usetips import UseTips # for the terminal import vte # other from portage_util import unique_array +import types GLADE_FILE = DATA_DIR+"portato.glade" @@ -171,6 +173,7 @@ class PreferenceWindow (AbstractDialog): "newUseCheck" : "newuse_opt", "maskPerVersionCheck" : "maskPerVersion_opt", "usePerVersionCheck" : "usePerVersion_opt", + "useTipsCheck" : ("useTips_opt", "gtk_sec"), "testPerVersionCheck" : "testingPerVersion_opt" } @@ -201,8 +204,13 @@ class PreferenceWindow (AbstractDialog): hintEB.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#f3f785")) for box in self.checkboxes: - self.tree.get_widget(box).\ - set_active(self.cfg.get_boolean(self.checkboxes[box])) + val = self.checkboxes[box] + if type(val) == types.TupleType: + self.tree.get_widget(box).\ + set_active(self.cfg.get_boolean(val[0], section = self.cfg.const[val[1]])) + else: + self.tree.get_widget(box).\ + set_active(self.cfg.get_boolean(val)) for edit in self.edits: self.tree.get_widget(edit).\ @@ -214,7 +222,11 @@ class PreferenceWindow (AbstractDialog): """Sets all options in the Config-instance.""" for box in self.checkboxes: - self.cfg.set_boolean(self.checkboxes[box], self.tree.get_widget(box).get_active()) + val = self.checkboxes[box] + if type(val) == types.TupleType: + self.cfg.set_boolean(val[0], self.tree.get_widget(box).get_active(), section = self.cfg.const[val[1]]) + else: + self.cfg.set_boolean(val, self.tree.get_widget(box).get_active()) for edit in self.edits: self.cfg.set(self.edits[edit],self.tree.get_widget(edit).get_text()) @@ -250,12 +262,16 @@ class PackageTable: # the table self.table = self.tree.get_widget("PackageTable") + # the combo vb + self.comboVB = self.tree.get_widget("comboVB") + # chechboxes self.installedCheck = self.tree.get_widget("installedCheck") self.maskedCheck = self.tree.get_widget("maskedCheck") self.testingCheck = self.tree.get_widget("testingCheck") # labels + self.descLabel = self.tree.get_widget("descLabel") self.notInSysLabel = self.tree.get_widget("notInSysLabel") self.missingLabel = self.tree.get_widget("missingLabel") @@ -295,11 +311,11 @@ class PackageTable: # version-combo-box self.vCombo = self.build_vers_combo() if not self.doEmerge: self.vCombo.set_sensitive(False) - vb = self.tree.get_widget("comboVB") - children = vb.get_children() + children = self.comboVB.get_children() if children: - for c in children: vb.remove(c) - vb.pack_start(self.vCombo) + for c in children: + self.comboVB.remove(c) + self.comboVB.pack_start(self.vCombo) # the label (must be here, because it depends on the combo box) desc = self.actual_package().get_env_var("DESCRIPTION").replace("&","&") @@ -310,7 +326,6 @@ class PackageTable: desc = "<b>"+desc+"</b>" use_markup = True desc = "<i><u>"+self.actual_package().get_cp()+"</u></i>\n\n"+desc - self.descLabel = self.tree.get_widget("descLabel") self.descLabel.set_use_markup(use_markup) self.descLabel.set_label(desc) @@ -332,15 +347,7 @@ class PackageTable: pkg_flags = pkg.get_all_use_flags() pkg_flags.sort() for use in pkg_flags: - if pkg.is_installed() and use in pkg.get_actual_use_flags(): # flags set during install - enabled = True - elif (not pkg.is_installed()) and use in pkg.get_settings("USE").split() and not flags.invert_use_flag(use) in pkg.get_new_use_flags(): # flags that would be set - enabled = True - elif use in pkg.get_new_use_flags(): - enabled = True - else: - enabled = False - store.append([enabled, use, backend.get_use_desc(use, self.cp)]) + store.append([pkg.is_use_flag_enabled(use), use, backend.get_use_desc(use, self.cp)]) return store @@ -590,12 +597,6 @@ class MainWindow (Window): self.cfg.modify_external_configs() - # accelerators - for whatever reason they are not automatically working for popups - self.accel_group = gtk.AccelGroup() - self.window.add_accel_group(self.accel_group) - self.accel_group.connect_group(ord("C"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, lambda g, a, k, m: self.cb_copy_clicked(a)) - self.accel_group.connect_group(ord("1"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE, lambda g, a, k, m: self.cb_oneshot_clicked(a)) - # set vpaned position vpaned = self.tree.get_widget("vpaned") vpaned.set_position(mHeight/2) @@ -630,7 +631,7 @@ class MainWindow (Window): self.packageTable.table.hide_all() # popups - self.queuePopup = self.create_popup("queuePopup") + self.queuePopup = self.tree.get_widget("queuePopup") self.consolePopup = self.create_popup("consolePopup") # set emerge queue @@ -655,6 +656,9 @@ class MainWindow (Window): col = gtk.TreeViewColumn("Options", cell, markup = 1) self.queueList.append_column(col) + self.useTips = UseTips(0, self.cfg) + self.useTips.add_view(self.queueList) + def build_cat_list (self): """Builds the category list.""" @@ -711,8 +715,8 @@ class MainWindow (Window): else: title = ("Console (%s)" % title) gobject.idle_add(self.notebook.set_tab_label_text, self.termHB, title) - + def cb_cat_list_selection (self, view): """Callback for a category-list selection. Updates the package list with the packages in the category.""" # get the selected category @@ -885,7 +889,8 @@ class MainWindow (Window): pthinfo = object.get_path_at_pos(x, y) if pthinfo is not None: path, col, cellx, celly = pthinfo - if self.queueTree.is_in_emerge(self.queueTree.get_original().get_iter(path)): + it = self.queueTree.get_original().get_iter(path) + if self.queueTree.is_in_emerge(it) and self.queueTree.iter_has_parent(it): object.grab_focus() object.set_cursor(path, col, 0) self.queuePopup.popup(None, None, None, event.button, time) diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py index 759752e..7808298 100644 --- a/portato/gui/gui_helper.py +++ b/portato/gui/gui_helper.py @@ -33,6 +33,7 @@ class Config: """Wrapper around a ConfigParser and for additional local configurations.""" const = { "main_sec" : "Main", + "gtk_sec" : "Gtk", "usePerVersion_opt" : "usePerVersion", "useFile_opt" : "usefile", "maskFile_opt" : "maskfile", @@ -43,7 +44,8 @@ class Config: "oneshot_opt" : "oneshot", "deep_opt" : "deep", "newuse_opt" : "newuse", - "syncCmd_opt" : "synccommand" + "syncCmd_opt" : "synccommand", + "useTips_opt" : "showusetips" } def __init__ (self, cfgFile): |