Example #1
0
    def __init__(self, with_code=True, create_mode=False):
        self.create_mode = create_mode
        self._accounts = {}

        columns = [StockTextColumn('description', title=_("Account name"),
                                   data_type=str, pack_end=True, expand=True,
                                   sorted=True, sort_func=sort_models)]
        if with_code:
            columns.append(Column('code', title=_("Code"), data_type=str,
                                  width=120))
        if not create_mode:
            # FIXME: This needs to be much better colorized, and moved to the
            #        domain classes
            def colorize(account):
                if (account.kind == 'account' and
                    account.account_type == Account.TYPE_INCOME):
                    return False
                else:
                    return account.total < 0
            columns.append(ColoredColumn('total', title=_("Total"), width=100,
                                         data_type=currency,
                                         color='red',
                                         data_func=colorize,
                                         use_data_model=True))
        ObjectTree.__init__(self, columns,
                            mode=gtk.SELECTION_SINGLE)

        def render_icon(icon):
            return self.render_icon(icon, gtk.ICON_SIZE_MENU)
        self._pixbuf_money = render_icon(STOQ_MONEY)
        self._pixbuf_payable = render_icon(STOQ_PAYABLE_APP)
        self._pixbuf_receivable = render_icon(STOQ_BILLS)
        self._pixbuf_till = render_icon(STOQ_TILL_APP)
        if self.create_mode:
            self.set_headers_visible(False)
Example #2
0
    def __init__(self, model, parent):
        super(DetailsTab, self).__init__()

        self.model = model
        self._parent = parent

        self.set_spacing(6)
        self.set_border_width(6)

        self.klist = ObjectTree(self.get_columns())
        self.populate()

        self.pack_start(self.klist, True, True, 0)
        self.klist.show()

        if len(self.klist) and self.get_details_dialog_class():
            self.button_box = Gtk.HButtonBox()
            self.button_box.set_layout(Gtk.ButtonBoxStyle.START)

            details_button = Gtk.Button.new_with_label(self.details_lbl)
            self.button_box.pack_start(details_button, True, True, 0)
            details_button.set_sensitive(bool(self.klist.get_selected()))
            details_button.show()

            self.pack_end(self.button_box, False, False, 0)
            self.button_box.show()

            self.button_box.details_button = details_button
            details_button.connect('clicked', self._on_details_button__clicked)

            self.klist.connect('row-activated', self._on_klist__row_activated)
            self.klist.connect('selection-changed',
                               self._on_klist__selection_changed)

        self.setup_widgets()
Example #3
0
    def setup_wikitree(self):
        columns = ['name', 'id', 'lastModified', 'perms', 'size']
        columns = [Column(s) for s in columns]
        self.objectlist = ObjectTree(columns)

        self.objectlist.connect("selection-changed", self.selected)
        self.view.vbox2.add(self.objectlist)
Example #4
0
	def __init__(self, parent, mo):
		self.log = logging.getLogger('MINICAL')
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		self.__stop_auto_highlight = False # Disable automatic highlighting of events.
		self.__stop_auto_dayjump = False   # Disable automatically jumping to the start of the event on selection.
		self.__stop_auto_treeview_update = False   # FIXME

		GladeSlaveDelegate.__init__(self, gladefile='mo_tab_events', toplevel_name='window_main')

		# Set up the user interface
		eventColumns = [
			Column('start', title='Start', data_type=datetime.datetime, sorted=True),
			Column('end', title='End', data_type=datetime.datetime),
			Column('summaryformat', title='Summary', use_markup=True),
			Column('duration', title='Duration', justify=gtk.JUSTIFY_RIGHT)
		]
		self.treeview_event = ObjectTree(eventColumns)
		self.vbox_eventslist.add(self.treeview_event)
		self.combobox_display_range.set_active(self.show_ranges.index(self.mo.config['events.default_show'].lower()))
		cal_options = gtk.CALENDAR_WEEK_START_MONDAY
		if self.mo.config['events.cal_show_weeknr']:
			cal_options |= gtk.CALENDAR_SHOW_WEEK_NUMBERS
		self.calendar.set_display_options((self.calendar.get_display_options() | cal_options))

		# Connect signals
		self.treeview_event.connect('selection-changed', self.treeview_event__selection_changed)
		self.treeview_event.connect('row-activated', self.treeview_event__row_activated)
		self.treeview_event.connect('key-press-event', self.treeview_event__key_press_event)

		self.on_toolbutton_today__clicked()
Example #5
0
    def __init__(self, parent, menubar):
        self.project_data = ObjectTree([Column('name',
                                               use_markup=True,
                                               data_type=str,
                                               sorted=True),
                                        Column('info')])

        self.project_data.connect('row-activated', self.on_row_activated)
        self.model_tree = Project()
        self._set_treeview_hooks()

        self.menubar = menubar

        self.set_parent(parent)


        self.filename = ''

        self.undo_stack = UndoStack(
            self.model_tree.__repr__,
            self.import_xml_file,
            self.project_data.select,
            menubar,
            self.meta,
            'Initialization')

        SlaveDelegate.__init__(self, toplevel=self.project_data)
Example #6
0
    def setup_wikitree(self):
        columns = ['id', 'lastModified', 'perms', 'size']
        columns = [Column(s) for s in columns]
        columns.insert(0, Column('icon', title='name', data_type=gtk.gdk.Pixbuf))
        self.objectlist = ObjectTree(columns)
        columns.insert(1, Column('name', column='icon'))
        self.objectlist.set_columns(columns)

        self.objectlist.connect("selection-changed", self.selected)
        self.view.vbox2.add(self.objectlist)
Example #7
0
    def __init__(self, store, columns=None, editor_class=None,
                 klist_objects=None, visual_mode=False, restore_name=None,
                 tree=False):
        """ Creates a new AdditionListSlave object

        :param store:         a store
        :param columns:       column definitions
        :type columns:        sequence of :class:`kiwi.ui.objectlist.Columns`
        :param editor_class:  the window that is going to be open when user
                              clicks on add_button or edit_button.
        :type: editor_class:  a :class:`stoqlib.gui.editors.BaseEditor` subclass
        :param klist_objects: initial objects to insert into the list
        :param visual_mode:   if we are working on visual mode, that means,
                              not possible to edit the model on this object
        type visual_mode:     bool
        :param restore_name:  the name used to save and restore the columns
                              on a cache system (e.g. pickle)
        :type restore_name:   basestring
        :param tree:          Indication of which kind of list we are adding.
                              If `True` ObjectTree otherwise ObjectList will be
                              added
        """
        columns = columns or self.get_columns()
        SearchSlave.__init__(self, columns=columns,
                             restore_name=restore_name,
                             store=store)
        self.tree = tree
        self.klist = ObjectTree() if tree else ObjectList()
        self.list_vbox.add(self.klist)
        self.list_vbox.show_all()

        if not self.columns:
            raise StoqlibError("columns must be specified")
        self.visual_mode = visual_mode
        self.store = store
        self.set_editor(editor_class)
        self._can_edit = True
        self._callback_id = None
        if self.visual_mode:
            self.hide_add_button()
            self.hide_edit_button()
            self.hide_del_button()
        items = klist_objects or self.get_items()
        self._setup_klist(items)
        self._update_sensitivity()
Example #8
0
	def __init__(self, parent, mo):
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		# Set up the user interface
		GladeSlaveDelegate.__init__(self, gladefile="mo_tab_notes", toplevel_name="window_main")
	
		noteColumns = [
			Column("summary", title='Title', data_type=str),
		]
		#self.treeview_note = ObjectList(noteColumns)
		self.treeview_note = ObjectTree(noteColumns)
		self.vbox_notelist.add(self.treeview_note)

		# Connect signals
		self.treeview_note.connect('row-activated', self.treeview_note__row_activated)
		self.treeview_note.connect('selection-changed', self.treeview_note__selection_changed)
		self.treeview_note.connect('key-press-event', self.treeview_note__key_press_event)

		self.refresh()
Example #9
0
	def __init__(self, parent, mo):
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		GladeSlaveDelegate.__init__(self, gladefile="mo_tab_todo", toplevel_name="window_main")

		# Set up the user interface
		todoColumns = [
			Column("done", title='Done', data_type=bool, editable=True),
			Column("summaryformat", title='Summary', use_markup=True),
			Column('priority', title='Priority', sorted=True, order=gtk.SORT_DESCENDING),
			ColoredColumn('due', title='Due', data_type=datetime.datetime, color='red', data_func=self.color_due),
			Column('created', title='Created', data_type=datetime.datetime)
		]
		self.treeview_todo = ObjectTree(todoColumns)
		self.vbox_todolist.add(self.treeview_todo)

		# Connect signals
		self.treeview_todo.connect('row-activated', self.treeview_todo__row_activated)
		self.treeview_todo.connect('selection-changed', self.treeview_todo__selection_changed)
		self.treeview_todo.connect('key-press-event', self.treeview_todo__key_press_event)

		self.refresh()
Example #10
0
class DetailsTab(Gtk.VBox):
    details_dialog_class = None

    def __init__(self, model, parent):
        super(DetailsTab, self).__init__()

        self.model = model
        self._parent = parent

        self.set_spacing(6)
        self.set_border_width(6)

        self.klist = ObjectTree(self.get_columns())
        self.populate()

        self.pack_start(self.klist, True, True, 0)
        self.klist.show()

        if len(self.klist) and self.get_details_dialog_class():
            self.button_box = Gtk.HButtonBox()
            self.button_box.set_layout(Gtk.ButtonBoxStyle.START)

            details_button = Gtk.Button.new_with_label(self.details_lbl)
            self.button_box.pack_start(details_button, True, True, 0)
            details_button.set_sensitive(bool(self.klist.get_selected()))
            details_button.show()

            self.pack_end(self.button_box, False, False, 0)
            self.button_box.show()

            self.button_box.details_button = details_button
            details_button.connect('clicked', self._on_details_button__clicked)

            self.klist.connect('row-activated', self._on_klist__row_activated)
            self.klist.connect('selection-changed',
                               self._on_klist__selection_changed)

        self.setup_widgets()

    def refresh(self):
        """Refreshes the list of respective tab."""
        self.klist.clear()
        self.klist.add_list(self.populate())

    def get_columns(self):
        """Returns a list of columns this tab should show."""
        raise NotImplementedError

    def show_details(self):
        """Called when the details button is clicked. Displays the details of
        the selected object in the list."""
        model = self.get_details_model(self.klist.get_selected())
        run_dialog(self.get_details_dialog_class(),
                   parent=self._parent,
                   store=self._parent.store,
                   model=model,
                   visual_mode=True)

    def get_label(self):
        """Returns the name of the tab."""
        label = Gtk.Label(label=self.labels[1])
        return label

    def get_details_model(self, model):
        """Subclassses can overwrite this method if the details dialog class
        needs a model different than the one on the list."""
        return model

    def get_details_dialog_class(self):
        """Subclasses must return the dialog that should be displayed for more
        information about the item on the list"""
        return self.details_dialog_class

    def setup_widgets(self):
        """Override this if tab needs to do some custom widget setup."""

    #
    # Callbacks
    #

    def _on_details_button__clicked(self, button):
        self.show_details()

    def _on_klist__row_activated(self, klist, item):
        self.show_details()

    def _on_klist__selection_changed(self, klist, data):
        self.button_box.details_button.set_sensitive(bool(data))
Example #11
0
class EventUI(GladeSlaveDelegate):
	
	show_ranges = ['day', 'week', 'month', 'year']

	def __init__(self, parent, mo):
		self.log = logging.getLogger('MINICAL')
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		self.__stop_auto_highlight = False # Disable automatic highlighting of events.
		self.__stop_auto_dayjump = False   # Disable automatically jumping to the start of the event on selection.
		self.__stop_auto_treeview_update = False   # FIXME

		GladeSlaveDelegate.__init__(self, gladefile='mo_tab_events', toplevel_name='window_main')

		# Set up the user interface
		eventColumns = [
			Column('start', title='Start', data_type=datetime.datetime, sorted=True),
			Column('end', title='End', data_type=datetime.datetime),
			Column('summaryformat', title='Summary', use_markup=True),
			Column('duration', title='Duration', justify=gtk.JUSTIFY_RIGHT)
		]
		self.treeview_event = ObjectTree(eventColumns)
		self.vbox_eventslist.add(self.treeview_event)
		self.combobox_display_range.set_active(self.show_ranges.index(self.mo.config['events.default_show'].lower()))
		cal_options = gtk.CALENDAR_WEEK_START_MONDAY
		if self.mo.config['events.cal_show_weeknr']:
			cal_options |= gtk.CALENDAR_SHOW_WEEK_NUMBERS
		self.calendar.set_display_options((self.calendar.get_display_options() | cal_options))

		# Connect signals
		self.treeview_event.connect('selection-changed', self.treeview_event__selection_changed)
		self.treeview_event.connect('row-activated', self.treeview_event__row_activated)
		self.treeview_event.connect('key-press-event', self.treeview_event__key_press_event)

		self.on_toolbutton_today__clicked()
	
	def refresh(self):
		"""
		Refresh the entire events tab. This clears everything and rebuilds it.
		Call this when events are removed outside of this class.
		"""
		self.treeview_event.clear()
		self.calendar.clear_marks()
		self.on_calendar__month_changed(self.calendar)
		self.treeview_event__update()

	def on_toolbutton_add__clicked(self, *args):
		now = datetime.datetime.now()
		sel_day = self.calendar.get_date()
		start = datetime.datetime(sel_day[0], sel_day[1]+1, sel_day[2], now.hour, now.minute)
		end = start + datetime.timedelta(hours=+1)

		event = self.factory.event(start, end)
		event = miniorganizer.ui.EventEditUI(self.mo, event).run()
		if event:
			self.mo.cal_model.add(event)
			self.treeview_event.append(None, event)
			self.on_calendar__month_changed(self.calendar)
			self.on_calendar__day_selected(self.calendar)
			self.parent.menuitem_save.set_sensitive(True)

	def on_toolbutton_remove__clicked(self, *args):
		sel_event = self.treeview_event.get_selected()
		sel_real_event = getattr(sel_event, 'real_event', sel_event) # Delete real event instead of recurring event

		if sel_event != sel_real_event:
			response = dialogs.yesno('This is a recurring event. Deleting it will delete all recurrences. Are you sure you want to delete it?')
			if response == gtk.RESPONSE_NO:
				return
			else:
				sel_event = sel_real_event

		if sel_event:
			self.mo.cal_model.delete(sel_event)
			self.treeview_event.remove(sel_event)
			self.on_calendar__month_changed(self.calendar)
			self.on_calendar__day_selected(self.calendar)
			self.parent.menuitem_save.set_sensitive(True)

	def on_toolbutton_edit__clicked(self, *args):
		sel_event = self.treeview_event.get_selected()
		self.treeview_event__row_activated(self.treeview_event, sel_event)

	def on_toolbutton_today__clicked(self, *args):
		today_dt = datetime.date.today()
		self.calendar.select_month(today_dt.month - 1, today_dt.year)
		self.calendar.select_day(today_dt.day)

	def on_calendar__month_changed(self, calendar, *args):
		self.calendar.clear_marks()
		sel_date = self.calendar.get_date()

		month_start = datetime.datetime(sel_date[0], sel_date[1]+1, 1)
		month_end = month_start + relativedelta(months=+1, seconds=-1)

		events = self.mo.cal_model.get_events() + self.mo.cal_model.get_events_recurring(month_start, month_end)
		for event in events:
			event_start = event.get_start()
			event_end = event.get_end()

			self.log.debug('Event %s, start: %s, end %s' % (event.get_summary(), event_start, event_end))
			# If the event falls in the month, mark the days the event spans in
			# the calendar.
			if (month_start >= event_start and month_start <= event_end) or \
               (month_end >= event_start and month_end <= event_end) or \
               (event_start >= month_start and event_end <= month_end):
				# Walk through the days of the event, marking them.
				delta_iter = datetime.datetime(*event_start.timetuple()[0:3])
				while True:
					if delta_iter.year == month_start.year and delta_iter.month == month_start.month:
						self.calendar.mark_day(delta_iter.day)
					delta_iter = delta_iter + datetime.timedelta(days=+1)
					if delta_iter >= event_end:
						break

	def on_calendar__day_selected(self, calendar, *args):
		# Make sure the correct display range is shown.
		self.on_combobox_display_range__changed()

		# Retrieve the day the user selected.
		sel_day = self.calendar.get_date()
		day_start = datetime.datetime(sel_day[0], sel_day[1]+1, sel_day[2])
		day_end = day_start + datetime.timedelta(days=+1)

		display_month = datetime.datetime(day_start.year, day_start.month, 1)

		# Highlight an event if it starts on the selected day.
		highlight_events = []
		events = [event for event in self.treeview_event]
		for event in events:
			event_start = event.get_start()
			event_end = event.get_end()

			# If this is the first event that starts on the day the user
			# selected, highlight the item in the list of events.
			if event_start >= day_start and event_start < day_end:
				highlight_events.insert(0, event)
			# If the selected day occurs during an event, highlight it. We
			# append it to the list of events to be highlighted, so it'll only
			# be highlighted if no event actually starts on that day.
			elif (day_start > event_start and day_start < event_end) or \
                 (day_end > event_start and day_end < event_end) or \
                 (event_start > day_start and event_end < day_end):
				highlight_events.append(event)

		# Highlight the first event on the day the user selected, unless the
		# user manually selected an event.
		if not self.__stop_auto_highlight:
			if highlight_events and highlight_events[0] in self.treeview_event:
				self.__stop_auto_dayjump = True
				self.treeview_event.select(highlight_events[0], True)
				self.__stop_auto_dayjump = False
			else:
				self.treeview_event.unselect_all()
			
	def on_calendar__day_selected_double_click(self, *args):
		self.on_toolbutton_add__clicked()

	def on_combobox_display_range__changed(self, *args):
		# Get the currently selected date in the calendar.
		sel_date = self.calendar.get_date()
		sel_dt_start = datetime.datetime(sel_date[0], sel_date[1]+1, sel_date[2])
		sel_dt_end = sel_dt_start + datetime.timedelta(days=+1)

		# Determine the start and end of the period that needs to be shown.
		display_range = self.combobox_display_range.get_active_text()
		if display_range == 'Day':
			display_start = sel_dt_start
			display_end = display_start + datetime.timedelta(days=+1, seconds=-1)
			text = '%s' % (display_start.strftime('%a %b %d %Y'))
		elif display_range == 'Week':
			display_start = sel_dt_start + datetime.timedelta(days=-sel_dt_start.weekday())
			display_end = display_start + datetime.timedelta(weeks=+1, seconds=-1)
			text = '%s - %s' % (display_start.strftime('%a %b %d %Y'), display_end.strftime('%a %b %d %Y'))
		elif display_range == 'Month':
			display_start = sel_dt_start + datetime.timedelta(days=-(sel_dt_start.day - 1))
			display_end = display_start + relativedelta(months=+1, seconds=-1)
			text = '%s' % (display_start.strftime('%b %Y'))
		elif display_range == 'Year':
			display_start = datetime.datetime(sel_dt_start.year, 1, 1)
			display_end = display_start + relativedelta(years=+1, seconds=-1)
			text = '%s' % (display_start.strftime('%Y'))
		else:
			raise Exception('No selected display range!')
			
		# Update the displayed range
		self.displayed_range.set_text(text)

		self.display_start = display_start
		self.display_end = display_end

		self.treeview_event__update()

	def treeview_event__update(self):
		if self.__stop_auto_treeview_update:
			return

		# First, remove all the recurring events, because they're generated on
		# the fly, so we can't know which ones in the list we need to remove.
		# Therefor we remove them every time.
		events_rm = []
		for event in self.treeview_event:
			if hasattr(event, 'real_event'):
				events_rm.append(event)
		for event in events_rm:
			self.treeview_event.remove(event)

		# Add the events for the displayed range to the list
		events = self.mo.cal_model.get_events() + self.mo.cal_model.get_events_recurring(self.display_start, self.display_end)
		for event in events:
			event_start = event.get_start()
			event_end = event.get_end()

			# If the currently displayed range includes an event, add it to the list.
			if (self.display_start >= event_start and self.display_start < event_end) or \
               (self.display_end >= event_start and self.display_end < event_end) or \
               (event_start >= self.display_start and event_end < self.display_end):
				if not event in self.treeview_event:
					self.treeview_event.append(None, event)
			# Otherwise, we remove it from the list, if it's present.
			else:
				if event in self.treeview_event:
					self.treeview_event.remove(event)
		
	def treeview_event__row_activated(self, list, object):
		# FIXME: This might be more complicated than it needs to be. See todo.py's row_activated.
		sel_event = self.treeview_event.get_selected()
		sel_event = getattr(sel_event, 'real_event', sel_event) # Edit real event instead of recurring event
		event = miniorganizer.ui.EventEditUI(self.mo, sel_event).run()
		self.on_calendar__month_changed(self.calendar)
		self.on_calendar__day_selected(self.calendar)
		if sel_event in self.treeview_event:
			self.treeview_event.select(sel_event, True)
		self.parent.menuitem_save.set_sensitive(True)

	def treeview_event__selection_changed(self, list, selection):
		# Stop the treeview from automatically updating itself because that
		# will remove the recurring events and regenerate them (with different
		# instance IDs) which means the selection may be invalid.
		self.__stop_auto_treeview_update = True

		sel_event = self.treeview_event.get_selected()
		has_selection = sel_event is not None

		# Enable / disable toolbuttons
		self.toolbutton_remove.set_sensitive(has_selection)
		self.toolbutton_edit.set_sensitive(has_selection)

		# Do not jump to the day of the event. This is needed because an event
		# can be automatically selected even if it doesn't start on a
		# particular day.
		if self.__stop_auto_dayjump:
			self.__stop_auto_treeview_update = False
			return

		# Stop this selection from being overwritten.
		self.__stop_auto_highlight = True

		if has_selection:
			# Make the calendar jump to the day on which this event begins.
			sel_event_start = sel_event.get_start()
			self.calendar.select_month(sel_event_start.month - 1, sel_event_start.year)
			self.calendar.select_day(sel_event_start.day)

		# Enable automatic highlighting of items
		self.__stop_auto_highlight = False
		self.__stop_auto_treeview_update = False
	
	def treeview_event__key_press_event(self, treeview, event):
		if event.keyval == gtk.keysyms.Delete:
			self.on_toolbutton_remove__clicked()
Example #12
0
class DokuwikiView(GladeDelegate):
    """
    A dokuwiki editor window
    """
    def __init__(self):
        GladeDelegate.__init__(self, gladefile="pydoku",
                          delete_handler=self.quit_if_last)
        self.setup_wikitree()
        self.setup_attachments()
        self.setup_side()
        self.setup_sourceview()
        self.setup_htmlview()
        self.page_edit = self.view.notebook1.get_nth_page(0)
        self.page_view = self.view.notebook1.get_nth_page(1)
        self.page_attach = self.view.notebook1.get_nth_page(2)
        self.show_all()

    def quit_if_last(self, *args):
        self.htmlview.destroy() # for some reason has to be deleted explicitly
        GladeDelegate.quit_if_last(self)

    # general interface functions
    def post(self, text):
        id = self.view.statusbar.get_context_id("zap")
        self.view.statusbar.push(id, text)

    # setup functions
    def setup_side(self):
        columns = ['user', 'sum', 'type', 'version', 'ip']
        columns = [Column(s) for s in columns]
        self.versionlist = ObjectList(columns)

        self.view.side_vbox.pack_start(gtk.Label('Version Log:'), False, False)
        self.view.side_vbox.add(self.versionlist)

        self.view.side_vbox.pack_start(gtk.Label('BackLinks:'), False, False)
        self.backlinks = ObjectList([Column('name')])
        self.view.side_vbox.add(self.backlinks)

    def setup_attachments(self):
        columns = ['id', 'size', 'lastModified', 'writable', 'isimg', 'perms']
        columns = [Column(s) for s in columns]
        self.attachmentlist = ObjectList(columns)

        self.view.attachments_vbox.add(self.attachmentlist)

    def setup_wikitree(self):
        columns = ['name', 'id', 'lastModified', 'perms', 'size']
        columns = [Column(s) for s in columns]
        self.objectlist = ObjectTree(columns)

        self.objectlist.connect("selection-changed", self.selected)
        self.view.vbox2.add(self.objectlist)

    def setup_htmlview(self):
        self.htmlview = gtkmozembed.MozEmbed()
        self.view.html_scrolledwindow.add(self.htmlview)
        self.htmlview.realize()
        self.htmlview.show()

    def setup_sourceview(self):
        self.buffer = DokuwikiBuffer(table)
        self.editor = gtksourceview.SourceView(self.buffer)
        accel_group = gtk.AccelGroup()
        self.get_toplevel().add_accel_group(accel_group)
        self.editor.add_accelerator("paste-clipboard", accel_group, ord('v'), gtk.gdk.CONTROL_MASK, 0)
        self.editor.add_accelerator("copy-clipboard", accel_group, ord('c'), gtk.gdk.CONTROL_MASK, 0)
        self.editor.add_accelerator("cut-clipboard", accel_group, ord('x'), gtk.gdk.CONTROL_MASK, 0)
        #self.editor = gtk.TextView(self.buffer)
        self.editor.set_left_margin(5)
        self.editor.set_right_margin(5)
        self.editor.set_wrap_mode(gtk.WRAP_WORD_CHAR)
        self.view.scrolledwindow1.add(self.editor)

    # dokuwiki operations
    def get_version(self):
        version = self._rpc.dokuwiki.getVersion()
        self.view.version.set_text(version)

    def get_pagelist(self):
        pages = self._rpc.wiki.getAllPages()
        self._sections = {}
        self.objectlist.clear()
        for page in pages:
            self.add_page(page)
        self.view.new_page.set_sensitive(True)
        self.view.delete_page.set_sensitive(True)

    def get_attachments(self, ns):
        attachments = self._rpc.wiki.getAttachments(ns, {})
        attachments = [DictWrapper(s) for s in attachments]
        self.attachmentlist.add_list(attachments)

    def get_backlinks(self, pagename):
        backlinks = self._rpc.wiki.getBackLinks(pagename)
        backlinks = [Section(s) for s in backlinks]
        self.backlinks.add_list(backlinks)

    def get_versions(self, pagename):
        versionlist = self._rpc.wiki.getPageVersions(pagename, 0)
        versionlist = [DictWrapper(s) for s in versionlist]
        self.versionlist.add_list(versionlist)

    def get_htmlview(self, pagename):
        text = self._rpc.wiki.getPageHTML(pagename)
        self.htmlview.render_data(text, len(text), self.url.get_text(), 'text/html')
        # XXX following is for gtkhtml (not used)
        #self.document.clear()
        #self.document.open_stream('text/html')
        #self.document.write_stream(text)
        #self.document.close_stream()

    def put_page(self, text, summary, minor):
        pars = {}
        if summary:
            pars['sum'] = summary
        if minor:
            pars['minor'] = minor
        self._rpc.wiki.putPage(self.current, text, pars)
        if not self.current in self._sections:
            self.add_page({"id":self.current})

    # put a page into the page tree
    def add_page(self, page):
        name = page["id"]
        path = name.split(":")
        prev = None
        for i,pathm in enumerate(path):
            if i == len(path)-1: # a page
                new = DictWrapper(page, pathm)
                self._sections[name] = new
                self.objectlist.append(prev, new, False)
            else: # a namespace
                part_path = ":".join(path[:i+1])
                if not part_path in self._sections:
                    new = Section(pathm, part_path)
                    self._sections[part_path] = new
                    self.objectlist.append(prev, new, False)
                else:
                    new = self._sections[part_path]
            prev = new

    # page selected callback
    def selected(self, widget, object):
        if not object: return
        if isinstance(object, Section):
            self.get_attachments(object.id)
        if not isinstance(object, DictWrapper): return
        text = self._rpc.wiki.getPage(object.id)
        self.current = object.id
        self.buffer.add_text(text)
        self.get_htmlview(self.current)
        self.get_backlinks(object.id)
        self.get_versions(object.id)

    # kiwi interface callbacks
    def on_view_edit__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_edit, gtk.Label('edit'), 0)
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_edit))

    def on_view_view__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_view, gtk.Label('view'), 1)
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_view))

    def on_view_attachments__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_attach, gtk.Label('attach'))
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_attach))

    def on_view_extra__toggled(self, widget):
        if widget.get_active():
            self.backlinks.show()
            self.versionlist.show()
            self.view.hpaned2.set_position(self._prevpos)
        else:
            self.backlinks.hide()
            self.versionlist.hide()
            self._prevpos = self.view.hpaned2.get_position()
            self.view.hpaned2.set_position(self.view.hpaned2.allocation.width)

    def on_button_list__clicked(self, *args):
        self.post("Connecting...")
        dialog = ModalDialog("User Details")
        # prepare
        widgets = {}
        items = ["user", "password"]
        for i,item in enumerate(items):
            widgets[item] = gtk.Entry()
            if i == 1:
                widgets[item].set_visibility(False)
            hbox = gtk.HBox()
            hbox.pack_start(gtk.Label(item+': '))
            hbox.add(widgets[item])
            dialog.vbox.add(hbox)
        dialog.show_all()
        # run
        response = dialog.run()
        user = widgets['user'].get_text()
        password = widgets['password'].get_text()
        dialog.destroy()
        if not response == gtk.RESPONSE_ACCEPT: return
        # following commented line is for gtkhtml (not used)
        #simplebrowser.currentUrl = self.view.url.get_text()
        # handle response
        params = urlencode({'u':user,'p':password})
        fullurl = self.view.url.get_text() + "/lib/exe/xmlrpc.php?"+ params
        self._rpc = ServerProxy(fullurl)
        try:
            self.get_version()
        except:
            self.post("Failure to connect")
        self.get_pagelist()
        self.post("Connected")

    def on_delete_page__clicked(self, *args):
        dialog = ModalDialog("Are you sure?")
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            value = self._sections[self.current]
            sel = self.objectlist.remove(value)
            self._rpc.wiki.putPage(self.current, "", {})
            self.current = None
        dialog.destroy()

    def on_new_page__clicked(self, *args):
        dialog = ModalDialog("Name for the new page")
        text_w = gtk.Entry()
        text_w.show()
        response = []
        dialog.vbox.add(text_w)
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            text = text_w.get_text()
            if text:
                self.current = text
        dialog.destroy()

    def on_button_h1__clicked(self, *args):
        self.buffer.set_style('h1')

    def on_button_h2__clicked(self, *args):
        self.buffer.set_style('h2')

    def on_button_h3__clicked(self, *args):
        self.buffer.set_style('h3')

    def on_button_h4__clicked(self, *args):
        self.buffer.set_style('h4')

    def on_button_h5__clicked(self, *args):
        self.buffer.set_style('h5')

    def on_button_h6__clicked(self, *args):
        self.buffer.set_style('h6')

    def on_button_bold__clicked(self, *args):
        self.buffer.set_style('bold')

    def on_button_italic__clicked(self, *args):
        self.buffer.set_style('italic')

    def on_button_clear_style__clicked(self, *args):
        self.buffer.clear_style()

    def on_button_save__clicked(self, *args):
        self.post("Saving...")
        dialog = ModalDialog("Commit message")
        entry = gtk.Entry()
        minor = gtk.CheckButton("Minor")
        dialog.vbox.add(gtk.Label("Your attention to detail\nIs greatly appreciated"))
        dialog.vbox.add(entry)
        dialog.vbox.add(minor)
        dialog.show_all()
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            text = self.buffer.process_text()
            self.put_page(text, entry.get_text(), minor.get_active())
            self.get_htmlview(self.current)
            self.get_versions(self.current)
            self.post("Saved")
        dialog.destroy()

    # unused stuff
    def request_url(self, document, url, stream):
        f = simplebrowser.open_url(url)
        stream.write(f.read())

    def setup_htmlview_gtkhtml(self):
        # XXX not used now
        self.document = gtkhtml2.Document()
        self.document.connect('request_url', self.request_url)
        self.htmlview = gtkhtml2.View()
        self.htmlview.set_document(self.document)


    def setup_sourceview_gtksourceview(self):
        # XXX not used now
        self.buffer = gtksourceview.Buffer(table)
        self.editor = gtksourceview.View(self.buffer)
        if True:
            self.editor.set_show_line_numbers(True)
            lm = gtksourceview.LanguageManager()
            self.editor.set_indent_on_tab(True)
            self.editor.set_indent_width(4)
            self.editor.set_property("auto-indent", True)
            self.editor.set_property("highlight-current-line", True)
            self.editor.set_insert_spaces_instead_of_tabs(True)
            lang = lm.get_language("python")
            self.buffer.set_language(lang)
            self.buffer.set_highlight_syntax(True)
Example #13
0
	def __init__(self):
		## FIXME: The GUI should appear straight away, connecting should
		## happen after!
		# Set up the main window
		self.window = gtk.Window()
		self.window.set_title("PubSub Browser")
		self.window.set_default_size(400, 400)
		self.window.connect("destroy", self.quit)

		# Divide it vertically
		self.vbox = gtk.VBox()
		self.window.add(self.vbox)

		# This holds the location entry and the Get button
		self.top_box = gtk.HBox()
		self.vbox.pack_start(self.top_box, expand=False)

		self.location_label = gtk.Label("Server:")
		self.top_box.pack_start(self.location_label, expand=False)

		# This is where the server location is given
		self.location_entry = gtk.Entry()
		self.top_box.pack_start(self.location_entry)

		# This button run get_button_released to fetch the server's nodes
		self.get_button = gtk.Button(label="Get")
		self.get_button.connect("released", self.get_button_released)
		self.top_box.pack_end(self.get_button, expand=False)

		# Draw the tree using Kiwi, since plain GTK is a pain :P

		# The attribute is the data, ie. a Column looking for attribute
		# "foo", when appended by an object bar, will show bar.foo

		# We can put multiple things into a column (eg. an icon and a
		# label) by making 2 columns and passing the first to the second
		self.tree_columns = [\
			Column(attribute='icon', title='Nodes', use_stock=True, \
			justify=gtk.JUSTIFY_LEFT, icon_size=gtk.ICON_SIZE_MENU), \
			Column(attribute='name', justify=gtk.JUSTIFY_LEFT, column='icon')]
		self.tree_columns[0].expand = False
		self.tree_columns[1].expand = False
		self.tree_view = ObjectTree(self.tree_columns)
		self.tree_view.connect("selection-changed", self.selection_changed)
		self.vbox.pack_start(self.tree_view)

		# This holds the Add button and the Delete button
		self.bottom_box = gtk.HBox()
		self.vbox.pack_end(self.bottom_box, expand=False)

		# Make the Delete button, which runs the delete_button_released method
		self.delete_button = gtk.Button(stock=gtk.STOCK_REMOVE)
		try:
			# Attempt to change the label of the stock button
			delete_label = self.delete_button.get_children()[0]
			delete_label = delete_label.get_children()[0].get_children()[1]
			delete_label = delete_label.set_label("Delete Selection")
		except:
			# If it fails then just go back to the default
			self.delete_button = gtk.Button(stock=gtk.STOCK_REMOVE)
		self.delete_button.connect("released", self.delete_button_released)
		self.delete_button.set_sensitive(False)
		self.bottom_box.pack_start(self.delete_button, expand=True)

		# Make the Properties button, which runs the properties_button_released method
		self.properties_button = gtk.Button(stock=gtk.STOCK_PROPERTIES)
		try:
			# Attempt to change the label of the stock button
			properties_label = self.properties_button.get_children()[0]
			properties_label = properties_label.get_children()[0].get_children()[1]
			properties_label = properties_label.set_label("Node Properties...")
		except:
			# If it fails then just go back to the default
			self.properties_button = gtk.Button(stock=gtk.STOCK_PROPERTIES)
		self.properties_button.connect("released", self.properties_button_released)
		self.properties_button.set_sensitive(False)
		self.bottom_box.pack_start(self.properties_button, expand=True)

		# Make the Add button, which runs the add_button_released method
		self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
		try:
			# Attempt to change the label of the stock button
			add_label = self.add_button.get_children()[0]
			add_label = add_label.get_children()[0].get_children()[1]
			add_label = add_label.set_label("Add Child...")
		except:
			# If it fails then just go back to the default
			self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_button.connect("released", self.add_button_released)
		self.add_button.set_sensitive(False)
		self.bottom_box.pack_end(self.add_button, expand=True)

		# This handles our XMPP connection. Feel free to change the JID
		# and password
		self.client = pubsubclient.PubSubClient("[email protected]", "test")

		# Using the tree to store everything seems to have a few
		# glitches, so we use a regular list as our definitive memory
		self.known = []
Example #14
0
class Window(object):
	"""This is the browser application."""

	def __init__(self):
		## FIXME: The GUI should appear straight away, connecting should
		## happen after!
		# Set up the main window
		self.window = gtk.Window()
		self.window.set_title("PubSub Browser")
		self.window.set_default_size(400, 400)
		self.window.connect("destroy", self.quit)

		# Divide it vertically
		self.vbox = gtk.VBox()
		self.window.add(self.vbox)

		# This holds the location entry and the Get button
		self.top_box = gtk.HBox()
		self.vbox.pack_start(self.top_box, expand=False)

		self.location_label = gtk.Label("Server:")
		self.top_box.pack_start(self.location_label, expand=False)

		# This is where the server location is given
		self.location_entry = gtk.Entry()
		self.top_box.pack_start(self.location_entry)

		# This button run get_button_released to fetch the server's nodes
		self.get_button = gtk.Button(label="Get")
		self.get_button.connect("released", self.get_button_released)
		self.top_box.pack_end(self.get_button, expand=False)

		# Draw the tree using Kiwi, since plain GTK is a pain :P

		# The attribute is the data, ie. a Column looking for attribute
		# "foo", when appended by an object bar, will show bar.foo

		# We can put multiple things into a column (eg. an icon and a
		# label) by making 2 columns and passing the first to the second
		self.tree_columns = [\
			Column(attribute='icon', title='Nodes', use_stock=True, \
			justify=gtk.JUSTIFY_LEFT, icon_size=gtk.ICON_SIZE_MENU), \
			Column(attribute='name', justify=gtk.JUSTIFY_LEFT, column='icon')]
		self.tree_columns[0].expand = False
		self.tree_columns[1].expand = False
		self.tree_view = ObjectTree(self.tree_columns)
		self.tree_view.connect("selection-changed", self.selection_changed)
		self.vbox.pack_start(self.tree_view)

		# This holds the Add button and the Delete button
		self.bottom_box = gtk.HBox()
		self.vbox.pack_end(self.bottom_box, expand=False)

		# Make the Delete button, which runs the delete_button_released method
		self.delete_button = gtk.Button(stock=gtk.STOCK_REMOVE)
		try:
			# Attempt to change the label of the stock button
			delete_label = self.delete_button.get_children()[0]
			delete_label = delete_label.get_children()[0].get_children()[1]
			delete_label = delete_label.set_label("Delete Selection")
		except:
			# If it fails then just go back to the default
			self.delete_button = gtk.Button(stock=gtk.STOCK_REMOVE)
		self.delete_button.connect("released", self.delete_button_released)
		self.delete_button.set_sensitive(False)
		self.bottom_box.pack_start(self.delete_button, expand=True)

		# Make the Properties button, which runs the properties_button_released method
		self.properties_button = gtk.Button(stock=gtk.STOCK_PROPERTIES)
		try:
			# Attempt to change the label of the stock button
			properties_label = self.properties_button.get_children()[0]
			properties_label = properties_label.get_children()[0].get_children()[1]
			properties_label = properties_label.set_label("Node Properties...")
		except:
			# If it fails then just go back to the default
			self.properties_button = gtk.Button(stock=gtk.STOCK_PROPERTIES)
		self.properties_button.connect("released", self.properties_button_released)
		self.properties_button.set_sensitive(False)
		self.bottom_box.pack_start(self.properties_button, expand=True)

		# Make the Add button, which runs the add_button_released method
		self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
		try:
			# Attempt to change the label of the stock button
			add_label = self.add_button.get_children()[0]
			add_label = add_label.get_children()[0].get_children()[1]
			add_label = add_label.set_label("Add Child...")
		except:
			# If it fails then just go back to the default
			self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_button.connect("released", self.add_button_released)
		self.add_button.set_sensitive(False)
		self.bottom_box.pack_end(self.add_button, expand=True)

		# This handles our XMPP connection. Feel free to change the JID
		# and password
		self.client = pubsubclient.PubSubClient("[email protected]", "test")

		# Using the tree to store everything seems to have a few
		# glitches, so we use a regular list as our definitive memory
		self.known = []

	def selection_changed(self, list, object):
		self.add_button.set_sensitive(True)
		if type(object) == type(Node()):
			self.delete_button.set_sensitive(True)
			self.properties_button.set_sensitive(True)
		elif type(object) == type(Server()):
			self.delete_button.set_sensitive(False)
			self.properties_button.set_sensitive(False)

	def get_button_released(self, arg):
		"""This is run when the Get button is pressed. It adds the given
		server to the tree and runs get_nodes with that server."""
		listed_server = False		# Assume this server is not listed
		# Check every row of the tree to see if it matches given server
		for known_server in self.tree_view:
			if type(known_server) == type(Server()) and \
				self.location_entry.get_text() == str(known_server):
				listed_server = True		# True if server is listed
		# If we didn't find the server in the tree then add it
		if not listed_server:
			server = Server(name=self.location_entry.get_text())
			server.icon = gtk.STOCK_NETWORK
			self.tree_view.append(None, server)
			self.known.append(server)
		# Get the PubSub nodes on this server
		self.client.get_nodes(self.location_entry.get_text(), None, return_function=self.handle_incoming)

	def handle_incoming(self, nodes):
		# Go through each new node
		for node in nodes:
			# Assume we do not already know about this node
			node_is_known = False
			# Go through each node that we know about
			for known_entry in self.known:
				# See if this node is the same as the known node being checked
				if known_entry.name == node.name:	## FIXME: Needs to check server
					node_is_known = True
			if not node_is_known:
				parent = None
				for known_entry in self.known:
					if known_entry.name == node.parent.name:		## FIXME: Needs to check server
						parent = known_entry

				self.known.append(node)
				self.tree_view.append(parent, node)

				node.get_information(self.client, self.handle_information)

			node.get_sub_nodes(self.client, self.handle_incoming)

	def handle_information(self, node):
		known = False
		if node.type == 'leaf':
			if node.name is not None and node.server is not None:
				for known_entry in self.known:
					if known_entry.name == node.name:
						known_entry.set_type('leaf')
						known_entry.icon = gtk.STOCK_FILE
		elif node.type == 'collection':
			if node.name is not None and node.server is not None:
				for known_entry in self.known:
					if known_entry.name == node.name and known_entry.server == node.server:
						known_entry.set_type('collection')
						known_entry.icon = gtk.STOCK_DIRECTORY
			node.get_sub_nodes(self.client, self.handle_incoming)

	def handle_node_creation(self, return_value):
		if return_value == 0:
			self.tree_view.get_selected().get_sub_nodes(self.client, self.handle_incoming)
		else:
			print return_value

	def delete_button_released(self, args):
		to_delete = self.tree_view.get_selected()
		if type(to_delete) == type(Node()):
			self.client.delete_a_node(to_delete.server, str(to_delete), return_function=self.handle_deleted)

	def handle_deleted(self, return_value):
		if return_value == 0:
			deleted = self.tree_view.get_selected()
			self.tree_view.remove(deleted)
			self.known.remove(deleted)
		else:
			print return_value

	def add_button_released(self, args):
		self.add_window = {}
		self.add_window["parent"] = self.tree_view.get_selected()
		self.add_window["window"] = gtk.Window()
		self.add_window["window"].set_title("Add new node to " + self.add_window["parent"].name)
		self.add_window["vbox"] = gtk.VBox()
		self.add_window["window"].add(self.add_window["vbox"])

		self.add_window["top_box"] = gtk.HBox()
		self.add_window["vbox"].pack_start(self.add_window["top_box"], expand=False)
		self.add_window["name_label"] = gtk.Label("Name:")
		self.add_window["name_entry"] = gtk.Entry()
		self.add_window["top_box"].pack_start(self.add_window["name_label"], expand=False)
		self.add_window["top_box"].pack_end(self.add_window["name_entry"], expand=True)

		self.add_window["bottom_box"] = gtk.HBox()
		self.add_window["vbox"].pack_end(self.add_window["bottom_box"], expand=False)
		self.add_window["add_button"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_window["add_button"].connect("released", self.add_add_released)
		self.add_window["bottom_box"].pack_end(self.add_window["add_button"], expand=False)

		self.add_window["middle_box"] = gtk.HBox()
		self.add_window["vbox"].pack_end(self.add_window["middle_box"], expand=False)
		self.add_window["type_label"] = gtk.Label("Type:")
		self.add_window["type_select"] = gtk.combo_box_new_text()
		self.add_window["type_select"].append_text("Leaf")
		self.add_window["type_select"].append_text("Collection")
		self.add_window["middle_box"].pack_start(self.add_window["type_label"], expand=False)
		self.add_window["middle_box"].pack_end(self.add_window["type_select"], expand=True)

		self.add_window["window"].show_all()

	def add_add_released(self, args):
		name = self.add_window["name_entry"].get_text()
		node_type = self.add_window["type_select"].get_active_text()
		parent = self.add_window["parent"]
		self.add_node(name, node_type, parent)
		self.add_window["window"].destroy()
		del(self.add_window)

	def add_node(self, name, node_type, parent):
		"""Request a new child node of parent. For top-level a node
		parent should be a Server. node_type is either "leaf" or
		"collection"."""
		# This half runs if the parent is a Server
		if type(parent) == type(pubsubclient.Server()):
			# Request a top-level leaf node
			if node_type == 'Leaf':
				self.client.get_new_leaf_node(parent, \
					self.add_window["name_entry"].get_text(), None, None, return_function=self.handle_node_creation)
			# Request a top-level collection node
			elif node_type == 'Collection':
				self.client.get_new_collection_node(parent, \
					self.add_window["name_entry"].get_text(), None, None, return_function=self.handle_node_creation)

		# This half runs if the parent is a Node
		elif type(parent) == type(pubsubclient.Node()):
			# Request a child leaf node
			if node_type == 'Leaf':
				self.client.get_new_leaf_node(parent.server, \
					self.add_window["name_entry"].get_text(), parent, None, return_function=self.handle_node_creation)
			# Request a child collection node
			elif node_type == 'Collection':
				self.client.get_new_collection_node(parent.server, \
					self.add_window["name_entry"].get_text(), parent, None, return_function=self.handle_node_creation)

	def properties_button_released(self, args):
		## FIXME: This should allow multiple properties windows to be open at once
		# Setup a window containing a notebook
		self.properties_window = {}
		self.properties_window["node"] = self.tree_view.get_selected()
		self.properties_window["window"] = gtk.Window()
		self.properties_window["window"].set_title("Properties of " + str(self.properties_window["node"]))
		self.properties_window["window"].set_default_size(350, 450)
		self.properties_window["notebook"] = gtk.Notebook()
		self.properties_window["window"].add(self.properties_window["notebook"])

		# Add the Metadata page
		self.properties_window["metadata_page"] = gtk.VBox()
		self.properties_window["metadata_label"] = gtk.Label("Metadata")
		self.properties_window["notebook"].append_page(self.properties_window["metadata_page"], tab_label=self.properties_window["metadata_label"])

		# Add the Affiliations page
		self.properties_window["affiliations_page"] = gtk.VBox()
		self.properties_window["affiliations_label"] = gtk.Label("Affiliations")
		self.properties_window["notebook"].append_page(self.properties_window["affiliations_page"], tab_label=self.properties_window["affiliations_label"])

		node = self.tree_view.get_selected()
		node.get_information(self.client, self.information_received)
		node.request_all_affiliated_entities(self.client, return_function=self.properties_received)

	def information_received(self, info_dict):
		# Generate the contents of the Metadata page
		## FIXME: It would be awesome if this were generated automatically from what is found :)
		# The Name entry
		self.properties_window["name_box"] = gtk.HBox()
		self.properties_window["metadata_page"].pack_start(self.properties_window["name_box"], expand=False)
		self.properties_window["name_label"] = gtk.Label("Name:")
		self.properties_window["name_box"].pack_start(self.properties_window["name_label"], expand=False)
		self.properties_window["name_entry"] = gtk.Entry()
		self.properties_window["name_entry"].set_text(str(self.properties_window["node"]))		# Default to Node's name
		self.properties_window["name_box"].pack_start(self.properties_window["name_entry"], expand=True)
		self.properties_window["name_set"] = gtk.Button(label="Set")
		self.properties_window["name_set"].connect("released", self.set_name)
		self.properties_window["name_box"].pack_end(self.properties_window["name_set"], expand=False)

		# The Title entry
		## FIXME: This should default to the node's title
		self.properties_window["title_box"] = gtk.HBox()
		self.properties_window["metadata_page"].pack_start(self.properties_window["title_box"], expand=False)
		self.properties_window["title_label"] = gtk.Label("Title:")
		self.properties_window["title_box"].pack_start(self.properties_window["title_label"], expand=False)
		self.properties_window["title_entry"] = gtk.Entry()
		self.properties_window["title_box"].pack_start(self.properties_window["title_entry"], expand=True)
		self.properties_window["title_set"] = gtk.Button(label="Set")
		self.properties_window["title_set"].connect("released", self.set_title)
		self.properties_window["title_box"].pack_end(self.properties_window["title_set"], expand=False)

	def properties_received(self, affiliation_dictionary):
		# Add a warning about affiliation status
		self.properties_window["warning_label"] = gtk.Label("Note that a Jabber ID can only be in one state at a time. Adding a Jabber ID to a category will remove it from the others. There must always be at least one owner.")
		self.properties_window["warning_label"].set_line_wrap(True)
		self.properties_window["affiliations_page"].pack_start(self.properties_window["warning_label"], expand=False)

		# Owners frame
		self.properties_window["owners_frame"] = gtk.Frame("Owners")
		self.properties_window["affiliations_page"].pack_start(self.properties_window["owners_frame"], expand=True)
		self.properties_window["owners_box"] = gtk.HBox()
		self.properties_window["owners_frame"].add(self.properties_window["owners_box"])

		# Owners list
		self.properties_window["owners_column"] = Column(attribute="name", title="Jabber ID")
		self.properties_window["owners"] = ObjectList([self.properties_window["owners_column"]])
		self.properties_window["owners_box"].pack_start(self.properties_window["owners"], expand=True)

		# Add Owner button
		self.properties_window["owners_buttons"] = gtk.VBox()
		self.properties_window["owners_box"].pack_end(self.properties_window["owners_buttons"], expand=False)
		self.properties_window["add_owner"] = gtk.Button(stock=gtk.STOCK_ADD)
		try:
			# Attempt to change the label of the stock button
			label = self.properties_window["add_owner"].get_children()[0]
			label = label.get_children()[0].get_children()[1]
			label = label.set_label("Add...")
		except:
			# If it fails then just go back to the default
			self.properties_window["add_owner"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.properties_window["add_owner"].connect("released", self.add_owner)
		self.properties_window["owners_buttons"].pack_start(self.properties_window["add_owner"], expand=False)

		# Remove Owner button
		self.properties_window["remove_owner"] = gtk.Button(stock=gtk.STOCK_REMOVE)
		self.properties_window["remove_owner"].connect("released", self.remove_owner)
		self.properties_window["owners_buttons"].pack_end(self.properties_window["remove_owner"], expand=False)

		# Publishers frame
		self.properties_window["publishers_frame"] = gtk.Frame("Publishers")
		self.properties_window["affiliations_page"].pack_start(self.properties_window["publishers_frame"], expand=True)
		self.properties_window["publishers_box"] = gtk.HBox()
		self.properties_window["publishers_frame"].add(self.properties_window["publishers_box"])

		# Add Publisher button
		self.properties_window["publishers_buttons"] = gtk.VBox()
		self.properties_window["publishers_box"].pack_end(self.properties_window["publishers_buttons"], expand=False)
		self.properties_window["add_publisher"] = gtk.Button(stock=gtk.STOCK_ADD)
		try:
			# Attempt to change the label of the stock button
			label = self.properties_window["add_publisher"].get_children()[0]
			label = label.get_children()[0].get_children()[1]
			label = label.set_label("Add...")
		except:
			# If it fails then just go back to the default
			self.properties_window["add_publisher"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.properties_window["add_publisher"].connect("released", self.add_publisher)
		self.properties_window["publishers_buttons"].pack_start(self.properties_window["add_publisher"], expand=False)

		# Remove Publisher button
		self.properties_window["remove_publisher"] = gtk.Button(stock=gtk.STOCK_REMOVE)
		self.properties_window["remove_publisher"].connect("released", self.remove_publisher)
		self.properties_window["publishers_buttons"].pack_end(self.properties_window["remove_publisher"], expand=False)

		# Publishers list
		self.properties_window["publishers_column"] = Column(attribute="name", title="Jabber ID")
		self.properties_window["publishers"] = ObjectList([self.properties_window["publishers_column"]])
		self.properties_window["publishers_box"].pack_start(self.properties_window["publishers"], expand=True)

		# Outcasts frame
		self.properties_window["outcasts_frame"] = gtk.Frame("Outcasts")
		self.properties_window["affiliations_page"].pack_start(self.properties_window["outcasts_frame"], expand=True)
		self.properties_window["outcasts_box"] = gtk.HBox()
		self.properties_window["outcasts_frame"].add(self.properties_window["outcasts_box"])

		# Add Outcast button
		self.properties_window["outcasts_buttons"] = gtk.VBox()
		self.properties_window["outcasts_box"].pack_end(self.properties_window["outcasts_buttons"], expand=False)
		self.properties_window["add_outcast"] = gtk.Button(stock=gtk.STOCK_ADD)
		try:
			# Attempt to change the label of the stock button
			label = self.properties_window["add_outcast"].get_children()[0]
			label = label.get_children()[0].get_children()[1]
			label = label.set_label("Add...")
		except:
			# If it fails then just go back to the default
			self.properties_window["add_outcast"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.properties_window["add_outcast"].connect("released", self.add_outcast)
		self.properties_window["outcasts_buttons"].pack_start(self.properties_window["add_outcast"], expand=False)

		# Remove Outcast button
		self.properties_window["remove_outcast"] = gtk.Button(stock=gtk.STOCK_REMOVE)
		self.properties_window["remove_outcast"].connect("released", self.remove_outcast)
		self.properties_window["outcasts_buttons"].pack_end(self.properties_window["remove_outcast"], expand=False)

		# Outcasts list
		self.properties_window["outcasts_column"] = Column(attribute="name", title="Jabber ID")
		self.properties_window["outcasts"] = ObjectList([self.properties_window["outcasts_column"]])
		self.properties_window["outcasts_box"].pack_start(self.properties_window["outcasts"], expand=True)

		self.properties_window["window"].show_all()

		if "owner" in affiliation_dictionary.keys():
			for jid in affiliation_dictionary["owner"]:
				self.properties_window["owners"].append(jid)
		if "publisher" in affiliation_dictionary.keys():
			for jid in affiliation_dictionary["publisher"]:
				self.properties_window["publishers"].append(jid)
		if "outcast" in affiliation_dictionary.keys():
			for jid in affiliation_dictionary["outcast"]:
				self.properties_window["outcasts"].append(jid)

	def set_name(self, args):
		pass

	def set_title(self, args):
		pass

	def add_owner(self, args):
		self.add_owner_window = {}
		self.add_owner_window["window"] = gtk.Window()
		self.add_owner_window["window"].set_title("Add owner to " + str(self.tree_view.get_selected()))
		self.add_owner_window["box"] = gtk.HBox()
		self.add_owner_window["window"].add(self.add_owner_window["box"])
		self.add_owner_window["jid_label"] = gtk.Label("Jabber ID:")
		self.add_owner_window["box"].pack_start(self.add_owner_window["jid_label"], expand=False)
		self.add_owner_window["jid_entry"] = gtk.Entry()
		self.add_owner_window["box"].pack_start(self.add_owner_window["jid_entry"], expand=False)
		self.add_owner_window["add_button"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_owner_window["add_button"].connect("released", self.add_owner_send)
		self.add_owner_window["box"].pack_end(self.add_owner_window["add_button"], expand=False)
		self.add_owner_window["window"].show_all()

	def add_owner_send(self, args):
		self.add_owner_window["jid"] = JID(self.add_owner_window["jid_entry"].get_text())
		self.tree_view.get_selected().modify_affiliations(self.client, {self.add_owner_window["jid"]:"owner"}, self.owner_added)

	def owner_added(self, reply):
		if reply == 0:
			self.properties_window["owners"].append(self.add_owner_window["jid"])
			for jid in self.properties_window["publishers"]:
				if str(jid) == str(self.add_owner_window["jid"]):
					self.properties_window["publishers"].remove(jid)
			for jid in self.properties_window["outcasts"]:
				if str(jid) == str(self.add_owner_window["jid"]):
					self.properties_window["outcasts"].remove(jid)
		else:
			print "Error"
		self.add_owner_window["window"].destroy()
		del self.add_owner_window

	def remove_owner(self, args):
		self.tree_view.get_selected().modify_affiliations(self.client, {self.properties_window["owners"].get_selected():"none"}, self.owner_removed)

	def owner_removed(self, reply):
		if reply == 0:
			self.properties_window["owners"].remove(self.properties_window["owners"].get_selected())
		else:
			print "Error"

	def add_publisher(self, args):
		self.add_publisher_window = {}
		self.add_publisher_window["window"] = gtk.Window()
		self.add_publisher_window["window"].set_title("Add publisher to " + str(self.tree_view.get_selected()))
		self.add_publisher_window["hbox"] = gtk.HBox()
		self.add_publisher_window["window"].add(self.add_publisher_window["hbox"])
		self.add_publisher_window["jid_label"] = gtk.Label("Jabber ID:")
		self.add_publisher_window["hbox"].pack_start(self.add_publisher_window["jid_label"], expand=False)
		self.add_publisher_window["jid_entry"] = gtk.Entry()
		self.add_publisher_window["hbox"].pack_start(self.add_publisher_window["jid_entry"], expand=False)
		self.add_publisher_window["add_button"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_publisher_window["add_button"].connect("released", self.add_publisher_send)
		self.add_publisher_window["hbox"].pack_end(self.add_publisher_window["add_button"], expand=False)
		self.add_publisher_window["window"].show_all()

	def add_publisher_send(self, args):
		self.add_publisher_window["jid"] = JID(self.add_publisher_window["jid_entry"].get_text())
		self.tree_view.get_selected().modify_affiliations(self.client, {self.add_publisher_window["jid"]:"publisher"}, self.publisher_added)

	def publisher_added(self, reply):
		if reply == 0:
			self.properties_window["publishers"].append(self.add_publisher_window["jid"])
			for jid in self.properties_window["owners"]:
				if str(jid) == str(self.add_publisher_window["jid"]):
					self.properties_window["owners"].remove(jid)
			for jid in self.properties_window["outcasts"]:
				if str(jid) == str(self.add_publisher_window["jid"]):
					self.properties_window["outcasts"].remove(jid)
		else:
			print "Error"
		self.add_publisher_window["window"].destroy()
		del self.add_publisher_window

	def remove_publisher(self, args):
		self.tree_view.get_selected().modify_affiliations(self.client, {self.properties_window["publishers"].get_selected():"none"}, self.publisher_removed)

	def publisher_removed(self, reply):
		if reply == 0:
			self.properties_window["publishers"].remove(self.properties_window["publishers"].get_selected())
		else:
			print "Error"

	def add_outcast(self, args):
		self.add_outcast_window = {}
		self.add_outcast_window["window"] = gtk.Window()
		self.add_outcast_window["window"].set_title("Add outcast to " + str(self.tree_view.get_selected()))
		self.add_outcast_window["hbox"] = gtk.HBox()
		self.add_outcast_window["window"].add(self.add_outcast_window["hbox"])
		self.add_outcast_window["jid_label"] = gtk.Label("Jabber ID:")
		self.add_outcast_window["hbox"].pack_start(self.add_outcast_window["jid_label"], expand=False)
		self.add_outcast_window["jid_entry"] = gtk.Entry()
		self.add_outcast_window["hbox"].pack_start(self.add_outcast_window["jid_entry"], expand=False)
		self.add_outcast_window["add_button"] = gtk.Button(stock=gtk.STOCK_ADD)
		self.add_outcast_window["add_button"].connect("released", self.add_outcast_send)
		self.add_outcast_window["hbox"].pack_end(self.add_outcast_window["add_button"], expand=False)
		self.add_outcast_window["window"].show_all()

	def add_outcast_send(self, args):
		self.add_outcast_window["jid"] = JID(self.add_outcast_window["jid_entry"].get_text())
		self.tree_view.get_selected().modify_affiliations(self.client, {self.add_outcast_window["jid"]:"outcast"}, self.outcast_added)

	def outcast_added(self, reply):
		if reply == 0:
			self.properties_window["outcasts"].append(self.add_outcast_window["jid"])
			for jid in self.properties_window["publishers"]:
				if str(jid) == str(self.add_outcast_window["jid"]):
					self.properties_window["publishers"].remove(jid)
			for jid in self.properties_window["owners"]:
				if str(jid) == str(self.add_outcast_window["jid"]):
					self.properties_window["owners"].remove(jid)
		else:
			print "Error"
		self.add_outcast_window["window"].destroy()
		del self.add_outcast_window

	def remove_outcast(self, args):
		self.tree_view.get_selected().modify_affiliations(self.client, {self.properties_window["outcasts"].get_selected():"none"}, self.outcast_removed)

	def outcast_removed(self, reply):
		if reply == 0:
			self.properties_window["outcasts"].remove(self.properties_window["outcasts"].get_selected())
		else:
			print "Error"

	def main(self):
		self.window.show_all()
		self.client.connect()
		#gobject.idle_add(self.idle_process, priority=gobject.PRIORITY_LOW)
		gobject.timeout_add(250, self.idle_process)
		gtk.main()

	def idle_process(self):
		"""A PubSubClient needs its process method run regularly. This
		method can be used to do that in gobject.timeout or idle_add."""
		self.client.process()
		return True

	def quit(self, arg):
		"""Exits the application. Runs when a signal to quit is received."""
		gtk.main_quit()
Example #15
0
class DokuwikiView(GladeDelegate):
    """
    A dokuwiki editor window
    """
    def __init__(self):
        GladeDelegate.__init__(self, gladefile="pydoku",
                          delete_handler=self.quit_if_last)
        self._icons = {}
        self.throbber_icon = Throbber(self.view.throbber)
        self.setup_wikitree()
        self.setup_wikislist()
        self.setup_attachments()
        self.setup_lastchanges()
        self.setup_side()
        self.setup_sourceview()
        self.setup_htmlview()
        self.page_edit = self.view.notebook1.get_nth_page(0)
        self.page_view = self.view.notebook1.get_nth_page(1)
        self.page_attach = self.view.notebook1.get_nth_page(2)
        self.show_all()
        if len(cfg.getChildren()):
            wiki = cfg.getChildren()[0]
            self.connect(wiki.url, wiki.user, wiki.password)
            self.wiki = wiki
            if wiki.current:
                self.load_page(wiki.current)

    # quit override to work with twisted
    def quit_if_last(self, *args):
        self.htmlview.destroy() # for some reason has to be deleted explicitly
        windows = [toplevel
               for toplevel in gtk.window_list_toplevels()
                   if toplevel.get_property('type') == gtk.WINDOW_TOPLEVEL]
        if len(windows) == 1:
            reactor.stop()

    # general interface functions
    def post(self, text):
        id = self.view.statusbar.get_context_id("zap")
        self.view.statusbar.push(id, text)

    # setup functions
    def setup_wikislist(self):
        columns = [Column('url',format_func=self.get_favicon,data_type=gtk.gdk.Pixbuf,icon_size=gtk.ICON_SIZE_SMALL_TOOLBAR)]
        self.wikislist = ObjectList(columns)
        columns.append(Column('url', title='Wiki', column='url'))
        self.wikislist.set_columns(columns)
        self.view.vbox2.pack_start(self.wikislist)
        self.view.vbox2.reorder_child(self.wikislist, 0)
        self.wikislist.add_list(cfg.getChildren())
        self.wikislist.connect("selection-changed", self.wiki_selected)
        threads.deferToThread(self.download_favicons, cfg)

    def download_favicons(self, cfg):
        for wiki in cfg.getChildren():
            self.download_favicon(wiki)

    def download_favicon(self, wiki):
        import urllib
        icon_url = wiki.url+"/lib/tpl/sidebar/images/favicon.ico"
        filename, headers = urllib.urlretrieve(icon_url, "/tmp/ico.ico")
        if headers["Content-Type"] == 'image/x-icon':
            self.add_favicon(wiki, filename)

    def get_favicon(self, wiki_url):
        return self._icons.get(wiki_url, page_icon)

    def add_favicon(self, wiki, filename):
        pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
        pixbuf = pixbuf.scale_simple(16,16,gtk.gdk.INTERP_BILINEAR)
        self._icons[wiki.url] = pixbuf
        self.objectlist.refresh()

    def setup_side(self):
        columns = ['sum', 'user', 'type', 'version', 'ip']
        columns = [Column(s) for s in columns]
        self.versionlist = ObjectList(columns)

        self.view.side_vbox.pack_start(gtk.Label('Version Log:'), False, False)
        self.view.side_vbox.add(self.versionlist)
        self.versionlist.connect("selection-changed", self.version_selected)

        self.view.side_vbox.pack_start(gtk.Label('BackLinks:'), False, False)
        self.backlinks = ObjectList([Column('name')])
        self.backlinks.connect("selection-changed", self.change_selected)
        self.view.side_vbox.add(self.backlinks)

    def setup_attachments(self):
        columns = ['id', 'size', 'lastModified', 'writable', 'isimg', 'perms']
        columns = [Column(s) for s in columns]
        self.attachmentlist = ObjectList(columns)

        self.view.attachments_vbox.add(self.attachmentlist)

    def setup_lastchanges(self):
        columns = ['name', 'author', 'lastModified', 'perms', 'version', 'size']
        columns = [Column(s) for s in columns]
        columns.append(Column('lastModified', sorted=True, order=gtk.SORT_DESCENDING))
        self.lastchangeslist = ObjectList(columns)
        self.lastchangeslist.connect("selection-changed", self.change_selected)

        self.view.side_vbox.add(self.lastchangeslist)


    def setup_wikitree(self):
        columns = ['id', 'lastModified', 'perms', 'size']
        columns = [Column(s) for s in columns]
        columns.insert(0, Column('icon', title='name', data_type=gtk.gdk.Pixbuf))
        self.objectlist = ObjectTree(columns)
        columns.insert(1, Column('name', column='icon'))
        self.objectlist.set_columns(columns)

        self.objectlist.connect("selection-changed", self.selected)
        self.view.vbox2.add(self.objectlist)

    def html_realized(self, widget):
        if self.wiki and self.wiki.current:
            self.get_htmlview(self.wiki.current)

    def setup_htmlview(self):
        self.htmlview = gtkmozembed.MozEmbed()
        self.view.html_scrolledwindow.add_with_viewport(self.htmlview)
        self.htmlview.connect('realize', self.html_realized)
        #self.htmlview.set_size_request(800,600)
        #self.htmlview.realize()
        #self.view.html_scrolledwindow.show_all()
        #self.htmlview.show()

    def setup_sourceview(self):
        self.buffer = DokuwikiBuffer(table)
        self.editor = gtksourceview.SourceView(self.buffer)
        #self.editor.set_show_line_numbers(True)
        accel_group = gtk.AccelGroup()
        self.get_toplevel().add_accel_group(accel_group)
        self.editor.add_accelerator("paste-clipboard", accel_group, ord('v'), gtk.gdk.CONTROL_MASK, 0)
        self.editor.add_accelerator("copy-clipboard", accel_group, ord('c'), gtk.gdk.CONTROL_MASK, 0)
        self.editor.add_accelerator("cut-clipboard", accel_group, ord('x'), gtk.gdk.CONTROL_MASK, 0)
        #self.editor = gtk.TextView(self.buffer)
        self.editor.set_left_margin(5)
        self.editor.set_right_margin(5)
        self.editor.set_wrap_mode(gtk.WRAP_WORD_CHAR)
        self.view.scrolledwindow1.add(self.editor)

        lm = gtksourceview.SourceLanguagesManager()
        langs = lm.get_available_languages()
        lang_diffs = filter(lambda s: s.get_name() == 'Diff', langs)
        if lang_diffs:
            self.buffer.set_language(lang_diffs[0])

    # dokuwiki operations
    def _getVersion(self):
        return self._rpc.dokuwiki.getVersion()

    def get_version(self):
        return threads.deferToThread(self._getVersion)

    def get_pagelist(self):
        print "getpagelist1"
        pages = self._rpc.wiki.getAllPages()
        self._sections = {}
        self.objectlist.clear()
        print "getpagelist1.5"
        print "PAGES",pages
        for page in pages:
            self.add_page(page)
        print "getpagelist2"
        self.view.new_page.set_sensitive(True)
        self.view.delete_page.set_sensitive(True)
        if self.wiki.current:
            self.set_selection(self.wiki.current)
        print "getpagelist3"
        # XXX
        self.get_recent_changes()
        print "getpagelist2"

    def _getRecentChanges(self):
        return self._rpc.wiki.getRecentChanges(int(time.time()-(60*60*24*7*12)))

    def _gotRecentChanges(self, changes):
        changes = [DictWrapper(s) for s in changes]
        self.lastchangeslist.add_list(changes)

    def get_recent_changes(self):
        self.callDeferred(self._getRecentChanges, self._gotRecentChanges)

    def get_attachments(self, ns):
        attachments = self._rpc.wiki.getAttachments(ns, {})
        attachments = [DictWrapper(s) for s in attachments]
        self.attachmentlist.add_list(attachments)

    def _getBackLinks(self, pagename):
        return self._rpc.wiki.getBackLinks(pagename)

    def _gotBackLinks(self, backlinks):
        backlinks = [Section(s) for s in backlinks]
        self.backlinks.add_list(backlinks)

    def get_backlinks(self, pagename):
        self.callDeferred(self._getBackLinks, self._gotBackLinks, pagename)

    def _getVersions(self, pagename):
        return self._rpc.wiki.getPageVersions(pagename, 0)

    def _gotVersions(self, versionlist):
        versionlist = [DictWrapper(s) for s in versionlist]
        self.versionlist.add_list(versionlist)

    def get_versions(self, pagename):
        self.callDeferred(self._getVersions, self._gotVersions, pagename)

    def _getHtmlData(self, pagename):
        text = self._rpc.wiki.getPageHTML(pagename)
        return text

    def _gotHtmlData(self, text):
        self.throbber_icon.stop()
        if not self.htmlview.window:
            return
        text = """<head><meta http-equiv="Content-Type" content="text/html;  charset=utf-8" />
        </head><body>"""+text+"</body>"
        self.htmlview.render_data(text, len(text), self.wiki.url, 'text/html')
        self.htmlview.realize()
        self.htmlview.show()

    def get_htmlview(self, pagename):
        self.throbber_icon.start()
        self.callDeferred(self._getHtmlData, self._gotHtmlData, pagename)
        #d.addErrback(self.someError)

        # XXX following is for gtkhtml (not used)
        #self.document.clear()
        #self.document.open_stream('text/html')
        #self.document.write_stream(text)
        #self.document.close_stream()

    def callDeferred(self, get_func, got_func, *args):
        d = threads.deferToThread(get_func, *args)
        d.addCallback(got_func)

    def _getEditText(self, pagename):
        return self._rpc.wiki.getPage(pagename)

    def _gotEditText(self, text):
        self.throbber_icon.stop()
        self.buffer.set_highlight(False)
        self.editor.set_editable(True)
        self.buffer.add_text(text)

    def _getDiffText(self, pagename, version, idx):
        return self._rpc.wiki.getPageVersion(pagename, version), idx

    def _gotDiffText(self, data):
        import difflib
        import StringIO
        text, idx = data
        self.textstack[idx] = text
        if not None in self.textstack:
            fromlines = self.textstack[0].split("\n")
            tolines = self.textstack[1].split("\n")
            diff_text = difflib.unified_diff(fromlines, tolines, "a", "b",
                                        self.versions[0],
                                        self.versions[1])
            self.throbber_icon.stop()
            self.buffer.clear()
            str_buffer = StringIO.StringIO()
            for line in diff_text:
                str_buffer.write(line+'\n')
            str_buffer.seek(0)
            self.buffer.add_text(str_buffer.read())
            self.buffer.set_highlight(True)
            self.editor.set_editable(False)

    def get_difftext(self, pagename, version, prev_version):
        self.throbber_icon.start()
        self.textstack = [None, None]
        self.versions = [version, prev_version]
        self.callDeferred(self._getDiffText, self._gotDiffText,
                                  pagename, prev_version, 0)
        self.callDeferred(self._getDiffText, self._gotDiffText,
                                  pagename, version, 1)


    def get_edittext(self, pagename):
        self.throbber_icon.start()
        self.callDeferred(self._getEditText, self._gotEditText, pagename)

    def put_page(self, text, summary, minor):
        pars = {}
        if summary:
            pars['sum'] = summary
        if minor:
            pars['minor'] = minor
        d = threads.deferToThread(self._rpc.wiki.putPage, self.wiki.current, text, pars)
        return d

    # put a page into the page tree
    def add_page(self, page):
      print page
      try:
        name = page["id"]
        path = name.split(":")
        prev = None
        for i, pathm in enumerate(path):
            if i == len(path)-1: # a page
                new = DictWrapper(page, pathm)
                self._sections[name] = new
                self.objectlist.append(prev, new, False)
            else: # a namespace
                part_path = ":".join(path[:i+1])
                if not part_path in self._sections:
                    new = Section(pathm, part_path)
                    self._sections[part_path] = new
                    self.objectlist.append(prev, new, False)
                else:
                    new = self._sections[part_path]
            prev = new
      except:
        traceback.print_exc()

    def expand_to(self, pagename):
        path = pagename.split(":")
        for i, pathm in enumerate(path):
            if not i == len(path)-1:
                section = self._sections[":".join(path[:i+1])]
                self.view.objectlist.expand(section)

    def set_selection(self, pagename):
        obj = self._sections[pagename]
        self.expand_to(pagename)
        self.view.objectlist.select(obj, True)
        #self.selected(widget, obj)

    # page selected callback
    def wiki_selected(self, widget, wiki):
        self.connect(wiki.url, wiki.user, wiki.password)
        self.objectlist.clear()
        self.versionlist.clear()
        self.lastchangeslist.clear()
        self.backlinks.clear()
        self._sections = {}
        self.wiki = wiki
        self.buffer.clear()
        if wiki.current:
            self.load_page(wiki.current)

    def version_selected(self, widget, object):
        # yes, the previous item is the next in the widget
        if object == None:
            return
        previous = widget.get_next(object)
        if not previous:
            return
        prev_version = previous.version
        self.get_difftext(self.wiki.current, int(object.version),
                          int(prev_version))

    def change_selected(self, widget, object):
        if not object:
            return
        self.set_selection(object.name)

    def selected(self, widget, object):
        if not object:
            return
        if isinstance(object, Section):
            self.get_attachments(object.id)
        if not isinstance(object, DictWrapper):
            return
        self.wiki.current = object.id
        cfg.save()
        self.load_page(object.id)

    def load_page(self, pagename):
        self.get_edittext(pagename)
        self.get_htmlview(pagename)
        self.get_backlinks(pagename)
        self.get_versions(pagename)

    # kiwi interface callbacks
    def on_view_edit__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_edit, gtk.Label('edit'), 0)
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_edit))

    def on_view_view__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_view, gtk.Label('view'), 1)
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_view))

    def on_view_attachments__toggled(self, widget):
        if widget.get_active():
            self.notebook1.insert_page(self.page_attach, gtk.Label('attach'))
        else:
            self.notebook1.remove_page(self.notebook1.page_num(self.page_attach))

    def on_view_extra__toggled(self, widget):
        if widget.get_active():
            self.backlinks.show()
            self.versionlist.show()
            self.view.hpaned2.set_position(self._prevpos)
        else:
            self.backlinks.hide()
            self.versionlist.hide()
            self._prevpos = self.view.hpaned2.get_position()
            self.view.hpaned2.set_position(self.view.hpaned2.allocation.width)

    def on_button_add__clicked(self, *args):
        dialog = ModalDialog("User Details")
        # prepare
        widgets = {}
        items = ["url","user", "password"]
        for i, item in enumerate(items):
            widgets[item] = gtk.Entry()
            if i == 2:
                widgets[item].set_visibility(False)
            hbox = gtk.HBox()
            hbox.pack_start(gtk.Label(item+': '))
            hbox.add(widgets[item])
            dialog.vbox.add(hbox)
        dialog.show_all()
        # run
        response = dialog.run()
        user = widgets['user'].get_text()
        password = widgets['password'].get_text()
        url = widgets['url'].get_text()
        dialog.destroy()
        if not response == gtk.RESPONSE_ACCEPT:
            return

        self.wiki = cfg.new(Dokuwiki, 
                    url=url,
                    user=user,
                    password=password)

        cfg.addChild(self.wiki)
        cfg.save()
        self.connect(url, user, password)

    def get_full_url(self, url, user, password):
      try:
        if user and password:
            split_url = url.split('://')
            proto = split_url[0]
            base_url = split_url[1]
            return proto + '://' + user + ':' + password + '@' + base_url
        return url
      except:
        traceback.print_exc()

    def connect(self, url, user, password):
        # following commented line is for gtkhtml (not used)
        #simplebrowser.currentUrl = self.view.url.get_text()
        # handle response
        self.post("Connecting to " + url)
        params = urlencode({'u':user, 'p':password})
        print self.get_full_url(url, user, password)
        fullurl = self.get_full_url(url, user, password) + "/lib/exe/xmlrpc.php?"+ params
        print "serverproxy1"
        self._rpc = ServerProxy(fullurl)
        print "serverproxy1"
        d = self.get_version()
        d.addCallback(self.connected)
        d.addErrback(self.error_connecting)

    def error_connecting(self, failure):
        self.post("Error connecting to " + self.wiki.url)
        print failure.getErrorMessage()

    def connected(self, version):
        print "connected1"
        self.view.version.set_text(version)
        print "connected1.5"
        self.get_pagelist()
        print "connected2"
        self.post("Connected")

    def on_delete_page__clicked(self, *args):
        dialog = ModalDialog("Are you sure?")
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            value = self._sections[self.wiki.current]
            sel = self.objectlist.remove(value)
            self._rpc.wiki.putPage(self.wiki.current, "", {})
            self.wiki.current = ''
            cfg.save()
        dialog.destroy()

    def on_new_page__clicked(self, *args):
        dialog = ModalDialog("Name for the new page")
        text_w = gtk.Entry()
        text_w.show()
        response = []
        dialog.vbox.add(text_w)
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            text = text_w.get_text()
            if text:
                self.wiki.current = text
                cfg.save()
                self.buffer.clear()
        dialog.destroy()

    def on_button_h1__clicked(self, *args):
        self.buffer.set_style('h1')

    def on_button_h2__clicked(self, *args):
        self.buffer.set_style('h2')

    def on_button_h3__clicked(self, *args):
        self.buffer.set_style('h3')

    def on_button_h4__clicked(self, *args):
        self.buffer.set_style('h4')

    def on_button_h5__clicked(self, *args):
        self.buffer.set_style('h5')

    def on_button_h6__clicked(self, *args):
        self.buffer.set_style('h6')

    def on_button_bold__clicked(self, *args):
        self.buffer.set_style('bold')

    def on_button_italic__clicked(self, *args):
        self.buffer.set_style('italic')

    def on_button_clear_style__clicked(self, *args):
        self.buffer.clear_style()

    def _pagePut(self, *args):
        if not self.wiki.current in self._sections:
            self.add_page({"id":self.wiki.current})
        self.get_htmlview(self.wiki.current)
        self.get_versions(self.wiki.current)
        self.post("Saved")

    def on_button_save__clicked(self, *args):
        """ Save button callback """
        dialog = ModalDialog("Commit message")
        entry = gtk.Entry()
        minor = gtk.CheckButton("Minor")
        dialog.vbox.add(gtk.Label("Your attention to detail\nis greatly appreciated"))
        dialog.vbox.add(entry)
        dialog.vbox.add(minor)
        dialog.show_all()
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            self.post("Saving...")
            text = self.buffer.process_text()
            self.throbber_icon.start()
            d = self.put_page(text, entry.get_text(), minor.get_active())
            d.addCallback(self._pagePut)
        dialog.destroy()

    # unused stuff
    def request_url(self, document, url, stream):
        f = simplebrowser.open_url(url)
        stream.write(f.read())

    def setup_htmlview_gtkhtml(self):
        # XXX not used now
        self.document = gtkhtml2.Document()
        self.document.connect('request_url', self.request_url)
        self.htmlview = gtkhtml2.View()
        self.htmlview.set_document(self.document)
Example #16
0
import gtk

from kiwi.ui.objectlist import Column, ObjectTree


class Fruit:
    def __init__(self, name, price):
        self.name = name
        self.price = price


class FruitDesc:
    def __init__(self, name):
        self.name = name

fruits = ObjectTree([Column('name', data_type=str),
                     Column('price', data_type=int)])

for name, price in [('Apple', 4),
                    ('Pineapple', 2),
                    ('Kiwi', 8),
                    ('Banana', 3),
                    ('Melon', 5)]:
    row = fruits.append(None, FruitDesc(name))
    fruits.append(row, Fruit('Before taxes', price * 0.25))
    fruits.append(row, Fruit('After taxes', price))

window = gtk.Window()
window.connect('delete-event', gtk.main_quit)
window.set_title('Fruits')
window.set_size_request(150, 180)
Example #17
0
class TreeDataTests(unittest.TestCase):
    def setUp(self):
        self.win = gtk.Window()
        self.win.set_default_size(400, 400)
        self.tree = ObjectTree([Column('name'), Column('age')])
        self.win.add(self.tree)
        refresh_gui()

    def tearDown(self):
        self.win.destroy()
        del self.win

    def testGetRoot(self):
        root = Person('Big Kahuna', 7000)
        child1 = Person('Craf Kahuna', 200)
        child2 = Person('Sorcerer Kahuna', 150)

        self.tree.append(None, root)
        self.tree.append(root, child1)
        self.tree.append(root, child2)

        test_root = self.tree.get_root(child1)
        self.assertEqual(test_root, root)
        test_root = self.tree.get_root(child2)
        self.assertEqual(test_root, root)
        test_root = self.tree.get_root(root)
        self.assertEqual(test_root, root)

    def testGetDescendants(self):
        root = Person('Big Kahuna', 7000)
        child1 = Person('Craf Kahuna', 200)
        child2 = Person('Sorcerer Kahuna', 150)

        self.tree.append(None, root)
        self.tree.append(root, child1)
        self.tree.append(child1, child2)

        test_descendants = self.tree.get_descendants(root)
        test_descendants.sort()
        self.assertEqual(test_descendants, [child1, child2])
        test_descendants = self.tree.get_descendants(child1)
        self.assertEqual(test_descendants, [child2])
        test_descendants = self.tree.get_descendants(child2)
        self.assertEqual(test_descendants, [])
Example #18
0
 def __init__(self, columns):
     ObjectTree.__init__(self, columns)
Example #19
0
class NoteUI(GladeSlaveDelegate):

	def __init__(self, parent, mo):
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		# Set up the user interface
		GladeSlaveDelegate.__init__(self, gladefile="mo_tab_notes", toplevel_name="window_main")
	
		noteColumns = [
			Column("summary", title='Title', data_type=str),
		]
		#self.treeview_note = ObjectList(noteColumns)
		self.treeview_note = ObjectTree(noteColumns)
		self.vbox_notelist.add(self.treeview_note)

		# Connect signals
		self.treeview_note.connect('row-activated', self.treeview_note__row_activated)
		self.treeview_note.connect('selection-changed', self.treeview_note__selection_changed)
		self.treeview_note.connect('key-press-event', self.treeview_note__key_press_event)

		self.refresh()

	def refresh(self):
		self.treeview_note.clear()

		for journal in self.mo.cal_model.get_journals():
			parent = self.mo.cal_model.get_model_by_uid(journal.get_related_to())
			self.treeview_note.append(parent, journal)

	def on_toolbutton_add__clicked(self, *args):
		journal = self.factory.journal()
		journal = miniorganizer.ui.NoteEditUI(self.mo, journal).run()
		if journal:
			self.mo.cal_model.add(journal)
			self.treeview_note.append(None, journal)
			self.parent.menuitem_save.set_sensitive(True)

	def on_toolbutton_addsub__clicked(self, *args):
		parent_journal = self.treeview_note.get_selected()
		journal = self.factory.journal(parent_journal)
		if miniorganizer.ui.NoteEditUI(self.mo, journal).run():
			self.mo.cal_model.add(journal)
			self.treeview_note.append(parent_journal, journal)
			self.treeview_note.expand(parent_journal)
			self.parent.menuitem_save.set_sensitive(True)
		
	def on_toolbutton_edit__clicked(self, *args):
		sel_note = self.treeview_note.get_selected()
		self.treeview_note__row_activated(self.treeview_note, sel_note)

	def on_toolbutton_remove__clicked(self, *args):
		sel_note = self.treeview_note.get_selected()
		if sel_note:
			children = self.mo.cal_model.get_models_related_by_uid(sel_note.get_uid())

			if children:
				response = dialogs.warning('This note contains sub-notes. Removing it will also remove the sub-notes. Is this what you want?', buttons=gtk.BUTTONS_YES_NO)
				if response != gtk.RESPONSE_YES:
					return

			self.mo.cal_model.delete(sel_note, True)
			self.treeview_note.remove(sel_note, True)
			self.parent.menuitem_save.set_sensitive(True)

	def treeview_note__selection_changed(self, list, selection):
		has_selection = selection is not None
		self.toolbutton_addsub.set_sensitive(has_selection)
		self.toolbutton_remove.set_sensitive(has_selection)
		self.toolbutton_edit.set_sensitive(has_selection)
	
	def treeview_note__row_activated(self, list, object):
		sel_note = self.treeview_note.get_selected()
		note = miniorganizer.ui.NoteEditUI(self.mo, sel_note).run()

	def treeview_note__key_press_event(self, treeview, event):
		if event.keyval == gtk.keysyms.Delete:
			self.on_toolbutton_remove__clicked()
Example #20
0
class GTKProject(SlaveDelegate):
    """A facade of kmos.types.Project so that
    pygtk can display in a TreeView.
    """
    def __init__(self, parent, menubar):
        self.project_data = ObjectTree([Column('name',
                                               use_markup=True,
                                               data_type=str,
                                               sorted=True),
                                        Column('info')])

        self.project_data.connect('row-activated', self.on_row_activated)
        self.model_tree = Project()
        self._set_treeview_hooks()

        self.menubar = menubar

        self.set_parent(parent)


        self.filename = ''

        self.undo_stack = UndoStack(
            self.model_tree.__repr__,
            self.import_xml_file,
            self.project_data.select,
            menubar,
            self.meta,
            'Initialization')

        SlaveDelegate.__init__(self, toplevel=self.project_data)

    def _set_treeview_hooks(self):
        """Fudge function to import to access function to kmos.types.Project
        to kmos.gui.GTKProject.
        """
        self.project_data.clear()
        # Meta
        self.meta = self.project_data.append(None, self.model_tree.meta)
        self.model_tree.meta = self.meta

        # Layer List
        self.model_tree.add_layer = self.add_layer
        self.layer_list = self.project_data.append(None,
                                   self.model_tree.layer_list)
        self.get_layers = lambda :\
            sorted(self.project_data.get_descendants(self.layer_list),
                   key=lambda x: x.name)
        self.model_tree.get_layers = self.get_layers
        self.lattice = self.layer_list

        # Parameter List
        self.parameter_list = self.project_data.append(None,
                                       self.model_tree.parameter_list)
        self.add_parameter = lambda parameter :\
            self.project_data.append(self.parameter_list, parameter)
        self.model_tree.add_parameter = self.add_parameter
        self.get_parameters = lambda :\
            sorted(self.project_data.get_descendants(self.parameter_list),
                   key=lambda x: x.name)
        self.model_tree.get_parameters = self.get_parameters

        # Species List
        self.species_list = self.project_data.append(None,
                                   self.model_tree.species_list)
        self.add_species = lambda species :\
            self.project_data.append(self.species_list, species)
        self.model_tree.add_species = self.add_species
        self.get_speciess = lambda :\
            sorted(self.project_data.get_descendants(self.species_list),
                   key=lambda x: x.name)
        self.model_tree.get_speciess = self.get_speciess


        # Process List
        self.process_list = self.project_data.append(None,
                                     self.model_tree.process_list)
        self.add_process = lambda process:\
            self.project_data.append(self.process_list, process)
        self.model_tree.add_process = self.add_process
        self.get_processes = lambda :\
            sorted(self.project_data.get_descendants(self.process_list),
                   key=lambda x: x.name)
        self.model_tree.get_processes = self.get_processes

        # Output List
        self.output_list = self.project_data.append(None,
                                self.model_tree.output_list)
        self.add_output = lambda output:\
            self.project_data.append(self.output_list, output)
        self.model_tree.add_output = self.add_output
        self.get_outputs = lambda : \
            sorted(self.project_data.get_descendants(self.output_list),
                   key=lambda x: x.name)
        self.model_tree.get_outputs = self.get_outputs

    def add_layer(self, layer):
        self.project_data.append(self.layer_list, layer)
        if len(self.get_layers()) == 1 :
            self.set_default_layer(layer.name)
            self.set_substrate_layer(layer.name)

    def set_default_species(self, species):
        self.model_tree.species_list.default_species = species

    def set_substrate_layer(self, layer):
        self.model_tree.layer_list.substrate_layer = layer

    def set_default_layer(self, layer):
        self.model_tree.layer_list.default_layer = layer

    def update(self, model):
        self.project_data.update(model)

    def on_row_activated(self, tree, data):
        if isinstance(data, Layer):
            data.active = not data.active

    def get_name(self):
        if self.filename:
            return os.path.basename(self.filename)
        else:
            return 'Untitled'

    def __repr__(self):
        return str(self.model_tree)

    def import_xml_file(self, filename):
        self.model_tree.import_xml_file(filename)
        self.expand_all()

    def expand_all(self):
        """Expand all list of the project tree
        """
        self.project_data.expand(self.species_list)
        self.project_data.expand(self.layer_list)
        self.project_data.expand(self.parameter_list)
        self.project_data.expand(self.process_list)
        self.project_data.expand(self.output_list)

    def on_key_press(self, _, event):
        """When the user hits the keyboard focusing the treeview
        this event is triggered. Right now the only supported function
        is to deleted the selected item
        """
        selection = self.project_data.get_selected()
        if gtk.gdk.keyval_name(event.keyval) == 'Delete':
            if(isinstance(selection, Species)
            or isinstance(selection, Process)
            or isinstance(selection, Parameter)
            or isinstance(selection, Layer)):
                if kiwi.ui.dialogs.yesno(
                    "Do you really want to delete '%s'?" \
                        % selection.name) == gtk.RESPONSE_YES:
                    self.project_data.remove(selection)

    def on_project_data__selection_changed(self, _, elem):
        """When a new item is selected in the treeview this function
        loads the main area of the window with the corresponding form
        and data.
        """
        slave = self.get_parent().get_slave('workarea')
        if slave:
            self.get_parent().detach_slave('workarea')
        if isinstance(elem, Layer):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Layer %s' % elem.name,
                                                               elem)
            form = LayerEditor(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Meta):
            self.undo_stack.start_new_action('Edit Meta', elem)
            meta_form = MetaForm(self.meta, self)
            self.get_parent().attach_slave('workarea', meta_form)
            meta_form.focus_toplevel()
            meta_form.focus_topmost()
        elif isinstance(elem, OutputList):
            self.undo_stack.start_new_action('Edit Output', elem)
            form = OutputForm(self.output_list, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Parameter):
            self.undo_stack.start_new_action('Edit Parameter %s' % elem.name,
                                                                   elem)
            form = ParameterForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Process):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Process %s' % elem.name,
                                                                 elem)
            form = ProcessForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, ProcessList):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Batch process editing', elem)
            form = BatchProcessForm(self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Species):
            self.undo_stack.start_new_action('Edit species', elem)
            form = SpeciesForm(elem, self.project_data)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, SpeciesList):
            self.undo_stack.start_new_action('Edit default species', elem)
            form = SpeciesListForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, LayerList):
            self.undo_stack.start_new_action('Edit lattice', elem)
            dimension = self.meta.model_dimension
            form = LatticeForm(elem, dimension, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        else:
            self.get_parent().toast('Not implemented, yet(%s).' % type(elem))
Example #21
0
 def __init__(self):
     ObjectTree.__init__(self)
     self.connect('double-click', self._on__double_click)
     self.connect('row-activated', self._on__row_activated)
     self.connect('right-click', self._on__right_click)
Example #22
0
class AdditionListSlave(SearchSlave):
    """A slave that offers a simple list and its management.

    This slave also has the option to display a small message right next to the
    buttons
    """

    domain = 'stoq'
    toplevel_name = gladefile = 'AdditionListSlave'
    widgets = ('add_button',
               'delete_button',
               'klist',
               'list_vbox',
               'edit_button')
    gsignal('before-edit-item', object, retval=object)
    gsignal('on-edit-item', object)
    gsignal('on-add-item', object)
    gsignal('before-delete-items', object)
    gsignal('after-delete-items')

    def __init__(self, store, columns=None, editor_class=None,
                 klist_objects=None, visual_mode=False, restore_name=None,
                 tree=False):
        """ Creates a new AdditionListSlave object

        :param store:         a store
        :param columns:       column definitions
        :type columns:        sequence of :class:`kiwi.ui.objectlist.Columns`
        :param editor_class:  the window that is going to be open when user
                              clicks on add_button or edit_button.
        :type: editor_class:  a :class:`stoqlib.gui.editors.BaseEditor` subclass
        :param klist_objects: initial objects to insert into the list
        :param visual_mode:   if we are working on visual mode, that means,
                              not possible to edit the model on this object
        type visual_mode:     bool
        :param restore_name:  the name used to save and restore the columns
                              on a cache system (e.g. pickle)
        :type restore_name:   basestring
        :param tree:          Indication of which kind of list we are adding.
                              If `True` ObjectTree otherwise ObjectList will be
                              added
        """
        columns = columns or self.get_columns()
        SearchSlave.__init__(self, columns=columns,
                             restore_name=restore_name,
                             store=store)
        self.tree = tree
        self.klist = ObjectTree() if tree else ObjectList()
        self.list_vbox.add(self.klist)
        self.list_vbox.show_all()

        if not self.columns:
            raise StoqlibError("columns must be specified")
        self.visual_mode = visual_mode
        self.store = store
        self.set_editor(editor_class)
        self._can_edit = True
        self._callback_id = None
        if self.visual_mode:
            self.hide_add_button()
            self.hide_edit_button()
            self.hide_del_button()
        items = klist_objects or self.get_items()
        self._setup_klist(items)
        self._update_sensitivity()

    def _setup_klist(self, klist_objects):
        self.klist.set_columns(self.columns)
        self.klist.set_selection_mode(gtk.SELECTION_MULTIPLE)
        if self.tree:
            (self.klist.append(obj.parent_item, obj) for obj in klist_objects)
        else:
            self.klist.add_list(klist_objects)
        if self.visual_mode:
            self.klist.set_sensitive(False)

    def _update_sensitivity(self, *args):
        if self.visual_mode:
            return
        can_delete = _can_edit = True
        objs = self.get_selection()
        if not objs:
            _can_edit = can_delete = False
        elif len(objs) > 1:
            _can_edit = False

        self.add_button.set_sensitive(True)
        self.edit_button.set_sensitive(_can_edit)
        self.delete_button.set_sensitive(can_delete)

    def _edit_model(self, model=None, parent=None):
        edit_mode = model
        result = self.emit('before-edit-item', model)
        if result is None:
            result = self.run_editor(model)

        if not result:
            return

        if edit_mode:
            self.emit('on-edit-item', result)
            self.klist.update(result)
        else:
            if self.tree:
                self.klist.append(parent, result)
            else:
                self.klist.append(result)
            # Emit the signal after we added the item to the list to be able to
            # check the length of the list in our validation callbacks.
            self.emit('on-add-item', result)

        # As we have a selection extended mode for kiwi list, we
        # need to unselect everything before select the new instance.
        self.klist.unselect_all()
        self.klist.select(result)
        self._update_sensitivity()

    def _edit(self):
        if not self._can_edit:
            return
        objs = self.get_selection()
        qty = len(objs)
        if qty != 1:
            raise SelectionError(
                ("Please select only one item before choosing Edit."
                 "\nThere are currently %d items selected") % qty)
        self._edit_model(objs[0])

    def _clear(self):
        objs = self.get_selection()
        qty = len(objs)
        if qty < 1:
            raise SelectionError('There are no objects selected')

        msg = stoqlib_ngettext(
            _('Delete this item?'),
            _('Delete these %d items?') % qty,
            qty)
        delete_label = stoqlib_ngettext(
            _("Delete item"),
            _("Delete items"),
            qty)

        keep_label = stoqlib_ngettext(
            _("Keep it"),
            _("Keep them"),
            qty)
        if not yesno(msg, gtk.RESPONSE_NO, delete_label, keep_label):
            return
        self.emit('before-delete-items', objs)
        if qty == len(self.klist):
            self.klist.clear()
        else:
            for obj in objs:
                self.klist.remove(obj)
        self.klist.unselect_all()
        self._update_sensitivity()
        self.emit('after-delete-items')

    #
    # Hooks
    #

    def get_items(self):
        return []

    def get_columns(self):
        raise NotImplementedError("get_columns must be implemented in "
                                  "subclasses")

    def run_editor(self, model):
        """This can be overriden to provide a custom run_dialog line,
        or a conversion function for the model
        """
        if self._editor_class is None:
            raise TypeError(
                "%s cannot create or edit items without the editor_class "
                "argument set" % (self.__class__.__name__))

        self.store.savepoint('before_run_editor_addition')
        retval = run_dialog(self._editor_class, None, store=self.store,
                            model=model)
        if not retval:
            self.store.rollback_to_savepoint('before_run_editor_addition')
        return retval

    def delete_model(self, model):
        """Deletes a model, can be overridden in subclass
        :param model: model to delete
        """
        model.__class__.delete(model.id, store=self.store)

    #
    # Public API
    #

    def add_extra_button(self, label=None, stock=None):
        """Add an extra button on the this slave

        The extra button will be appended at the end of the button box,
        the one containing the add/edit/delete buttons

        :param label: label of the button, can be ``None`` if stock is passed
        :param stock: stock label of the button, can be ``None`` if label
            is passed
        :param returns: the button added
        :rtype: gtk.Button
        """
        if label is None and stock is None:
            raise TypeError("You need to provide a label or a stock argument")

        button = gtk.Button(label=label, stock=stock)
        button.set_property('can_focus', True)
        self.button_box.pack_end(button, False, False)
        button.show()

        return button

    def set_message(self, message, details_callback=None):
        """Display a simple message on a label, next to the add, edit, delete buttons
        :param message: a message with properly escaped markup
        """
        self.message_hbox.set_visible(True)
        self.message_details_button.set_visible(bool(details_callback))
        if details_callback:
            if self._callback_id:
                self.message_details_button.disconnect(self._callback_id)
            self._callback_id = self.message_details_button.connect(
                'clicked', details_callback)

        self.message_label.set_markup(message)

    def clear_message(self):
        self.message_hbox.set_visible(False)

    def get_selection(self):
        # XXX: add get_selected_rows and raise exceptions if not in the
        #      right mode
        if self.klist.get_selection_mode() == gtk.SELECTION_MULTIPLE:
            return self.klist.get_selected_rows()
        selection = self.klist.get_selected()
        if not selection:
            return []
        return [selection]

    def hide_add_button(self):
        self.add_button.hide()

    def hide_edit_button(self):
        self._can_edit = False
        self.edit_button.hide()

    def hide_del_button(self):
        self.delete_button.hide()

    def set_editor(self, editor_class):
        if editor_class and not issubclass(editor_class,
                                           (BaseEditor, BaseWizard)):
            raise TypeError("editor_class must be a BaseEditor subclass")
        self._editor_class = editor_class

    #
    # Signal handlers
    #

    def on_klist__row_activated(self, *args):
        self._edit()

    def on_klist__selection_changed(self, *args):
        self._update_sensitivity()

    def on_add_button__clicked(self, button):
        self._edit_model()

    def on_edit_button__clicked(self, button):
        self._edit()

    def on_delete_button__clicked(self, button):
        self._clear()
Example #23
0
 def setUp(self):
     self.win = gtk.Window()
     self.win.set_default_size(400, 400)
     self.tree = ObjectTree([Column('name'), Column('age')])
     self.win.add(self.tree)
     refresh_gui()
Example #24
0
class TodoUI(GladeSlaveDelegate):
	
	def __init__(self, parent, mo):
		self.parent = parent
		self.mo = mo
		self.factory = Factory()

		GladeSlaveDelegate.__init__(self, gladefile="mo_tab_todo", toplevel_name="window_main")

		# Set up the user interface
		todoColumns = [
			Column("done", title='Done', data_type=bool, editable=True),
			Column("summaryformat", title='Summary', use_markup=True),
			Column('priority', title='Priority', sorted=True, order=gtk.SORT_DESCENDING),
			ColoredColumn('due', title='Due', data_type=datetime.datetime, color='red', data_func=self.color_due),
			Column('created', title='Created', data_type=datetime.datetime)
		]
		self.treeview_todo = ObjectTree(todoColumns)
		self.vbox_todolist.add(self.treeview_todo)

		# Connect signals
		self.treeview_todo.connect('row-activated', self.treeview_todo__row_activated)
		self.treeview_todo.connect('selection-changed', self.treeview_todo__selection_changed)
		self.treeview_todo.connect('key-press-event', self.treeview_todo__key_press_event)

		self.refresh()

	def refresh(self):
		"""
		Refresh the entire todo tab. This clears everything and rebuilds it.
		Call this when todos are removed outside of this class.
		"""
		self.treeview_todo.clear()

		# Fill the user interface with information
		for todo in self.mo.cal_model.get_todos():
			parent = self.mo.cal_model.get_model_by_uid(todo.get_related_to())
			self.treeview_todo.append(parent, todo)
	
	def color_due(self, value):
		if not value:
			return(False)
		return(value < datetime.datetime.now())

	def on_toolbutton_add__clicked(self, *args):
		todo = self.factory.todo()
		todo = miniorganizer.ui.TodoEditUI(self.mo, todo).run()
		if todo:
			self.mo.cal_model.add(todo)
			self.treeview_todo.append(None, todo)
			self.parent.menuitem_save.set_sensitive(True)

	def on_toolbutton_edit__clicked(self, *args):
		sel_todo = self.treeview_todo.get_selected()
		self.treeview_todo__row_activated(self.treeview_todo, sel_todo)

	def on_toolbutton_remove__clicked(self, *args):
		sel_todo = self.treeview_todo.get_selected()
		if sel_todo:
			children = self.mo.cal_model.get_models_related_by_uid(sel_todo.get_uid())

			if children:
				response = dialogs.warning('This Todo contains sub-todos. Removing it will also remove the sub-todos. Is this what you want?', buttons=gtk.BUTTONS_YES_NO)
				if response != gtk.RESPONSE_YES:
					return

			self.treeview_todo.remove(sel_todo, True)
			self.mo.cal_model.delete(sel_todo, True)
			self.parent.menuitem_save.set_sensitive(True)

	def on_toolbutton_addsub__clicked(self, *args):
		parent_todo = self.treeview_todo.get_selected()
		todo = self.factory.todo(parent_todo)
		if miniorganizer.ui.TodoEditUI(self.mo, todo).run():
			self.mo.cal_model.add(todo)
			self.treeview_todo.append(parent_todo, todo)
			self.treeview_todo.expand(parent_todo)
			self.parent.menuitem_save.set_sensitive(True)
		
	def treeview_todo__selection_changed(self, list, selection):
		has_selection = selection is not None
		self.toolbutton_addsub.set_sensitive(has_selection)
		self.toolbutton_remove.set_sensitive(has_selection)
		self.toolbutton_edit.set_sensitive(has_selection)
	
	def treeview_todo__row_activated(self, list, object):
		todo = miniorganizer.ui.TodoEditUI(self.mo, object).run()
		self.parent.menuitem_save.set_sensitive(True)
	
	def treeview_todo__key_press_event(self, treeview, event):
		if event.keyval == gtk.keysyms.Delete:
			self.on_toolbutton_remove__clicked()