コード例 #1
0
 def __init__(self, file):
     INIConfigFile.__init__(self, file)
     if os.name == 'nt':
         endofline = 'dos'
     else:
         endofline = 'unix'
     name = file.dir.basename if hasattr(file, 'dir') else file.parent(
     ).basename  # HACK zim.fs and zim.newfs compat
     self['Notebook'].define((
         ('version', String('.'.join(map(str, DATA_FORMAT_VERSION)))),
         ('name', String(name)),
         ('interwiki', String(None)),
         ('home', ConfigDefinitionByClass(Path('Home'))),
         ('icon',
          String(None)),  # XXX should be file, but resolves relative
         ('document_root',
          String(None)),  # XXX should be dir, but resolves relative
         ('short_links', Boolean(False)),
         ('shared', Boolean(True)),
         ('endofline', Choice(endofline, {'dos', 'unix'})),
         ('disable_trash', Boolean(False)),
         ('default_file_format', String('zim-wiki')),
         ('default_file_extension', String('.txt')),
         ('notebook_layout', String('files')),
     ))
コード例 #2
0
	def __init__(self, parent):
		Dialog.__init__(self, parent, _('Insert Code Block')) # T: dialog title
		self.result = (None, None, None)
		self.uistate.define(id=String(None))
		self.uistate.define(lang=String(None))
		self.uistate.define(line_numbers=Boolean(True))

		grid = Gtk.Grid()
		grid.set_column_spacing(5)
		grid.set_row_spacing(5)

		label = Gtk.Label(_('Syntax') + ':') # T: input label
		grid.add(label)

		self.combobox = Gtk.ComboBox.new_with_model_and_entry(self.init_combobox_model())
		self.combobox.set_entry_text_column(0)
		entry = self.combobox.get_child()
		entry.set_activates_default(True)  # Pressing enter will activate the default button (here: ok-button)

		completion = Gtk.EntryCompletion()
		completion.set_model(self.init_autocomplete_model())
		completion.set_text_column(0)
		completion.set_minimum_key_length(0)
		entry.set_completion(completion)

		defaultlang = self.init_default_language()
		if defaultlang:
			entry.set_text(defaultlang)

		self.combobox.connect("changed", self.on_combobox_changed)

		grid.attach(self.combobox, 1, 0, 1, 1)

		label = Gtk.Label(_('Id') + ':') # T: input label for object ID
		grid.attach(label, 0, 1, 1, 1)
		self.entry = InputEntry()
		grid.attach(self.entry, 1, 1, 1, 1)

		self.checkbox = Gtk.CheckButton(_('Display line numbers')) # T: input checkbox
		self.checkbox.set_active(self.uistate['line_numbers'])
		grid.attach(self.checkbox, 1, 2, 1, 1)

		self.vbox.add(grid)

		# Set ok button as default.
		self.btn_ok = self.get_widget_for_response(response_id=Gtk.ResponseType.OK)
		self.btn_ok.set_can_default(True)
		self.btn_ok.grab_default()
		self.btn_ok.set_sensitive(defaultlang is not None)
コード例 #3
0
    def __init__(self):
        assert self.name is not None
        assert self.label is not None
        self.object_attr = self.object_attr.copy()
        # Prevent referencing and modifying class attribute of parent class
        self.object_attr['type'] = String(self.name)

        # each inserted object has an id attribute usable as anchor for linking
        self.object_attr['id'] = String(None)

        for name in ('model_from_data', 'data_from_model', 'format'):
            orig = getattr(self, name)
            wrapper = getattr(self, '_' + name + '_wrapper')
            setattr(self, '_inner_' + name, orig)
            setattr(self, name, wrapper)
コード例 #4
0
ファイル: applications.py プロジェクト: hjq300/zim-wiki
	def check(self, value):
		# Only ascii chars allowed in these keys
		value = BaseString.check(self, value)
		if isinstance(value, unicode) \
		and value.encode('utf-8') != value:
			raise ValueError, 'ASCII string required'
		return value
コード例 #5
0
ファイル: imagegenerator.py プロジェクト: thorhans/zimt
class BackwardImageGeneratorObjectType(ImageGeneratorObjectType):
    '''Base class for backward compatible image generator objects.'''

    object_attr = {
        'src': String('_new_'),
    }

    scriptname = None
    imagefile_extension = None

    def model_from_data(self, notebook, page, attrib, data):
        generator = self.generator_klass(self.plugin, notebook, page)
        return BackwardImageGeneratorModel(notebook, page, generator, attrib,
                                           data, self.scriptname,
                                           self.imagefile_extension)

    def format(self, format, dumper, attrib, data):
        if data:
            logger.warn('Unexpected data in %s object: %r', attrib['type'],
                        data)

        try:
            return ImageGeneratorObjectType.format(self, format, dumper,
                                                   attrib, data)
        except ValueError:
            if attrib['type'].startswith('image+'):
                attrib = attrib.copy()
                attrib['type'] = attrib['type'][6:]
            return dumper.dump_img(IMAGE, attrib, None)
コード例 #6
0
    def do_response_ok(self):
        # Get dynamic tabs
        newpreferences = {}
        for form in list(self.forms.values()):
            for key, value in list(form.items()):
                section = form.preferences_sections[key]
                if not section in newpreferences:
                    newpreferences[section] = {}
                newpreferences[section][key] = value

        # Set font - special case, consider it a HACK
        customfont = newpreferences['GtkInterface'].pop('use_custom_font')
        if customfont:
            font = self.fontbutton.get_font_name()
        else:
            font = None

        text_style = self.config.get_config_dict('<profile>/style.conf')
        text_style['TextView'].define(font=String(None))
        text_style['TextView']['font'] = font
        #

        with self.preferences.block_signals('changed'):
            # note we do not block signal on section dicts
            for section in newpreferences:
                self.preferences[section].update(newpreferences[section])

        self.preferences.emit('changed')  # delayed emission

        return True
コード例 #7
0
ファイル: sourceview.py プロジェクト: robla/zim-desktop-wiki
class SourceViewObjectType(InsertedObjectTypeExtension):

	name = 'code'

	label = _('Code Block') # T: menu item

	object_attr = {
		'lang': String(None),
		'linenumbers': Boolean(True),
	}

	def __init__(self, plugin, objmap):
		self._widgets = WeakSet()
		self.preferences = plugin.preferences
		InsertedObjectTypeExtension.__init__(self, plugin, objmap)
		self.connectto(self.preferences, 'changed', self.on_preferences_changed)

	def new_model_interactive(self, parent, notebook, page):
		lang = InsertCodeBlockDialog(parent).run()
		if lang is None:
			raise ValueError # dialog cancelled
		else:
			attrib = self.parse_attrib({'lang': lang})
			return SourceViewBuffer(attrib, '')

	def model_from_data(self, notebook, page, attrib, text):
		return SourceViewBuffer(attrib, text)

	def data_from_model(self, buffer):
		return buffer.get_object_data()

	def create_widget(self, buffer):
		widget = SourceViewWidget(buffer)
		widget.set_preferences(self.preferences)
		self._widgets.add(widget)
		return widget

	def on_preferences_changed(self, preferences):
		for widget in self._widgets:
			widget.set_preferences(preferences)

	def format_html(self, dumper, attrib, data):
		# to use highlight.js add the following to your template:
		#<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/default.min.css">
		#<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
		#<script>hljs.initHighlightingOnLoad();</script>
		#Map GtkSourceView language ids match with Highlight.js language ids.
		#http://packages.ubuntu.com/precise/all/libGtkSource.0-common/filelist
		#http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html
		sh_map = {'dosbatch': 'dos'}
		sh_lang = sh_map[attrib['lang']] if attrib['lang'] in sh_map else attrib['lang']
		# TODO: some template instruction to be able to use other highlighters as well?
		output = ['<pre><code class="%s">' % html_encode(sh_lang)] # for syntaxhigligther
		#class="brush: language;" works with SyntaxHighlighter 2.0.278, 3 & 4
		#output = ['<pre class="brush: %s;">' % html_encode(sh_lang)] # for syntaxhigligther

		output.append(html_encode(data))
		output.append('</code></pre>\n')

		return output
コード例 #8
0
	def check(self, value):
		# Only ascii chars allowed in these keys
		value = BaseString.check(self, value)
		if isinstance(value, unicode) \
		and value.encode('utf-8') != value:
			raise ValueError, 'ASCII string required'
		return value
コード例 #9
0
class TableViewObjectType(InsertedObjectTypeExtension):

    name = 'runnable'

    label = _('Runnable')

    object_attr = {
        'program': String('grep'),
        'arguments': String('-r "hello!"')
    }

    def __init__(self, plugin, objmap):

        #		InsertSymbolDialog(self.plugi).run()
        self._widgets = WeakSet()
        self.preferences = plugin.preferences
        InsertedObjectTypeExtension.__init__(self, plugin, objmap)
        self.connectto(self.preferences, 'changed',
                       self.on_preferences_changed)

    def data_from_model(self, buffer):
        return buffer.get_object_data()

    def model_from_data(self, notebook, page, attrib, data):
        return TableModel(attrib)

    def model_from_element(self, attrib, element):
        assert ElementTree.iselement(element)
        attrib = self.parse_attrib(attrib)
        return TableModel(attrib)

    def create_widget(self, model):
        widget = TableViewWidget(model)
        self._widgets.add(widget)
        return widget

    def on_preferences_changed(self, preferences):
        for widget in self._widgets:
            widget.set_preferences(preferences)

    def dump(self, builder):

        builder.start("start")
        builder.data("data")
        builder.end("end")
コード例 #10
0
	def __init__(self):
		assert self.name is not None
		assert self.label is not None
		self.object_attr['type'] = String(self.name)

		for name in ('model_from_data', 'data_from_model', 'format'):
			orig = getattr(self, name)
			wrapper = getattr(self, '_' + name + '_wrapper')
			setattr(self, '_inner_' + name, orig)
			setattr(self, name, wrapper)
コード例 #11
0
 def check(self, value):
     # Only ascii chars allowed in these keys
     value = BaseString.check(self, value)
     if isinstance(value, str):
         try:
             x = value.encode('ascii')
         except UnicodeEncodeError:
             raise ValueError('ASCII string required')
         else:
             pass
     return value
コード例 #12
0
def mount_notebook(filepath):
	from zim.config import ConfigManager, String

	configdict = ConfigManager.get_config_dict('automount.conf')

	groups = sorted([k for k in list(configdict.keys()) if k.startswith('Path')])
	for group in groups:
		path = group[4:].strip() # len('Path') = 4
		dir = Dir(path)
		if is_relevant_mount_point(dir, filepath):
			configdict[group].define(mount=String(None))
			handler = ApplicationMountPointHandler(dir, **configdict[group])
			if handler(filepath):
				break
コード例 #13
0
ファイル: __init__.py プロジェクト: zrf1/zim-desktop-wiki
def mount_notebook(filepath):
	from zim.config import ConfigManager, String

	config = ConfigManager() # XXX should be passed in
	configdict = config.get_config_dict('automount.conf')

	groups = sorted([k for k in configdict.keys() if k.startswith('Path')])
	for group in groups:
		path = group[4:].strip() # len('Path') = 4
		dir = Dir(path)
		if filepath.path == dir.path or filepath.ischild(dir):
			configdict[group].define(mount=String(None))
			handler = ApplicationMountPointHandler(dir, **configdict[group])
			if handler(filepath):
				break
コード例 #14
0
ファイル: sourceview.py プロジェクト: hjq300/zim-wiki
    def __init__(self, ui):
        Dialog.__init__(self, ui, _('Insert Code Block'))  # T: dialog title
        names = sorted(LANGUAGES, key=lambda k: k.lower())
        self.add_form((('lang', 'choice', _('Syntax'), names),
                       )  # T: input label
                      )

        # Set previous used language
        self.uistate.define(lang=String(None))
        if 'lang' in self.uistate:
            for name, id in LANGUAGES.items():
                if self.uistate['lang'] == id:
                    try:
                        self.form['lang'] = name
                    except ValueError:
                        pass

                    break
コード例 #15
0
    def __init__(self, parent):
        Dialog.__init__(self, parent,
                        _('Insert Code Block'))  # T: dialog title
        self.result = (None, None)
        self.uistate.define(lang=String(None))
        self.uistate.define(line_numbers=Boolean(True))
        defaultlang = self.uistate['lang']

        menu = {}
        for l in sorted(LANGUAGES, key=lambda k: k.lower()):
            key = l[0].upper()
            if not key in menu:
                menu[key] = []
            menu[key].append(l)

        model = Gtk.TreeStore(str)
        defaultiter = None
        for key in sorted(menu):
            iter = model.append(None, [key])
            for lang in menu[key]:
                myiter = model.append(iter, [lang])
                if LANGUAGES[lang] == defaultlang:
                    defaultiter = myiter

        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        hbox.set_spacing(5)
        label = Gtk.Label(_('Syntax') + ':')  # T: input label
        hbox.add(label)

        combobox = Gtk.ComboBox.new_with_model(model)
        renderer_text = Gtk.CellRendererText()
        combobox.pack_start(renderer_text, True)
        combobox.add_attribute(renderer_text, "text", 0)
        if defaultiter is not None:
            combobox.set_active_iter(defaultiter)
        hbox.add(combobox)
        self.combobox = combobox
        self.vbox.add(hbox)
        self.checkbox = Gtk.CheckButton(
            _('Display line numbers'))  # T: input checkbox
        self.checkbox.set_active(self.uistate['line_numbers'])
        self.vbox.add(self.checkbox)
コード例 #16
0
 def __init__(self, file):
     INIConfigFile.__init__(self, file)
     if os.name == 'nt': endofline = 'dos'
     else: endofline = 'unix'
     self['Notebook'].define((
         ('version', String('.'.join(map(str, DATA_FORMAT_VERSION)))),
         ('name', String(file.dir.basename)),
         ('interwiki', String(None)),
         ('home', ConfigDefinitionByClass(Path('Home'))),
         ('icon',
          String(None)),  # XXX should be file, but resolves relative
         ('document_root',
          String(None)),  # XXX should be dir, but resolves relative
         ('shared', Boolean(True)),
         ('endofline', Choice(endofline, set(('dos', 'unix')))),
         ('disable_trash', Boolean(False)),
         ('profile', String(None)),
     ))
コード例 #17
0
ファイル: sourceview.py プロジェクト: zrf1/zim-desktop-wiki
class SourceViewObject(CustomObjectClass):

	OBJECT_ATTR = {
		'type': String('code'),
		'lang': String(None),
		'linenumbers': Boolean(True),
	}

	def __init__(self, attrib, data, preferences):
		if data.endswith('\n'):
			data = data[:-1]
			# If we have trailing \n it looks like an extra empty line
			# in the buffer, so we default remove one
		CustomObjectClass.__init__(self, attrib, data)
		self.preferences = preferences
		self.buffer = None
		self._widgets = WeakSet()

	def get_widget(self):
		if not self.buffer:
			self.buffer = gtksourceview2.Buffer()
			self.buffer.set_text(self._data)
			self.buffer.connect('modified-changed', self.on_modified_changed)
			self.buffer.set_highlight_matching_brackets(True)
			self.buffer.set_modified(False)
			self._data = None

			try:
				if self._attrib['lang']:
					self.buffer.set_language(lm.get_language(self._attrib['lang']))
			except:
				logger.exception('Could not set language for sourceview: %s', lang)

		widget = SourceViewWidget(self, self.buffer)
		self._widgets.add(widget)

		widget.view.set_show_line_numbers(self._attrib['linenumbers'])
		widget.set_preferences(self.preferences)
		return widget

	def preferences_changed(self):
		for widget in self._widgets:
			widget.set_preferences(self.preferences)

	def on_modified_changed(self, buffer):
		# Sourceview changed, set change on oject, reset state of
		# sourceview buffer so we get a new signal with next change
		if buffer.get_modified():
			self.set_modified(True)
			buffer.set_modified(False)

	def get_data(self):
		'''Returns data as text.'''
		if self.buffer:
			bounds = self.buffer.get_bounds()
			text = self.buffer.get_text(bounds[0], bounds[1])
			text += '\n' # Make sure we always have a trailing \n
			return text
		else:
			return self._data

	def dump(self, format, dumper, linker=None):
		if format == "html":
			if self._attrib['lang']:
				''' to use highlight.js add the following to your template:
				<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/default.min.css">
				<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
				<script>hljs.initHighlightingOnLoad();</script>
				Map GtkSourceView language ids match with Highlight.js language ids.
				http://packages.ubuntu.com/precise/all/libgtksourceview2.0-common/filelist
				http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html
                '''
				sh_map = {'dosbatch': 'dos'}
				sh_lang = sh_map[self._attrib['lang']] if self._attrib['lang'] in sh_map else self._attrib['lang']
				# TODO: some template instruction to be able to use other highlighters as well?
				output = ['<pre><code class="%s">' % html_encode(sh_lang)] # for syntaxhigligther
				'''' class="brush: language;" works with SyntaxHighlighter 2.0.278, 3 & 4
				output = ['<pre class="brush: %s;">' % html_encode(sh_lang)] # for syntaxhigligther
				'''
			else:
				output = ['<pre>\n']
			data = self.get_data()
			data = html_encode(data) # XXX currently dumper gives encoded lines - NOK
			#if self._attrib['linenumbers']:
			#	for i, l in enumerate(data.splitlines(1)):
			#		output.append('%i&nbsp;' % (i+1) + l)
			#else:
			output.append(data) # ignoring numbering for html - syntaxhighlighter takes care of that
			if self._attrib['lang']:
				output.append('</code></pre>\n')
			else:
				output.append('</pre>\n')
			return output
		return CustomObjectClass.dump(self, format, dumper, linker)

	def set_language(self, lang):
		'''Set language in SourceView.'''
		self._attrib['lang'] = lang
		self.set_modified(True)

		if self.buffer:
			if lang is None:
				self.buffer.set_language(None)
			else:
				self.buffer.set_language(lm.get_language(lang))

	def show_line_numbers(self, show):
		'''Toggles line numbers in SourceView.'''
		self._attrib['linenumbers'] = show
		self.set_modified(True)

		for widget in self._widgets:
			widget.view.set_show_line_numbers(show)
コード例 #18
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'])
コード例 #19
0
class TableViewObjectType(InsertedObjectType):

    name = 'table'

    label = _('Table')  # T: menu item
    verb_icon = 'zim-insert-table'

    object_attr = {
        'aligns': String(''),  # i.e. String(left,right,center)
        'wraps': String('')  # i.e. String(0,1,0)
    }

    def __init__(self, plugin):
        InsertedObjectType.__init__(self, plugin)
        self._widgets = WeakSet()
        self.preferences = plugin.preferences
        self.connectto(self.preferences, 'changed',
                       self.on_preferences_changed)

    def new_object_interactive(self, parent):
        definition = EditTableDialog(parent).run()
        if definition is None:
            raise ValueError  # dialog cancelled

        ids, headers, wraps, aligns = definition
        attrib = self.parse_attrib({
            'aligns': ','.join(map(str, aligns)),
            'wraps': ','.join(map(str, wraps))
        })
        rows = [''] * len(headers)
        data = ' | '.join(headers) + '\n' + ' | '.join(rows) + '\n'
        return attrib, data

    def model_from_data(self, attrib, data):
        rows = [line.split(' | ') for line in data.splitlines()]
        headers = rows.pop(0) if rows else []
        if not headers:
            headers = ['Column1', 'Column2']
        return TableModel(attrib, headers, rows)

    def model_from_element(self, attrib, element):
        assert ElementTree.iselement(element)
        attrib = self.parse_attrib(attrib)
        headers, rows = self._tabledom_to_list(element)
        return TableModel(attrib, headers, rows)

    def _tabledom_to_list(self, tabledata):
        '''
		Extracts necessary data out of a xml-table into a list structure

		:param tabledata: XML - formated as a zim-tree table-object
		:return: tuple of header-list and list of row lists -  ([h1,h2],[[r11,r12],[r21,r22])
		'''
        headers = [head.text for head in tabledata.findall('thead/th')]
        headers = list(map(CellFormatReplacer.zim_to_cell, headers))

        rows = []
        for trow in tabledata.findall('trow'):
            row = trow.findall('td')
            row = [
                ElementTree.tostring(r, 'unicode').replace('<td>', '').replace(
                    '</td>', '') for r in row
            ]
            row = list(map(CellFormatReplacer.zim_to_cell, row))
            rows.append(row)
        return headers, rows

    def create_widget(self, model):
        widget = TableViewWidget(model)
        widget.set_preferences(self.preferences)
        self._widgets.add(widget)
        return widget

    def on_preferences_changed(self, preferences):
        for widget in self._widgets:
            widget.set_preferences(preferences)

    def dump(self, builder, model):
        headers, attrib, rows = model.get_object_data()

        builder.start(TABLE, dict(attrib))
        builder.start(HEADROW)
        for header in headers:
            builder.append(HEADDATA, header)
        builder.end(HEADROW)
        for row in rows:
            builder.start(TABLEROW)
            for cell in row:
                builder.append(TABLEDATA, cell)
            builder.end(TABLEROW)
        builder.end(TABLE)
コード例 #20
0
ファイル: tableeditor.py プロジェクト: hjq300/zim-wiki
class TableViewObject(CustomObjectClass):
    '''data presenter of an inserted table within a page'''

    OBJECT_ATTR = {
        'type': String('table'),
        'aligns': String(''),  # i.e. String(left,right,center)
        'wraps': String('')  # i.e. String(0,1,0)
    }

    def __init__(self, attrib, header, rows, preferences):
        '''
		Creates a new object which can displayed within the page
		:param attrib: aligns, wraps
		:param header: titles of the table as list
		:param rows: body-rows of the table as list of lists
		:param preferences: optionally some preferences
		'''
        _attrib = {}
        for k, v in attrib.iteritems():
            if isinstance(v, list):
                v = ','.join(map(str, v))
            _attrib[k] = v
        CustomObjectClass.__init__(self, _attrib, [header] + rows)
        self.attrib = {'type': OBJECT_TYPE}  # just to be sure

        self._tableattrib = attrib
        self._header = header
        self._rows = rows
        self._widgets = WeakSet()
        self._liststore = None  # shared model between widgets

        self.preferences = preferences

    # getters and setters for attributes
    def get_aligns(self):
        ''' get the list of align-attributes '''
        return self._attrib['aligns'].split(',')

    def set_aligns(self, data):
        ''' Set list of align attributes for the current table. Each item belongs to a column.'''
        assert (isinstance(data, list))
        self._attrib['aligns'] = ','.join(data)

    def get_wraps(self):
        ''' get the list of wrap-attributes '''
        return map(int, self._attrib['wraps'].split(','))

    def set_wraps(self, data):
        ''' Set list of wrap attributes for the current table. Each item belongs to a column.'''
        assert (isinstance(data, list))
        self._attrib['wraps'] = ','.join(str(item) for item in data)

    def _get_liststore(self, reset=False):
        if reset or not self._liststore:
            cols = [str] * len(self._header)
            self._liststore = gtk.ListStore(*cols)
            for trow in self._rows:
                self._liststore.append(trow)
            self._liststore.connect('row-changed', self.on_modified_changed)

        return self._liststore

    def get_widget(self):
        ''' Creates a new table-widget which can displayed on the wiki-page '''
        liststore = self._get_liststore()
        attrib = {'aligns': self.get_aligns(), 'wraps': self.get_wraps()}
        widget = TableViewWidget(self, liststore, self._header, attrib)
        self._widgets.add(widget)
        widget.set_preferences(self.preferences)
        return widget

    def preferences_changed(self):
        '''	Updates all created table-widgets, if preferences have changed '''
        for widget in self._widgets:
            widget.set_preferences(self.preferences)

    def on_sort_column_changed(self, liststore):
        ''' Trigger after a column-header is clicked and therefore its sort order has changed '''
        self.set_modified(True)

    def on_modified_changed(self, liststore, path, treeiter):
        ''' Trigger after a table cell content is changed by the user '''
        self.set_modified(True)

    def get_data(self):
        '''Returns table-object into textual data, for saving it as text.'''
        headers = self._header
        attrs = {
            'aligns': self._attrib['aligns'],
            'wraps': self._attrib['wraps']
        }

        if not self._liststore:
            rows = self._rows
        else:
            rows = []
            for treerow in self._liststore:
                rows.append(
                    map(
                        lambda cell: CellFormatReplacer.cell_to_input(
                            cell, True), treerow))

        return headers, rows, attrs

    def change_model(self, new_model):
        '''
		Replace liststore with new model and notify widgets to update
		their treeview.
		:param new_model: tuple of lists for ([id], [header], [warps], [aligns])
		'''
        # prepare results out of dialog-window
        id_mapping, headers, aligns, wraps = ({}, [], [], [])
        for i, model in enumerate(new_model):
            if model[0] != -1:
                id_mapping[i] = model[0]
            header = model[1] if model[1] else ' '
            headers.append(header)
            aligns.append(model[3])
            wraps.append(model[2])

        # update data
        if self._liststore:
            liststore = self._get_liststore()
            self._rows = self._update_rows(liststore, id_mapping, len(headers))
            liststore = self._get_liststore(reset=True)
        else:
            liststore = None
            self._rows = self._update_rows(self._rows, id_mapping,
                                           len(headers))

        self.set_aligns(aligns)
        self.set_wraps(wraps)
        self.set_modified(True)

        # notify widgets
        for widget in self._widgets:
            assert liststore is not None, 'Huh?'
            attrib = {'aligns': self.get_aligns(), 'wraps': self.get_wraps()}
            widget.on_model_changed(liststore, headers, attrib)

        self.preferences_changed()  # reset prefs on widgets

    def _update_rows(self, old_rows, id_mapping, nr_cols):
        ''' Old value of cells are used in the new table, but only if its column is not deleted '''
        new_rows = []
        for oldrow in old_rows:
            newrow = [' '] * nr_cols
            for v, k in id_mapping.iteritems():
                newrow[v] = oldrow[k]
            new_rows.append(newrow)
        return new_rows

    def build_parsetree_of_table(self, builder, iter):
        logger.debug("Anchor with TableObject: %s", self)

        # inserts a newline before and after table-object
        bound = iter.copy()
        bound.backward_char()
        char_before_table = bound.get_slice(iter)
        need_newline_infront = char_before_table.decode(
            'utf-8') != "\n".decode('utf-8')
        bound = iter.copy()
        bound.forward_char()
        iter2 = bound.copy()
        bound.forward_char()
        char_after_table = iter2.get_slice(bound)
        need_newline_behind = char_after_table.decode('utf-8') != "\n".decode(
            'utf-8')
        #

        headers, rows, attrib = self.get_data()
        #~ print "Table data:", headers, rows, attrib

        if need_newline_infront:
            builder.data('\n')

        builder.start(TABLE, attrib)
        builder.start(HEADROW)
        for header in headers:
            builder.append(HEADDATA, header)
        builder.end(HEADROW)
        for row in rows:
            builder.start(TABLEROW)
            for cell in row:
                builder.append(TABLEDATA, cell)
            builder.end(TABLEROW)
        builder.end(TABLE)

        if need_newline_behind:
            builder.data('\n')
コード例 #21
0
ファイル: sourceview.py プロジェクト: hjq300/zim-wiki
class SourceViewObject(CustomObjectClass):

    OBJECT_ATTR = {
        'type': String('code'),
        'lang': String(None),
        'linenumbers': Boolean(True),
    }

    def __init__(self, attrib, data, preferences):
        if data.endswith('\n'):
            data = data[:-1]
            # If we have trailing \n it looks like an extra empty line
            # in the buffer, so we default remove one
        CustomObjectClass.__init__(self, attrib, data)
        self.preferences = preferences
        self.buffer = None
        self._widgets = WeakSet()

    def get_widget(self):
        if not self.buffer:
            self.buffer = gtksourceview2.Buffer()
            self.buffer.set_text(self._data)
            self.buffer.connect('modified-changed', self.on_modified_changed)
            self.buffer.set_highlight_matching_brackets(True)
            self.buffer.set_modified(False)
            self._data = None

            try:
                if self._attrib['lang']:
                    self.buffer.set_language(
                        lm.get_language(self._attrib['lang']))
            except:
                logger.exception('Could not set language for sourceview: %s',
                                 lang)

        widget = SourceViewWidget(self, self.buffer)
        self._widgets.add(widget)

        widget.view.set_show_line_numbers(self._attrib['linenumbers'])
        widget.set_preferences(self.preferences)
        return widget

    def preferences_changed(self):
        for widget in self._widgets:
            widget.set_preferences(self.preferences)

    def on_modified_changed(self, buffer):
        # Sourceview changed, set change on oject, reset state of
        # sourceview buffer so we get a new signal with next change
        if buffer.get_modified():
            self.set_modified(True)
            buffer.set_modified(False)

    def get_data(self):
        '''Returns data as text.'''
        if self.buffer:
            bounds = self.buffer.get_bounds()
            text = self.buffer.get_text(bounds[0], bounds[1])
            text += '\n'  # Make sure we always have a trailing \n
            return text
        else:
            return self._data

    def dump(self, format, dumper, linker=None):
        if format == "html":
            if self._attrib['lang']:
                # class="brush: language;" works with SyntaxHighlighter 2.0.278
                # by Alex Gorbatchev <http://alexgorbatchev.com/SyntaxHighlighter/>
                # TODO: not all GtkSourceView language ids match with SyntaxHighlighter
                # language ids.
                # TODO: some template instruction to be able to use other highlighters as well?
                output = [
                    '<pre class="brush: %s;">\n' %
                    html_encode(self._attrib['lang'])
                ]
            else:
                output = ['<pre>\n']
            data = self.get_data()
            data = html_encode(
                data)  # XXX currently dumper gives encoded lines - NOK
            if self._attrib['linenumbers']:
                for i, l in enumerate(data.splitlines(1)):
                    output.append('%i&nbsp;' % (i + 1) + l)
            else:
                output.append(data)
            output.append('</pre>\n')
            return output
        return CustomObjectClass.dump(self, format, dumper, linker)

    def set_language(self, lang):
        '''Set language in SourceView.'''
        self._attrib['lang'] = lang
        self.set_modified(True)

        if self.buffer:
            if lang is None:
                self.buffer.set_language(None)
            else:
                self.buffer.set_language(lm.get_language(lang))

    def show_line_numbers(self, show):
        '''Toggles line numbers in SourceView.'''
        self._attrib['linenumbers'] = show
        self.set_modified(True)

        for widget in self._widgets:
            widget.view.set_show_line_numbers(show)
コード例 #22
0
class TableViewObjectType(InsertedObjectTypeExtension):

    name = 'table'

    label = _('Table')  # T: menu item
    verb_icon = 'zim-insert-table'

    object_attr = {
        'aligns': String(''),  # i.e. String(left,right,center)
        'wraps': String('')  # i.e. String(0,1,0)
    }

    def __init__(self, plugin, objmap):
        self._widgets = WeakSet()
        self.preferences = plugin.preferences
        InsertedObjectTypeExtension.__init__(self, plugin, objmap)
        self.connectto(self.preferences, 'changed',
                       self.on_preferences_changed)

    def new_model_interactive(self, parent, notebook, page):
        definition = EditTableDialog(parent).run()
        if definition is None:
            raise ValueError  # dialog cancelled

        ids, headers, wraps, aligns = definition
        attrib = self.parse_attrib({
            'aligns': ','.join(map(str, aligns)),
            'wraps': ','.join(map(str, wraps))
        })
        rows = [''] * len(headers)
        return TableModel(attrib, headers, rows)

    def model_from_data(self, notebook, page, attrib, data):
        tree = WikiParser().parse(data)
        element = tree._etree.getroot().find(
            'table')  # XXX - should use token interface instead
        if element is not None:
            return self.model_from_element(element.attrib, element)
        else:
            return TableModel(attrib, [data.strip()], [''])

    def model_from_element(self, attrib, element):
        assert ElementTree.iselement(element)
        attrib = self.parse_attrib(attrib)
        headers, rows = self._tabledom_to_list(element)
        return TableModel(attrib, headers, rows)

    def _tabledom_to_list(self, tabledata):
        '''
		Extracts necessary data out of a xml-table into a list structure

		:param tabledata: XML - formated as a zim-tree table-object
		:return: tuple of header-list and list of row lists -  ([h1,h2],[[r11,r12],[r21,r22])
		'''
        headers = [head.text for head in tabledata.findall('thead/th')]
        headers = list(map(CellFormatReplacer.zim_to_cell, headers))

        rows = []
        for trow in tabledata.findall('trow'):
            row = trow.findall('td')
            row = [
                ElementTree.tostring(r, 'unicode').replace('<td>', '').replace(
                    '</td>', '') for r in row
            ]
            row = list(map(CellFormatReplacer.zim_to_cell, row))
            rows.append(row)
        return headers, rows

    def create_widget(self, model):
        widget = TableViewWidget(model)
        widget.set_preferences(self.preferences)
        self._widgets.add(widget)
        return widget

    def on_preferences_changed(self, preferences):
        for widget in self._widgets:
            widget.set_preferences(preferences)

    def dump(self, builder, model):
        headers, attrib, rows = model.get_object_data()

        def append(tag, text):
            builder.start(tag, {})
            builder.data(text)
            builder.end(tag)

        builder.start(TABLE, dict(attrib))
        builder.start(HEADROW)
        for header in headers:
            append(HEADDATA, header)
        builder.end(HEADROW)
        for row in rows:
            builder.start(TABLEROW, {})
            for cell in row:
                append(TABLEDATA, cell)
            builder.end(TABLEROW)
        builder.end(TABLE)
コード例 #23
0
    def __init__(self, parent, store, preferences):
        title = _('Command Palette')
        Dialog.__init__(self, parent, title)

        self.uistate.define(last_entry=String(None))
        self.action = None
        self.store = store
        self.entries = {item[0]: item[1]
                        for item in self.store}  # { label: action }

        # Configure completion for search field.
        completion = Gtk.EntryCompletion()
        completion.set_model(store)

        cell_shortcut = Gtk.CellRendererText()
        completion.pack_end(cell_shortcut, False)
        completion.add_attribute(cell_shortcut, 'text', 2)

        completion.set_text_column(0)
        completion.set_minimum_key_length(0)
        completion.connect("match-selected", self.on_match_selected)

        def match_anywhere(_completion, _entrystr, _iter, _data):
            """ Match any part. """
            _modelstr = _completion.get_model()[_iter][0].lower()
            for part in _entrystr.split():
                if part not in _modelstr:
                    return False
            return True

        completion.set_match_func(match_anywhere, None)

        self.hbox = Gtk.HBox()

        # Add search field.
        self.txt_search = Gtk.SearchEntry(hexpand=True, margin=2)
        self.txt_search.set_activates_default(
            True)  # Make ENTER key press trigger the OK button.
        self.txt_search.set_icon_from_icon_name(
            Gtk.EntryIconPosition.SECONDARY, Gtk.STOCK_FIND)
        self.txt_search.set_placeholder_text("Search commands")
        self.txt_search.set_completion(completion)

        last_entry = self.init_last_entry()
        if last_entry:
            self.txt_search.set_text(last_entry)

        self.txt_search.connect('search-changed', self.do_validate, parent)
        self.txt_search.connect("key-press-event", self.on_key_pressed, parent)

        # Add ok button.
        self.btn_ok = self.get_widget_for_response(
            response_id=Gtk.ResponseType.OK)
        self.btn_ok.set_can_default(True)
        self.btn_ok.grab_default()
        self.btn_ok.set_sensitive(last_entry is not None)

        # Configure dialog.
        self.set_modal(True)
        self.set_default_size(380, 100)
        self.hbox.pack_start(self.txt_search, True, True, 0)
        self.vbox.pack_start(self.hbox, True, True, 0)

        # Set focus to search field
        self.txt_search.grab_focus()