示例#1
0
文件: history.py 项目: thorhans/zimt
    def testSerialize(self):
        '''Test parsing the history from the state file'''
        uistate = INIConfigFile(VirtualFile([]))
        history = History(self.notebook, uistate)

        for page in self.pages:
            history.append(page)
        self.assertHistoryEquals(history, self.pages)
        self.assertCurrentEquals(history, self.pages[-1])

        # rewind 2
        for i in range(2):
            prev = history.get_previous()
            history.set_current(prev)

        # check state
        #~ import pprint
        #~ pprint.pprint(uistate)
        self.assertHistoryEquals(history, uistate['History']['list'])
        self.assertRecentEquals(history, uistate['History']['recent'])
        self.assertEqual(uistate['History']['current'], len(self.pages) - 3)

        # clone uistate by text
        lines = uistate.dump()
        newuistate = INIConfigFile(VirtualFile(lines))
        newuistate['History'].setdefault('list', [])
        newuistate['History'].setdefault('recent', [])
        newuistate['History'].setdefault('current', 0)

        # check new state
        self.assertHistoryEquals(
            history, [Path(t[0]) for t in newuistate['History']['list']])
        self.assertRecentEquals(
            history, [Path(t[0]) for t in newuistate['History']['recent']])
        self.assertEqual(newuistate['History']['current'], len(self.pages) - 3)

        # and compare resulting history object
        newhistory = History(self.notebook, newuistate)
        self.assertEqual(list(newhistory.get_history()),
                         list(history.get_history()))
        self.assertEqual(list(newhistory.get_recent()),
                         list(history.get_recent()))
        self.assertEqual(newhistory.get_current(), history.get_current())

        # Check recent is initialized if needed
        newuistate = INIConfigFile(VirtualFile(lines))
        newuistate['History'].setdefault('recent', [])
        newuistate['History'].pop('recent')
        newhistory = History(self.notebook, newuistate)

        self.assertEqual(list(newhistory.get_history()),
                         list(history.get_history()))
        self.assertEqual(list(newhistory.get_recent()),
                         list(history.get_recent()))
        self.assertEqual(newhistory.get_current(), history.get_current())
示例#2
0
    def __init__(self, cache_dir, config, folder, layout, index):
        '''Constructor
		@param cache_dir: a L{Folder} object used for caching the notebook state
		@param config: a L{NotebookConfig} object
		@param folder: a L{Folder} object for the notebook location
		@param layout: a L{NotebookLayout} object
		@param index: an L{Index} object
		'''
        self.folder = folder
        self.cache_dir = cache_dir
        self.state = INIConfigFile(cache_dir.file('state.conf'))
        self.config = config
        self.properties = config['Notebook']
        self.layout = layout
        self.index = index
        self._operation_check = NOOP

        self.readonly = not _iswritable(folder)

        if self.readonly:
            logger.info('Notebook read-only: %s', folder.path)

        self._page_cache = weakref.WeakValueDictionary()

        self.name = None
        self.icon = None
        self.document_root = None
        self.interwiki = None

        if folder.watcher is None:
            from zim.newfs.helpers import FileTreeWatcher
            folder.watcher = FileTreeWatcher()

        from .index import PagesView, LinksView, TagsView
        self.pages = PagesView.new_from_index(self.index)
        self.links = LinksView.new_from_index(self.index)
        self.tags = TagsView.new_from_index(self.index)

        def on_page_row_changed(o, row, oldrow):
            if row['name'] in self._page_cache:
                self._page_cache[
                    row['name']].haschildren = row['n_children'] > 0
                self.emit('page-info-changed', self._page_cache[row['name']])

        def on_page_row_deleted(o, row):
            if row['name'] in self._page_cache:
                self._page_cache[row['name']].haschildren = False
                self.emit('page-info-changed', self._page_cache[row['name']])

        self.index.update_iter.pages.connect('page-row-changed',
                                             on_page_row_changed)
        self.index.update_iter.pages.connect('page-row-deleted',
                                             on_page_row_deleted)

        self.connectto(self.properties, 'changed', self.on_properties_changed)
        self.on_properties_changed(self.properties)
示例#3
0
文件: history.py 项目: thorhans/zimt
    def testRobustness(self):
        '''Test history can deal with garbage data'''
        uistate = INIConfigFile(VirtualFile([]))
        uistate['History'].input({
            'list': 'FOOOO',
            'recent': [["BARRRR", 0]],
            'cursor': 'Not an integer',
        })

        with tests.LoggingFilter(logger='zim.config',
                                 message='Invalid config'):
            with tests.LoggingFilter(logger='zim.history',
                                     message='Could not parse'):
                history = History(self.notebook, uistate)
        self.assertEqual(list(history.get_history()), [])
        self.assertEqual(list(history.get_recent()), [])
        self.assertIsNone(history.get_current())
示例#4
0
	def parse(self, text):
		'''Parses the config and cache and populates the list

		Format is::

		  [NotebookList]
		  Default=uri1
		  1=uri1
		  2=uri2

		  [Notebook 1]
		  name=Foo
		  uri=uri1

		Then followed by more "[Notebook]" sections that are cache data

		@param text: a string or a list of lines
		'''
		# Format <= 0.60 was:
		#
		#  [NotebookList]
		#  Default=uri1
		#  uri1
		#  uri2
		#
		#  [Notebook]
		#  name=Foo
		#  uri=uri1


		if isinstance(text, str):
			text = text.splitlines(True)

		assert text[0].strip() == '[NotebookList]'

		# Backward compatibility, make valid INI file:
		# - make redundant [Notebook] sections numbered
		# - prefix lines without a key with a number
		n = 0
		l = 0
		for i, line in enumerate(text):
			if line.strip() == '[Notebook]':
				n += 1
				text[i] = '[Notebook %i]\n' % n
			elif line and not line.isspace()  \
			and not line.lstrip().startswith('[') \
			and not line.lstrip().startswith('#') \
			and not '=' in line:
				l += 1
				text[i] = ('%i=' % l) + line
		###

		config = INIConfigFile(VirtualFile(text))

		mylist = config['NotebookList']
		mylist.define(Default=String(None))
		mylist.define((k, String(None)) for k in list(mylist._input.keys())) # XXX

		for key, uri in list(config['NotebookList'].items()):
			if key == 'Default':
				continue

			section = config['Notebook %s' % key]
			section.define(
				uri=String(None),
				name=String(None),
				icon=String(None),
				mtime=String(None),
				interwiki=String(None)
			)
			if section['uri'] == uri:
				info = NotebookInfo(**section)
			else:
				info = NotebookInfo(uri)
			self.append(info)

		if 'Default' in config['NotebookList'] \
		and config['NotebookList']['Default']:
			self.set_default(config['NotebookList']['Default'])
示例#5
0
    def __init__(self,
                 notebook,
                 config,
                 page=None,
                 fullscreen=False,
                 geometry=None):
        '''Constructor
		@param notebook: the L{Notebook} to show in this window
		@param config: a C{ConfigManager} object
		@param page: a C{Path} object to open
		@param fullscreen: if C{True} the window is shown fullscreen,
		if C{None} the previous state is restored
		@param geometry: the window geometry as string in format
		"C{WxH+X+Y}", if C{None} the previous state is restored
		'''
        Window.__init__(self)
        self.notebook = notebook
        self.page = None  # will be set later by open_page
        self.navigation = NavigationModel(self)
        self.hideonclose = False

        self.config = config
        self.preferences = config.preferences['GtkInterface']
        self.preferences.define(
            toggle_on_ctrlspace=Boolean(False),
            remove_links_on_delete=Boolean(True),
            always_use_last_cursor_pos=Boolean(True),
        )
        self.preferences.connect('changed', self.do_preferences_changed)

        self.maximized = False
        self.isfullscreen = False
        self.connect_after('window-state-event',
                           self.__class__.on_window_state_event)

        # Hidden setting to force the gtk bell off. Otherwise it
        # can bell every time you reach the begin or end of the text
        # buffer. Especially specific gtk version on windows.
        # See bug lp:546920
        self.preferences.setdefault('gtk_bell', False)
        if not self.preferences['gtk_bell']:
            Gtk.rc_parse_string('gtk-error-bell = 0')

        self._block_toggle_panes = False
        self._sidepane_autoclose = False
        self._switch_focus_accelgroup = None

        # Catching this signal prevents the window to actually be destroyed
        # when the user tries to close it. The action for close should either
        # hide or destroy the window.
        def do_delete_event(*a):
            logger.debug('Action: close (delete-event)')
            self.close()
            return True  # Do not destroy - let close() handle it

        self.connect('delete-event', do_delete_event)

        # setup uistate
        if not hasattr(config, 'uistate'):
            config.uistate = INIConfigFile(
                notebook.cache_dir.file('state.conf'))
        self.uistate = self.config.uistate['MainWindow']

        self.history = History(notebook, config.uistate)

        # init uimanager
        self.uimanager = Gtk.UIManager()
        self.uimanager.add_ui_from_string('''
		<ui>
			<menubar name="menubar">
			</menubar>
			<toolbar name="toolbar">
			</toolbar>
		</ui>
		''')

        # setup menubar and toolbar
        self.add_accel_group(self.uimanager.get_accel_group())
        self.menubar = self.uimanager.get_widget('/menubar')
        self.toolbar = self.uimanager.get_widget('/toolbar')
        self.toolbar.connect('popup-context-menu', self.do_toolbar_popup)
        self.add_bar(self.menubar)
        self.add_bar(self.toolbar)

        self.pageview = PageView(self.notebook, config, self.navigation)
        self.connect_object('readonly-changed', PageView.set_readonly,
                            self.pageview)
        self.pageview.connect_after('textstyle-changed',
                                    self.on_textview_textstyle_changed)
        self.pageview.textview.connect_after('toggle-overwrite',
                                             self.on_textview_toggle_overwrite)
        self.pageview.textview.connect('link-enter', self.on_link_enter)
        self.pageview.textview.connect('link-leave', self.on_link_leave)

        self.add(self.pageview)

        # create statusbar
        self.statusbar = Gtk.Statusbar()
        self.statusbar.push(0, '<page>')
        self.add_bar(self.statusbar, start=False)
        self.statusbar.set_property('margin', 0)

        def statusbar_element(string, size):
            frame = Gtk.Frame()
            frame.set_shadow_type(Gtk.ShadowType.IN)
            self.statusbar.pack_end(frame, False, True, 0)
            label = Gtk.Label(label=string)
            label.set_size_request(size, 10)
            label.set_alignment(0.1, 0.5)
            frame.add(label)
            return label

        # specify statusbar elements right-to-left
        self.statusbar_style_label = statusbar_element('<style>', 100)
        self.statusbar_insert_label = statusbar_element('INS', 60)

        # and build the widget for backlinks
        self.statusbar_backlinks_button = \
         BackLinksMenuButton(self.notebook, self.open_page, status_bar_style=True)
        frame = Gtk.Frame()
        frame.set_shadow_type(Gtk.ShadowType.IN)
        self.statusbar.pack_end(frame, False, True, 0)
        frame.add(self.statusbar_backlinks_button)

        self.move_bottom_minimized_tabs_to_statusbar(self.statusbar)

        self.do_preferences_changed()

        self._geometry_set = False
        self._set_fullscreen = False
        if geometry:
            try:
                self.parse_geometry(geometry)
                self._geometry_set = True
            except:
                logger.exception('Parsing geometry string failed:')
        elif fullscreen:
            self._set_fullscreen = True

        # Init mouse settings
        self.preferences.setdefault('mouse_nav_button_back', 8)
        self.preferences.setdefault('mouse_nav_button_forw', 9)

        # Finish uimanager
        self._uiactions = UIActions(self, self.notebook, self.page,
                                    self.config, self.navigation)
        group = get_gtk_actiongroup(self._uiactions)
        self.uimanager.insert_action_group(group, 0)

        group = get_gtk_actiongroup(self.pageview)
        self.uimanager.insert_action_group(group, 0)

        group = get_gtk_actiongroup(self)
        group.add_actions(MENU_ACTIONS)
        self.uimanager.insert_action_group(group, 0)

        group.get_action('open_page_back').set_sensitive(False)
        group.get_action('open_page_forward').set_sensitive(False)

        fname = 'menubar.xml'
        self.uimanager.add_ui_from_string(data_file(fname).read())

        # Do this last, else menu items show up in wrong place
        self.pageview.notebook = self.notebook  # XXX
        self._customtools = CustomToolManagerUI(self.uimanager, self.config,
                                                self.pageview)
        self._insertedobjects = InsertedObjectUI(self.uimanager, self.pageview)
        # XXX: would like to do this in PageView itself, but need access to uimanager

        # Setup notebook signals
        notebook.connect('page-info-changed', self.do_page_info_changed)

        def move_away(o, path):
            # Try several options to get awaay
            actions = [
                self.open_page_back, self.open_page_parent, self.open_page_home
            ]
            while (path == self.page or self.page.ischild(path)) and actions:
                action = actions.pop(0)
                action()

        notebook.connect('deleted-page', move_away)  # after action

        def follow(o, path, newpath):
            if path == self.page:
                self.open_page(newpath)
            elif self.page.ischild(path):
                newpath = newpath + self.page.relname(path)
                self.open_page(newpath)
            else:
                pass

        notebook.connect('moved-page', follow)  # after action

        # init page
        page = page or self.history.get_current()
        if page:
            page = notebook.get_page(page)
            self.open_page(page)
        else:
            self.open_page_home()

        self.pageview.grab_focus()