And the final dialog present in olive.glade.I'm very happy with the result. I was able to reduce the workload a lot by doing an iteration over a list with the info keys/labels. That way, info.py is halved in size while the GTK code is now included as well! :D
I know a dozen exec and eval statements is not the most readable code but it beats writing the same set for every key every day. :)
Enjoy! Jasper
# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: [EMAIL PROTECTED] # target_branch: https://code.launchpad.net/~bzr-gtk/bzr-gtk/trunk # testament_sha1: e6516aaed86418dbf8e577d2f50e3478c074472c # timestamp: 2008-07-20 01:16:59 +0200 # source_branch: https://code.launchpad.net/~bzr-gtk/bzr-gtk/trunk # base_revision_id: [EMAIL PROTECTED] # # Begin patch === modified file 'olive/__init__.py' --- olive/__init__.py 2008-07-18 18:25:39 +0000 +++ olive/__init__.py 2008-07-19 23:16:51 +0000 @@ -783,11 +783,11 @@ def on_menuitem_stats_infos_activate(self, widget): """ Statistics/Informations... menu handler. """ - from info import OliveInfo + from bzrlib.plugins.gtk.olive.info import InfoDialog if self.remote: - info = OliveInfo(self.remote_branch) + info = InfoDialog(self.remote_branch) else: - info = OliveInfo(self.wt.branch) + info = InfoDialog(self.wt.branch) info.display() def on_menuitem_stats_log_activate(self, widget): === modified file 'olive/info.py' --- olive/info.py 2008-05-05 18:16:46 +0000 +++ olive/info.py 2008-07-19 23:16:51 +0000 @@ -14,6 +14,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +import os + try: import pygtk pygtk.require("2.0") @@ -21,13 +23,11 @@ pass import gtk -import gtk.glade import bzrlib.errors as errors -from bzrlib.plugins.gtk import _i18n +from bzrlib.plugins.gtk import _i18n, icon_path from bzrlib.plugins.gtk.dialog import error_dialog -from guifiles import GLADEFILENAME def info(location): @@ -137,21 +137,16 @@ ret['repstats'] = info_helper.get_repository_stats(repository) finally: repository.unlock() - return ret - return + return ret except errors.NoRepositoryPresent: pass -class OliveInfo: +class InfoDialog(object): """ Display Informations window and perform the needed actions. """ + def __init__(self, branch): """ Initialize the Informations window. """ - self.glade = gtk.glade.XML(GLADEFILENAME, 'window_info', 'olive-gtk') - - # Get the Informations window widget - self.window = self.glade.get_widget('window_info') - # Check if current location is a branch self.notbranch = False try: @@ -160,391 +155,113 @@ self.notbranch = True return - # Dictionary for signal_autoconnect - dic = { "on_button_info_close_clicked": self.close, - "on_expander_info_location_activate": self.activate, - "on_expander_info_related_activate": self.activate, - "on_expander_info_format_activate": self.activate, - "on_expander_info_locking_activate": self.activate, - "on_expander_info_missing_activate": self.activate, - "on_expander_info_wtstats_activate": self.activate, - "on_expander_info_brstats_activate": self.activate, - "on_expander_info_repstats_activate": self.activate } - - # Connect the signals to the handlers - self.glade.signal_autoconnect(dic) - + iconpath = icon_path() + os.sep + + # Create the window + self.window = gtk.Dialog(title="Olive - Information", + parent = None, + flags=0, + buttons=None) + self.window.set_icon_list(gtk.gdk.pixbuf_new_from_file(iconpath+"oliveicon2.png"), + gtk.gdk.pixbuf_new_from_file(iconpath+"olive-gtk.png")) + self.window.vbox.set_spacing(3) + self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL) + + infokeylist = ( ('location', _i18n("Location"), ( + ('lightcoroot', _i18n("Light checkout root")), + ('sharedrepo', _i18n("Shared repository")), + ('repobranch', _i18n("Repository branch")), + ('cobranch', _i18n("Checkout of branch")), + ('repoco', _i18n("Repository checkout")), + ('coroot', _i18n("Checkout root")), + ('branchroot', _i18n("Branch root")), + )), + ('related', _i18n("Related branches"), ( + ('parentbranch', _i18n("Parent branch")), + ('publishbranch', _i18n("Publish to branch")), + )), + ('format', _i18n("Format"), ( + ('control', _i18n("Control format")), + ('workingtree', _i18n("Working tree format")), + ('branch', _i18n("Branch format")), + ('repository', _i18n("Repository format")), + )), + ('locking', _i18n("Lock status"), ( + ('workingtree', _i18n("Working tree lock status")), + ('branch', _i18n("Branch lock status")), + ('repository', _i18n("Repository lock status")), + )), + #('missing', _i18n("Missing revisions"), ( + # ('branch', _i18n("Missing revisions in branch")), + # ('workingtree', _i18n("Missing revisions in working tree")), + # )), # Missing is 'temporary' disabled + ('wtstats', _i18n("In the working tree"), ( + ('unchanged', _i18n("Unchanged files")), + ('modified', _i18n("Modified files")), + ('added', _i18n("Added files")), + ('removed', _i18n("Removed files")), + ('renamed', _i18n("Renamed files")), + ('unknown', _i18n("Unknown files")), + ('ignored', _i18n("Ignored files")), + ('subdirs', _i18n("Versioned subdirectories")), + )), + ('brstats', _i18n("Branch history"), ( + ('revno', _i18n("Revisions in branch")), + ('commiters', _i18n("Number of commiters")), + ('age', _i18n("Age of branch in days")), + ('firstrev', _i18n("Time of first revision")), + ('lastrev', _i18n("Time of last revision")), + )), + ('repstats', _i18n("Revision store"), ( + ('revisions', _i18n("Revisions in repository")), + ('size', _i18n("Size of repository in bytes")), + )), + ) + # Generate status output - self._generate_info() - - def _generate_info(self): + self._generate_info(infokeylist) + + button_close = gtk.Button(stock=gtk.STOCK_CLOSE) + button_close.connect('clicked', self.close) + self.window.action_area.pack_end(button_close) + self.window.set_focus(button_close) + + def _generate_info(self, infokeylist): """ Generate 'bzr info' output. """ - # location - if self.ret.has_key('location'): - display = False - e = self.glade.get_widget('expander_info_location') - if self.ret['location'].has_key('lightcoroot'): - ll = self.glade.get_widget('label_info_location_lightcoroot_label') - l = self.glade.get_widget('label_info_location_lightcoroot') - l.set_text(self.ret['location']['lightcoroot']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('sharedrepo'): - ll = self.glade.get_widget('label_info_location_sharedrepo_label') - l = self.glade.get_widget('label_info_location_sharedrepo') - l.set_text(self.ret['location']['sharedrepo']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('repobranch'): - ll = self.glade.get_widget('label_info_location_repobranch_label') - l = self.glade.get_widget('label_info_location_repobranch') - l.set_text(self.ret['location']['repobranch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('cobranch'): - ll = self.glade.get_widget('label_info_location_cobranch_label') - l = self.glade.get_widget('label_info_location_cobranch') - l.set_text(self.ret['location']['cobranch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('repoco'): - ll = self.glade.get_widget('label_info_location_repoco_label') - l = self.glade.get_widget('label_info_location_repoco') - l.set_text(self.ret['location']['repoco']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('coroot'): - ll = self.glade.get_widget('label_info_location_coroot_label') - l = self.glade.get_widget('label_info_location_coroot') - l.set_text(self.ret['location']['coroot']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['location'].has_key('branchroot'): - ll = self.glade.get_widget('label_info_location_branchroot_label') - l = self.glade.get_widget('label_info_location_branchroot') - l.set_text(self.ret['location']['branchroot']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # related - if self.ret.has_key('related'): - display = False - e = self.glade.get_widget('expander_info_related') - if self.ret['related'].has_key('parentbranch'): - ll = self.glade.get_widget('label_info_related_parentbranch_label') - l = self.glade.get_widget('label_info_related_parentbranch') - l.set_text(self.ret['related']['parentbranch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['related'].has_key('publishbranch'): - ll = self.glade.get_widget('label_info_related_publishbranch_label') - l = self.glade.get_widget('label_info_related_publishbranch') - l.set_text(self.ret['related']['publishbranch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # format - if self.ret.has_key('format'): - display = False - e = self.glade.get_widget('expander_info_format') - if self.ret['format'].has_key('control'): - ll = self.glade.get_widget('label_info_format_control_label') - l = self.glade.get_widget('label_info_format_control') - l.set_text(self.ret['format']['control']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['format'].has_key('workingtree'): - ll = self.glade.get_widget('label_info_format_workingtree_label') - l = self.glade.get_widget('label_info_format_workingtree') - l.set_text(self.ret['format']['workingtree']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['format'].has_key('branch'): - ll = self.glade.get_widget('label_info_format_branch_label') - l = self.glade.get_widget('label_info_format_branch') - l.set_text(self.ret['format']['branch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['format'].has_key('repository'): - ll = self.glade.get_widget('label_info_format_repository_label') - l = self.glade.get_widget('label_info_format_repository') - l.set_text(self.ret['format']['repository']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # locking - if self.ret.has_key('locking'): - display = False - e = self.glade.get_widget('expander_info_locking') - if self.ret['locking'].has_key('workingtree'): - ll = self.glade.get_widget('label_info_locking_workingtree_label') - l = self.glade.get_widget('label_info_locking_workingtree') - l.set_text(self.ret['locking']['workingtree']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['locking'].has_key('branch'): - ll = self.glade.get_widget('label_info_locking_branch_label') - l = self.glade.get_widget('label_info_locking_branch') - l.set_text(self.ret['locking']['branch']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['locking'].has_key('repository'): - ll = self.glade.get_widget('label_info_locking_repository_label') - l = self.glade.get_widget('label_info_locking_repository') - l.set_text(self.ret['locking']['repository']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # missing - temporary disabled - """ - if self.ret.has_key('missing'): - display = False - e = self.glade.get_widget('expander_info_missing') - if self.ret['missing'].has_key('branch'): - ll = self.glade.get_widget('label_info_missing_branch_label') - l = self.glade.get_widget('label_info_missing_branch') - l.set_text(self.ret['missing']['branch']) - ll.set_markup('<b>' + ll.get_text() + '</b>') - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['missing'].has_key('workingtree'): - ll = self.glade.get_widget('label_info_missing_workingtree_label') - l = self.glade.get_widget('label_info_missing_workingtree') - l.set_text(self.ret['missing']['branch']) - ll.set_markup('<b>' + ll.get_text() + '</b>') - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - """ - # working tree stats - if self.ret.has_key('wtstats'): - display = False - e = self.glade.get_widget('expander_info_wtstats') - if self.ret['wtstats'].has_key('unchanged'): - ll = self.glade.get_widget('label_info_wtstats_unchanged_label') - l = self.glade.get_widget('label_info_wtstats_unchanged') - l.set_text(str(self.ret['wtstats']['unchanged'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('modified'): - ll = self.glade.get_widget('label_info_wtstats_modified_label') - l = self.glade.get_widget('label_info_wtstats_modified') - l.set_text(str(self.ret['wtstats']['modified'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('added'): - ll = self.glade.get_widget('label_info_wtstats_added_label') - l = self.glade.get_widget('label_info_wtstats_added') - l.set_text(str(self.ret['wtstats']['added'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('removed'): - ll = self.glade.get_widget('label_info_wtstats_removed_label') - l = self.glade.get_widget('label_info_wtstats_removed') - l.set_text(str(self.ret['wtstats']['removed'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('renamed'): - ll = self.glade.get_widget('label_info_wtstats_renamed_label') - l = self.glade.get_widget('label_info_wtstats_renamed') - l.set_text(str(self.ret['wtstats']['renamed'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('unknown'): - ll = self.glade.get_widget('label_info_wtstats_unknown_label') - l = self.glade.get_widget('label_info_wtstats_unknown') - l.set_text(str(self.ret['wtstats']['unknown'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('ignored'): - ll = self.glade.get_widget('label_info_wtstats_ignored_label') - l = self.glade.get_widget('label_info_wtstats_ignored') - l.set_text(str(self.ret['wtstats']['ignored'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['wtstats'].has_key('subdirs'): - ll = self.glade.get_widget('label_info_wtstats_subdirs_label') - l = self.glade.get_widget('label_info_wtstats_subdirs') - l.set_text(str(self.ret['wtstats']['subdirs'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # branch stats - if self.ret.has_key('brstats'): - display = False - e = self.glade.get_widget('expander_info_brstats') - if self.ret['brstats'].has_key('revno'): - ll = self.glade.get_widget('label_info_brstats_revno_label') - l = self.glade.get_widget('label_info_brstats_revno') - l.set_text(str(self.ret['brstats']['revno'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['brstats'].has_key('commiters'): - ll = self.glade.get_widget('label_info_brstats_commiters_label') - l = self.glade.get_widget('label_info_brstats_commiters') - l.set_text(str(self.ret['brstats']['commiters'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['brstats'].has_key('age'): - ll = self.glade.get_widget('label_info_brstats_age_label') - l = self.glade.get_widget('label_info_brstats_age') - l.set_text('%d days' % self.ret['brstats']['age']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['brstats'].has_key('firstrev'): - ll = self.glade.get_widget('label_info_brstats_firstrev_label') - l = self.glade.get_widget('label_info_brstats_firstrev') - l.set_text(self.ret['brstats']['firstrev']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['brstats'].has_key('lastrev'): - ll = self.glade.get_widget('label_info_brstats_lastrev_label') - l = self.glade.get_widget('label_info_brstats_lastrev') - l.set_text(self.ret['brstats']['lastrev']) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - # repository stats - if self.ret.has_key('repstats'): - display = False - e = self.glade.get_widget('expander_info_repstats') - if self.ret['repstats'].has_key('revisions'): - ll = self.glade.get_widget('label_info_repstats_revisions_label') - l = self.glade.get_widget('label_info_repstats_revisions') - l.set_text(str(self.ret['repstats']['revisions'])) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True - if self.ret['repstats'].has_key('size'): - ll = self.glade.get_widget('label_info_repstats_size_label') - l = self.glade.get_widget('label_info_repstats_size') - l.set_text('%d KiB' % (self.ret['repstats']['size'] / 1024)) - ll.show() - l.show() - if not display: - e.set_expanded(True) - e.show() - display = True + for key, keystring, subkeylist in infokeylist: + if self.ret.has_key(key): + tablelength = 0 + for subkey, subkeystring in subkeylist: + if self.ret[key].has_key(subkey): + tablelength += 1 + if tablelength == 0: + pass + else: + exec "exp_%s = gtk.Expander('<b>%s</b>')"%(key, keystring) + eval("exp_%s.set_use_markup(True)"%key) + eval("exp_%s.connect('activate', self.activate)"%key) + + exec "alignment_%s = gtk.Alignment()"%key + eval("alignment_%s.set_padding(0, 0, 24, 0)"%key) + eval("exp_%s.add(alignment_%s)"%(key, key)) + + exec "table_%s = gtk.Table(tablelength, 2)"%key + eval("table_%s.set_col_spacings(12)"%key) + eval("alignment_%s.add(table_%s)"%(key, key)) + + tablepos = 0 + for subkey, subkeystring in subkeylist: + if self.ret[key].has_key(subkey): + exec "%s_%s_label = gtk.Label('%s:')"%(key,subkey, subkeystring) + eval("table_%s.attach(%s_%s_label, 0, 1, %i, %i, gtk.FILL)"%(key, key, subkey, tablepos, tablepos + 1)) + eval("%s_%s_label.set_alignment(0, 0.5)"%(key, subkey)) + + exec "%s_%s = gtk.Label('%s')"%(key, subkey, str(self.ret[key][subkey])) + eval("table_%s.attach(%s_%s, 1, 2, %i, %i, gtk.FILL)"%(key, key, subkey, tablepos, tablepos + 1)) + eval("%s_%s.set_alignment(0, 0.5)"%(key, subkey)) + tablepos += 1 + eval("exp_%s.set_expanded(True)"%key) + eval("self.window.vbox.pack_start(exp_%s, False, True, 0)"%key) def activate(self, expander): """ Redraw the window. """ @@ -558,7 +275,7 @@ _i18n('You can perform this action only in a branch.')) self.close() else: - self.window.show() - + self.window.show_all() + def close(self, widget=None): self.window.destroy() === modified file 'olive/info_helper.py' --- olive/info_helper.py 2007-08-12 21:14:51 +0000 +++ olive/info_helper.py 2008-07-19 23:16:51 +0000 @@ -17,6 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import time +import sys import bzrlib @@ -28,8 +29,9 @@ urlutils, ) +from bzrlib.diff import show_diff_trees from bzrlib.missing import find_unmerged - + def _repo_rel_url(repo_url, inner_url): """Return path with common prefix of repository path removed. @@ -260,7 +262,7 @@ if revno > 0: firstrev = repository.get_revision(history[0]) age = int((time.time() - firstrev.timestamp) / 3600 / 24) - ret['age'] = age + ret['age'] = '%d days'%age ret['firstrev'] = osutils.format_date(firstrev.timestamp, firstrev.timezone) @@ -279,7 +281,7 @@ if repository.bzrdir.root_transport.listable(): c, t = repository._revision_store.total_size(repository.get_transaction()) ret['revisions'] = c - ret['size'] = t + ret['size'] = '%d KiB'%t return ret @@ -298,17 +300,10 @@ :param new_revision_spec: if None, use working tree as new revision, otherwise use the tree for the specified revision. """ - import sys - - from bzrlib.diff import show_diff_trees if output == None: output = sys.stdout - def spec_tree(spec): - revision_id = spec.in_store(tree.branch).rev_id - return tree.branch.repository.revision_tree(revision_id) - if old_revision_spec is None: old_tree = tree.basis_tree() else: @@ -322,3 +317,7 @@ return show_diff_trees(old_tree, new_tree, output, specific_files, external_diff_options, old_label=old_label, new_label=new_label) + +def spec_tree(spec): + revision_id = spec.in_store(tree.branch).rev_id + return tree.branch.repository.revision_tree(revision_id) # Begin bundle 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
signature.asc
Description: OpenPGP digital signature
-- bzr-gtk mailing list [email protected] Modify settings or unsubscribe at: https://lists.canonical.com/mailman/listinfo/bzr-gtk
