[gtkclient] GtkBuilder-powered gtkclient
This commit is contained in:
parent
5764ebb604
commit
14b79bf0a4
2 changed files with 388 additions and 79 deletions
|
@ -1,7 +1,9 @@
|
|||
import sys
|
||||
import logging
|
||||
import threading
|
||||
import pkg_resources
|
||||
|
||||
from functools import wraps
|
||||
from datetime import datetime
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
@ -13,86 +15,74 @@ from accounting.client import Client
|
|||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Accounting(Gtk.Window):
|
||||
def indicate_activity(func_or_str):
|
||||
description = None
|
||||
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kw):
|
||||
self.status_description.set_text(description)
|
||||
self.activity_indicator.show()
|
||||
self.activity_indicator.start()
|
||||
|
||||
return func(self, *args, **kw)
|
||||
|
||||
return wrapper
|
||||
|
||||
if callable(func_or_str):
|
||||
description = 'Working'
|
||||
return decorator(func_or_str)
|
||||
else:
|
||||
description = func_or_str
|
||||
return decorator
|
||||
|
||||
|
||||
def indicate_activity_done(func):
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kw):
|
||||
self.status_description.set_text('')
|
||||
self.activity_indicator.stop()
|
||||
self.activity_indicator.hide()
|
||||
|
||||
return func(self, *args, **kw)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class AccountingApplication:
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title='Accounting Client')
|
||||
#Gtk.Window.__init__(self, title='Accounting Client')
|
||||
|
||||
self.client = Client()
|
||||
|
||||
self.set_border_width(0)
|
||||
self.load_ui(pkg_resources.resource_filename(
|
||||
'accounting', 'res/client-ui.glade'))
|
||||
|
||||
self.set_default_geometry(640, 360)
|
||||
self.about_dialog.set_transient_for(self.accounting_window)
|
||||
|
||||
# Controls
|
||||
self.accounting_window.connect('delete-event', Gtk.main_quit)
|
||||
self.accounting_window.set_border_width(0)
|
||||
self.accounting_window.set_default_geometry(640, 360)
|
||||
|
||||
self.btn_load_transactions = Gtk.Button(label='Load transactions')
|
||||
self.btn_load_transactions.connect('clicked', self.on_button_clicked)
|
||||
self.accounting_window.show_all()
|
||||
self.transaction_detail.hide()
|
||||
|
||||
self.spinner = Gtk.Spinner()
|
||||
def load_ui(self, path):
|
||||
_log.debug('Loading UI...')
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file(path)
|
||||
builder.connect_signals(self)
|
||||
|
||||
renderer = Gtk.CellRendererText()
|
||||
for element in builder.get_objects():
|
||||
try:
|
||||
setattr(self, Gtk.Buildable.get_name(element), element)
|
||||
_log.debug('Loaded %s', Gtk.Buildable.get_name(element))
|
||||
except TypeError as exc:
|
||||
_log.error('%s could not be loaded: %s', element, exc)
|
||||
|
||||
# Transaction stuff
|
||||
_log.debug('UI loaded')
|
||||
|
||||
self.transaction_data = None
|
||||
self.transaction_store = Gtk.ListStore(str, str, str)
|
||||
self.transaction_view = Gtk.TreeView(self.transaction_store)
|
||||
|
||||
self.id_column = Gtk.TreeViewColumn('ID', renderer, text=0)
|
||||
self.date_column = Gtk.TreeViewColumn('Date', renderer, text=1)
|
||||
self.payee_column = Gtk.TreeViewColumn('Payee', renderer, text=2)
|
||||
|
||||
self.transaction_view.append_column(self.date_column)
|
||||
self.transaction_view.append_column(self.payee_column)
|
||||
|
||||
self.transaction_view.connect('cursor-changed',
|
||||
self.on_transaction_selected)
|
||||
|
||||
# Postings
|
||||
|
||||
self.posting_store = Gtk.ListStore(str, str, str)
|
||||
self.posting_view = Gtk.TreeView(self.posting_store)
|
||||
|
||||
self.account_column = Gtk.TreeViewColumn('Account', renderer, text=0)
|
||||
self.amount_column = Gtk.TreeViewColumn('Amount', renderer, text=1)
|
||||
self.symbol_column = Gtk.TreeViewColumn('Symbol', renderer, text=2)
|
||||
|
||||
self.posting_view.append_column(self.account_column)
|
||||
self.posting_view.append_column(self.amount_column)
|
||||
self.posting_view.append_column(self.symbol_column)
|
||||
|
||||
# The transaction detail view
|
||||
|
||||
self.lbl_payee = Gtk.Label()
|
||||
|
||||
# Layout setting
|
||||
self.menu = Gtk.MenuBar.new()
|
||||
|
||||
self.ctrl_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
self.ctrl_box.pack_start(self.btn_load_transactions, False, False, 0)
|
||||
self.ctrl_box.pack_start(self.spinner, False, False, 5)
|
||||
|
||||
self.detail_view = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
self.detail_view.pack_start(self.lbl_payee, False, True, 0)
|
||||
self.detail_view.pack_start(self.posting_view, True, True, 0)
|
||||
|
||||
self.vertical = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
self.vertical.pack_start(self.ctrl_box, False, True, 0)
|
||||
self.vertical.pack_start(self.transaction_view, True, True, 0)
|
||||
|
||||
self.paned = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
|
||||
self.add(self.paned)
|
||||
|
||||
self.paned.add1(self.vertical)
|
||||
self.paned.add2(self.detail_view)
|
||||
|
||||
# Show
|
||||
|
||||
self.show_all()
|
||||
self.spinner.hide()
|
||||
self.detail_view.hide()
|
||||
|
||||
def on_transaction_selected(self, widget):
|
||||
def on_transaction_view_cursor_changed(self, widget):
|
||||
selection = self.transaction_view.get_selection()
|
||||
selection.set_mode(Gtk.SelectionMode.SINGLE)
|
||||
xact_store, xact_iter = selection.get_selected()
|
||||
|
@ -102,7 +92,7 @@ class Accounting(Gtk.Window):
|
|||
|
||||
for transaction in self.transaction_data:
|
||||
if transaction.id == xact_id:
|
||||
self.lbl_payee.set_text(transaction.payee)
|
||||
self.transaction_header.set_text(transaction.payee)
|
||||
|
||||
self.posting_store.clear()
|
||||
|
||||
|
@ -113,22 +103,30 @@ class Accounting(Gtk.Window):
|
|||
posting.amount.symbol
|
||||
])
|
||||
|
||||
self.detail_view.show()
|
||||
self.transaction_detail.show()
|
||||
break
|
||||
|
||||
def on_button_clicked(self, widget):
|
||||
def on_show_about_activate(self, widget):
|
||||
_log.debug('Showing About')
|
||||
self.about_dialog.show_all()
|
||||
|
||||
def on_about_dialog_response(self, widget, response_type):
|
||||
_log.debug('Closing About')
|
||||
if response_type == Gtk.ResponseType.CANCEL:
|
||||
self.about_dialog.hide()
|
||||
else:
|
||||
_log.error('Unexpected response_type: %d', response_type)
|
||||
|
||||
@indicate_activity('Refreshing Transactions')
|
||||
def on_transaction_refresh_activate(self, widget):
|
||||
def load_transactions():
|
||||
transactions = self.client.get_register()
|
||||
GLib.idle_add(self.on_transactions_loaded, transactions)
|
||||
|
||||
self.spinner.show()
|
||||
self.spinner.start()
|
||||
|
||||
threading.Thread(target=load_transactions).start()
|
||||
|
||||
@indicate_activity_done
|
||||
def on_transactions_loaded(self, transactions):
|
||||
self.spinner.stop()
|
||||
self.spinner.hide()
|
||||
_log.debug('transactions: %s', transactions)
|
||||
|
||||
self.transaction_data = transactions
|
||||
|
@ -147,8 +145,7 @@ def main(argv=None):
|
|||
|
||||
GObject.threads_init()
|
||||
|
||||
accounting_win = Accounting()
|
||||
accounting_win.connect('delete-event', Gtk.main_quit)
|
||||
accounting = AccountingApplication()
|
||||
|
||||
Gtk.main()
|
||||
|
||||
|
|
312
accounting/res/client-ui.glade
Normal file
312
accounting/res/client-ui.glade
Normal file
|
@ -0,0 +1,312 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<!-- interface-requires gtk+ 3.0 -->
|
||||
<object class="GtkListStore" id="posting_store">
|
||||
<columns>
|
||||
<!-- column-name Account -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name Amount -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name Symbol -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkAction" id="show_about">
|
||||
<property name="label" translatable="yes">About</property>
|
||||
<signal name="activate" handler="on_show_about_activate" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkWindow" id="accounting_window">
|
||||
<property name="can_focus">False</property>
|
||||
<accel-groups>
|
||||
<group name="transaction_accel_group"/>
|
||||
</accel-groups>
|
||||
<child>
|
||||
<object class="GtkBox" id="main">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkMenuBar" id="menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menu_file">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_File</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_menuitem1_activate" swapped="no"/>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="get_transactions">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="menu_refresh">
|
||||
<property name="related_action">refresh</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="menu_quit">
|
||||
<property name="label">gtk-quit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="menu_help">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Help</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu" id="menu3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="menu_about">
|
||||
<property name="related_action">show_about</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="transaction_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="opacity">0.98999999999999999</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="model">transaction_store</property>
|
||||
<property name="search_column">2</property>
|
||||
<signal name="cursor-changed" handler="on_transaction_view_cursor_changed" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="transaction_col_id">
|
||||
<property name="visible">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="id_renderer"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="transaction_col_date">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="title" translatable="yes">Date</property>
|
||||
<property name="sort_indicator">True</property>
|
||||
<property name="sort_column_id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="date_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="transaction_col_payee">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Payee</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="payee_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="transaction_detail">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="transaction_header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="ypad">18</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.2"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="posting_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="model">posting_store</property>
|
||||
<property name="headers_clickable">False</property>
|
||||
<property name="search_column">0</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="posting_col_account">
|
||||
<property name="title" translatable="yes">Account</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="account_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="posting_col_amount">
|
||||
<property name="title" translatable="yes">Amount</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="amount_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="posting_col_symbol">
|
||||
<property name="title" translatable="yes">Symbol</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="symbol_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="status_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinner" id="activity_indicator">
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="status_description">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="ypad">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkAboutDialog" id="about_dialog">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="window_position">center-always</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="transient_for">accounting_window</property>
|
||||
<property name="program_name">Accounting Client</property>
|
||||
<property name="version">dev</property>
|
||||
<property name="website">http://gitorious.org/conservancy/accounting-api</property>
|
||||
<property name="website_label" translatable="yes">Source code</property>
|
||||
<property name="license_type">lgpl-2-1</property>
|
||||
<signal name="close" handler="on_about_dialog_close" swapped="no"/>
|
||||
<signal name="response" handler="on_about_dialog_response" swapped="no"/>
|
||||
</object>
|
||||
<object class="GtkAccelGroup" id="transaction_accel_group"/>
|
||||
<object class="GtkActionGroup" id="transaction_actions">
|
||||
<property name="accel_group">transaction_accel_group</property>
|
||||
<child>
|
||||
<object class="GtkAction" id="refresh">
|
||||
<property name="label" translatable="yes">Test</property>
|
||||
<signal name="activate" handler="on_transaction_refresh_activate" swapped="no"/>
|
||||
</object>
|
||||
<accelerator key="r" modifiers="GDK_CONTROL_MASK"/>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="transaction_store">
|
||||
<columns>
|
||||
<!-- column-name ID -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name Date -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name Payee -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
</interface>
|
Loading…
Reference in a new issue