Example #1
0
	def __init__(self, plugin, attachment_folder=None):
		ImageGeneratorClass.__init__(self, plugin)
		file = data_file('templates/plugins/gnuploteditor.gnu')
		assert file, 'BUG: could not find templates/plugins/gnuploteditor.gnu'
		self.template = GenericTemplate(file.readlines(), name=file)
		self.attachment_folder = attachment_folder
		self.plotscriptfile = TmpFile(self.scriptname)
Example #2
0
	def __init__(self, ui, callback=None):
		Dialog.__init__(self, ui, _('Open Notebook')) # T: dialog title
		# TODO set button to "OPEN" instead of "OK"
		self.callback = callback
		self.set_default_size(500, 400)
		self.set_help(':Help:Notebooks')

		# show some art work in an otherwise boring dialog
		path = data_file('globe_banner_small.png').path
		image = gtk.Image()
		image.set_from_file(path) # new_from_file not in 2.6
		align = gtk.Alignment(0,0.5, 0,0)
		align.add(image)
		self.vbox.pack_start(align, False)

		# split between treeview and vbuttonbox
		hbox = gtk.HBox(spacing=12)
		self.vbox.add(hbox)

		# add notebook list - open notebook on clicking a row
		self.treeview = NotebookTreeView()
		self.treeview.connect(
			'row-activated', lambda *a: self.response(gtk.RESPONSE_OK))

		swindow = gtk.ScrolledWindow()
		swindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
		swindow.set_shadow_type(gtk.SHADOW_IN)
		swindow.add(self.treeview)
		hbox.add(swindow)

		# add buttons for modifying the treeview
		vbbox = gtk.VButtonBox()
		vbbox.set_layout(gtk.BUTTONBOX_START)
		hbox.pack_start(vbbox, False)
		add_button = gtk.Button(stock='gtk-add')
		add_button.connect('clicked', self.do_add_notebook)
		#~ edit_button = gtk.Button(stock='gtk-edit')
		#~ edit_button.connect('clicked', self.do_edit_notebook)
		rm_button = gtk.Button(stock='gtk-remove')
		rm_button.connect('clicked', self.do_remove_notebook)
		#~ for b in (add_button, edit_button, rm_button):
		for b in (add_button, rm_button):
			b.set_alignment(0.0, 0.5)
			vbbox.add(b)
		# FIXME buttons for "up" and "down" ?

		# add dropdown to select default
		self.combobox = DefaultNotebookComboBox(self.treeview.get_model())

		# clear button de-selects any item in the combobox
		clear_button = IconButton('gtk-clear')
		clear_button.connect('clicked', lambda o: self.combobox.set_active(-1))

		hbox = gtk.HBox(spacing=5)
		hbox.pack_start(gtk.Label(_('Default notebook')+': '), False)
			# T: Input label in 'open notebook' dialog
		hbox.pack_start(self.combobox, False)
		hbox.pack_start(clear_button, False)
		self.vbox.pack_start(hbox, False)
Example #3
0
    def __init__(self, parent, callback=None):
        Dialog.__init__(self, parent, _('Open Notebook'))  # T: dialog title
        # TODO set button to "OPEN" instead of "OK"
        self.callback = callback
        self.set_default_size(500, 400)
        self.set_help(':Help:Notebooks')

        # show some art work in an otherwise boring dialog
        path = data_file('globe_banner_small.png').path
        image = Gtk.Image()
        image.set_from_file(path)  # new_from_file not in 2.6
        align = Gtk.Alignment.new(0, 0.5, 0, 0)
        align.add(image)
        self.vbox.pack_start(align, False, True, 0)

        # split between treeview and vbuttonbox
        hbox = Gtk.HBox(spacing=12)
        self.vbox.pack_start(hbox, True, True, 0)

        # add notebook list - open notebook on clicking a row
        self.treeview = NotebookTreeView()
        self.treeview.connect('row-activated',
                              lambda *a: self.response(Gtk.ResponseType.OK))

        hbox.add(ScrolledWindow(self.treeview))

        # add buttons for modifying the treeview
        vbbox = Gtk.VButtonBox()
        vbbox.set_layout(Gtk.ButtonBoxStyle.START)
        hbox.pack_start(vbbox, False, True, 0)
        add_button = Gtk.Button.new_with_mnemonic(_('_Add'))  # T: Button label
        add_button.connect('clicked', self.do_add_notebook)
        #~ edit_button = Gtk.Button.new_with_mnemonic(_('_Edit')) # T: Button label
        #~ edit_button.connect('clicked', self.do_edit_notebook)
        rm_button = Gtk.Button.new_with_mnemonic(
            _('_Remove'))  # T: Button label
        rm_button.connect('clicked', self.do_remove_notebook)
        #~ for b in (add_button, edit_button, rm_button):
        for b in (add_button, rm_button):
            b.set_alignment(0.0, 0.5)
            vbbox.add(b)
        # FIXME buttons for "up" and "down" ?

        # add dropdown to select default
        self.combobox = DefaultNotebookComboBox(self.treeview.get_model())

        # clear button de-selects any item in the combobox
        clear_button = IconButton('gtk-clear')
        clear_button.connect('clicked', lambda o: self.combobox.set_active(-1))

        hbox = Gtk.HBox(spacing=5)
        hbox.pack_start(Gtk.Label(_('Default notebook') + ': '), False, True,
                        0)
        # T: Input label in 'open notebook' dialog
        hbox.pack_start(self.combobox, False, True, 0)
        hbox.pack_start(clear_button, False, True, 0)
        self.vbox.pack_start(hbox, False, True, 0)
Example #4
0
	def __init__(self, plugin):
		ImageGeneratorClass.__init__(self, plugin)
		file = data_file('templates/plugins/scoreeditor.ly')
		assert file, 'BUG: could not find templates/plugins/scoreeditor.ly'
		self.template = GenericTemplate(file.readlines(), name=file)
		self.scorefile = TmpFile(self.scriptname)
		self.cur_lilypond_version = _get_lilypond_version()
		self.include_header = plugin.preferences['include_header']
		self.include_footer = plugin.preferences['include_footer']
Example #5
0
 def __init__(self, plugin):
     ImageGeneratorClass.__init__(self, plugin)
     file = data_file('templates/plugins/scoreeditor.ly')
     assert file, 'BUG: could not find templates/plugins/scoreeditor.ly'
     self.template = GenericTemplate(file.readlines(), name=file)
     self.scorefile = TmpFile(self.scriptname)
     self.cur_lilypond_version = _get_lilypond_version()
     self.include_header = plugin.preferences['include_header']
     self.include_footer = plugin.preferences['include_footer']
Example #6
0
	def __init__(self, preferences={}):
		file = data_file('templates/plugins/scoreeditor.ly')
		assert file, 'BUG: could not find templates/plugins/scoreeditor.ly'
		self.template = GenericTemplate(file.readlines(), name=file)
		self.scorefile = TmpFile(self.scriptname)
		self.cur_lilypond_version = _get_lilypond_version()
		if preferences.has_key('include_header'):
			self.include_header = preferences['include_header']
		if preferences.has_key('include_footer'):
			self.include_footer = preferences['include_footer']
	def refresh(self):
		model = self.get_model()
		model.clear()
		for category in list_template_categories():
			parent = model.append(None, (category, None, None))
			for name, basename in list_templates(category):
				base = XDG_DATA_HOME.file(('zim', 'templates', category, basename))
				default = data_file(('templates', category, basename)) # None if not existing
				#~ print '>>>', name, base, default
				model.append(parent, (name, base, default))

		self.expand_all()
Example #8
0
	def __init__(self):
		gtk.StatusIcon.__init__(self)

		icon_theme = gtk.icon_theme_get_default()
		if icon_theme.has_icon('zim-panel'):
		    self.set_from_icon_name('zim-panel')
		else:
			icon = data_file('zim.png').path
			self.set_from_file(icon)

		self.set_tooltip(_('Zim Desktop Wiki')) # T: tooltip for tray icon
		self.connect('popup-menu', self.__class__.do_popup_menu)
Example #9
0
    def __init__(self):
        gtk.StatusIcon.__init__(self)

        icon_theme = gtk.icon_theme_get_default()
        if icon_theme.has_icon('zim-panel'):
            self.set_from_icon_name('zim-panel')
        else:
            icon = data_file('zim.png').path
            self.set_from_file(icon)

        self.set_tooltip(_('Zim Desktop Wiki')) # T: tooltip for tray icon
        self.connect('popup-menu', self.__class__.do_popup_menu)
	def refresh(self):
		model = self.get_model()
		model.clear()
		for category in list_template_categories():
			parent = model.append(None, (category, None, None))
			for name, basename in list_templates(category):
				base = XDG_DATA_HOME.file(('zim', 'templates', category, basename))
				default = data_file(('templates', category, basename)) # None if not existing
				#~ print('>>>', name, base, default)
				model.append(parent, (name, base, default))

		self.expand_all()
Example #11
0
    def testExportResources(self):
        '''Test export notebook to html with template resources'''
        self.export()

        file = self.dir.file('Test/foo.html')
        self.assertTrue(file.exists())
        text = file.read()
        self.assertTrue('src="../_resources/foo/bar.png"' in text)
        self.assertTrue(self.dir.file('_resources/foo/bar.png').exists())

        for icon in ('checked-box', ):  #'unchecked-box', 'xchecked-box'):
            # Template has its own checkboxes
            self.assertTrue(self.dir.file('_resources/%s.png' % icon).exists())
            self.assertNotEqual(md5(self.dir.file('_resources/%s.png' % icon)),
                                md5(data_file('pixmaps/%s.png' % icon)))
Example #12
0
    def runTest(self):
        '''Test export notebook to html'''
        self.export()

        file = self.dir.file('Test/foo.html')
        self.assertTrue(file.exists())
        text = file.read()
        self.assertTrue('<!-- Wiki content -->' in text, 'template used')
        self.assertTrue('<h1>Foo</h1>' in text)

        for icon in ('checked-box', ):  #'unchecked-box', 'xchecked-box'):
            # Default template doesn't have its own checkboxes
            self.assertTrue(self.dir.file('_resources/%s.png' % icon).exists())
            self.assertEqual(md5(self.dir.file('_resources/%s.png' % icon)),
                             md5(data_file('pixmaps/%s.png' % icon)))
Example #13
0
def _get_xml_for_menu(name):
    # Need to get sub-set of ui definition
    # Simple parser assumes we pretty-format input file per line
    file_name = 'menubar.xml'
    xml = iter(l.strip() for l in data_file(file_name).readlines())
    menu = []

    for line in xml:
        if line.startswith('<popup name=\'%s\'>' % name):
            menu.append(line)
            for line in xml:
                menu.append(line)
                if line.startswith('</popup>'):
                    return '<ui>\n%s\n</ui>\n' % '\n'.join(menu)
    else:
        raise ValueError('No such popup defined in %s: %s' % (file_name, name))
Example #14
0
	def testExportResources(self):
		'''Test export notebook to html with template resources'''
		self.export()

		file = self.dir.file('Test/foo.html')
		self.assertTrue(file.exists())
		text = file.read()
		self.assertTrue('src="../_resources/foo/bar.png"' in text)
		self.assertTrue(self.dir.file('_resources/foo/bar.png').exists())

		for icon in ('checked-box',): #'unchecked-box', 'xchecked-box'):
			# Template has its own checkboxes
			self.assertTrue(self.dir.file('_resources/%s.png' % icon).exists())
			self.assertNotEqual(
				md5(self.dir.file('_resources/%s.png' % icon)),
				md5(data_file('pixmaps/%s.png' % icon))
			)
Example #15
0
	def runTest(self):
		'''Test export notebook to html'''
		self.export()

		file = self.dir.file('Test/foo.html')
		self.assertTrue(file.exists())
		text = file.read()
		self.assertTrue('<!-- Wiki content -->' in text, 'template used')
		self.assertTrue('<h1>Foo</h1>' in text)

		for icon in ('checked-box',): #'unchecked-box', 'xchecked-box'):
			# Default template doesn't have its own checkboxes
			self.assertTrue(self.dir.file('_resources/%s.png' % icon).exists())
			self.assertEqual(
				md5(self.dir.file('_resources/%s.png' % icon)),
				md5(data_file('pixmaps/%s.png' % icon))
			)
Example #16
0
    def __init__(self, parent):
        import zim

        GObject.GObject.__init__(self)
        self.set_transient_for(parent.get_toplevel())

        self.set_program_name('Zim')
        self.set_version(zim.__version__)
        self.set_comments(_('A desktop wiki'))
        # T: General description of zim itself
        file = data_file('zim.png')
        pixbuf = GdkPixbuf.Pixbuf.new_from_file(file.path)
        self.set_logo(pixbuf)
        self.set_copyright(zim.__copyright__)
        self.set_license(zim.__license__)
        self.set_authors([zim.__author__])
        self.set_translator_credits(_('translator-credits'))
        # T: This string needs to be translated with names of the translators for this language
        self.set_website(zim.__url__)
Example #17
0
    def __init__(self, notebook, page, navigation, editable=True):
        Window.__init__(self)
        self.navigation = navigation
        self.notebook = notebook

        headerbar = Gtk.HeaderBar()
        headerbar.set_show_close_button(True)

        action = self.toggle_editable
        button = action.create_icon_button()
        headerbar.pack_end(button)

        self.set_titlebar(headerbar)

        self.set_title(page.name)
        #if ui.notebook.icon:
        #	try:
        #		self.set_icon_from_file(ui.notebook.icon)
        #	except GObject.GError:
        #		logger.exception('Could not load icon %s', ui.notebook.icon)

        self.notebook = notebook
        self.page = notebook.get_page(page)

        self.uistate = notebook.state['PageWindow']
        self.uistate.setdefault('windowsize', (500, 400), check=value_is_coord)
        w, h = self.uistate['windowsize']
        self.set_default_size(w, h)

        self.pageview = PageView(notebook, navigation)
        self.connect_object('readonly-changed', PageView.set_readonly,
                            self.pageview)
        self.pageview.set_page(self.page)
        self.add(self.pageview)

        # Need UIManager to make accelerators work
        self.uimanager = Gtk.UIManager()
        self.add_accel_group(self.uimanager.get_accel_group())
        group = get_gtk_actiongroup(self.pageview)
        self.uimanager.insert_action_group(group, 0)
        fname = 'pagewindow_ui.xml'
        self.uimanager.add_ui_from_string(data_file(fname).read())

        # Close window when page is moved or deleted
        def on_notebook_change(o, path, *a):
            if path == self.page:
                logger.debug('Close PageWindow for %s (page is gone)',
                             self.page)
                self._save_uistate()
                self.destroy()

        notebook.connect('deleted-page', on_notebook_change)
        notebook.connect('moved-page', on_notebook_change)

        # setup state
        if self.notebook.readonly:
            self.toggle_editable(False)
            self.toggle_editable.set_sensitive(False)
        else:
            self.toggle_editable(editable)

        # on close window
        def do_delete_event(*a):
            logger.debug('Close PageWindow for %s', self.page)
            self._save_uistate()

        self.connect('delete-event', do_delete_event)
Example #18
0
File: www.py Project: gdw2/zim
	def __call__(self, environ, start_response):
		'''Main function for handling a single request. Follows the
		WSGI API.

		@param environ: dictionary with environment variables for the
		request and some special variables. See the PEP for expected
		variables.

		@param start_response: a function that can be called to set the
		http response and headers. For example::

			start_response(200, [('Content-Type', 'text/plain')])

		@returns: the html page content as a list of lines
		'''
		headerlist = []
		headers = Headers(headerlist)
		path = environ.get('PATH_INFO', '/')
		try:
			methods = ('GET', 'HEAD')
			if not environ['REQUEST_METHOD'] in methods:
				raise WWWError('405', headers=[('Allow', ', '.join(methods))])

			# cleanup path
			#~ print 'INPUT', path
			path = path.replace('\\', '/') # make it windows save
			isdir = path.endswith('/')
			parts = [p for p in path.split('/') if p and not p == '.']
			if [p for p in parts if p.startswith('.')]:
				# exclude .. and all hidden files from possible paths
				raise PathNotValidError()
			path = '/' + '/'.join(parts)
			if isdir and not path == '/': path += '/'
			#~ print 'PATH', path

			if not path:
				path = '/'
			elif path == '/favicon.ico':
				path = '/+resources/favicon.ico'
			else:
				path = urllib.unquote(path)

			if path == '/':
				headers.add_header('Content-Type', 'text/html', charset='utf-8')
				content = self.render_index()
			elif path.startswith('/+docs/'):
				dir = self.notebook.document_root
				if not dir:
					raise PageNotFoundError(path)
				file = dir.file(path[7:])
				content = [file.raw()]
					# Will raise FileNotFound when file does not exist
				headers['Content-Type'] = file.get_mimetype()
			elif path.startswith('/+file/'):
				file = self.notebook.dir.file(path[7:])
					# TODO: need abstraction for getting file from top level dir ?
				content = [file.raw()]
					# Will raise FileNotFound when file does not exist
				headers['Content-Type'] = file.get_mimetype()
 			elif path.startswith('/+resources/'):
				if self.template.resources_dir:
					file = self.template.resources_dir.file(path[12:])
					if not file.exists():
						file = data_file('pixmaps/%s' % path[12:])
				else:
					file = data_file('pixmaps/%s' % path[12:])

				if file:
					content = [file.raw()]
						# Will raise FileNotFound when file does not exist
					headers['Content-Type'] = file.get_mimetype()
	 			else:
					raise PageNotFoundError(path)
			else:
				# Must be a page or a namespace (html file or directory path)
				headers.add_header('Content-Type', 'text/html', charset='utf-8')
				if path.endswith('.html'):
					pagename = path[:-5].replace('/', ':')
				elif path.endswith('/'):
					pagename = path[:-1].replace('/', ':')
				else:
					raise PageNotFoundError(path)

				path = self.notebook.resolve_path(pagename)
				page = self.notebook.get_page(path)
				if page.hascontent:
					content = self.render_page(page)
				elif page.haschildren:
					content = self.render_index(page)
				else:
					raise PageNotFoundError(page)
		except Exception, error:
			headerlist = []
			headers = Headers(headerlist)
			headers.add_header('Content-Type', 'text/plain', charset='utf-8')
			if isinstance(error, (WWWError, FileNotFoundError)):
				logger.error(error.msg)
				if isinstance(error, FileNotFoundError):
					error = PageNotFoundError(path)
					# show url path instead of file path
				if error.headers:
					for key, value in error.headers:
						headers.add_header(key, value)
				start_response(error.status, headerlist)
				content = unicode(error).splitlines(True)
			# TODO also handle template errors as special here
			else:
				# Unexpected error - maybe a bug, do not expose output on bugs
				# to the outside world
				logger.exception('Unexpected error:')
				start_response('500 Internal Server Error', headerlist)
				content = ['Internal Server Error']
			if environ['REQUEST_METHOD'] == 'HEAD':
				return []
			else:
				return [string.encode('utf-8') for string in content]
Example #19
0
	def __init__(self):
		file = data_file('templates/_Equation.tex')
		assert file, 'BUG: could not find templates/_Equation.tex'
		self.template = GenericTemplate(file.readlines(), name=file)
		self.texfile = TmpFile('latex-equation.tex')
Example #20
0
from zim import NotebookInterface
from zim.errors import Error
from zim.notebook import Path, Page, IndexPage, PageNameError
from zim.fs import *
from zim.formats import ParseTree, TreeBuilder, BaseLinker
from zim.config import data_file
from zim.stores import encode_filename


logger = logging.getLogger('zim.www')


# TODO FIXME HACK - this translation needs to be done when exporting
icons = {}
for icon in ('checked-box.png', 'xchecked-box.png', 'unchecked-box.png'):
	file = data_file('pixmaps/'+icon)
	icons[file.path] = icon


class WWWError(Error):

	statusstring = {
		'404': 'Not Found',
		'405': 'Method Not Allowed',
		'500': 'Internal Server Error',
	}

	def __init__(self, msg, status='500', headers=None):
		self.status = '%s %s' % (status, self.statusstring[status])
		self.headers = headers
		self.msg = self.status
Example #21
0
 def __init__(self, plugin):
     ImageGeneratorClass.__init__(self, plugin)
     file = data_file('templates/plugins/equationeditor.tex')
     assert file, 'BUG: could not find templates/plugins/equationeditor.tex'
     self.template = GenericTemplate(file.readlines(), name=file)
     self.texfile = TmpFile(self.scriptname)
Example #22
0
 def icon(self, name):
     '''Returns an url for an icon'''
     if not name in self._icons:
         self._icons[name] = data_file('pixmaps/%s.png' % name).uri
     return self._icons[name]
Example #23
0
	def main(self):
		# Set window icon in case we open the notebook dialog
		icon = data_file('zim.png').path
		gtk.window_set_default_icon(gtk.gdk.pixbuf_new_from_file(icon))

		gtk.main()
Example #24
0
	def __init__(self):
		gtk.StatusIcon.__init__(self)
		self.set_from_file(data_file('zim.png').path)
		self.set_tooltip(_('Zim Desktop Wiki')) # T: tooltip for tray icon
		self.connect('popup-menu', self.__class__.do_popup_menu)
Example #25
0
    def _init_inputs(self,
                     namespace,
                     basename,
                     append,
                     text,
                     template_options,
                     custom=None):
        if template_options is None:
            template_options = {}
        else:
            template_options = template_options.copy()

        if namespace is not None and basename is not None:
            page = namespace + ':' + basename
        else:
            page = namespace or basename

        self.form.add_inputs((
            ('page', 'page', _('Page')),
            ('namespace', 'namespace', _('Namespace')),  # T: text entry field
            ('new_page', 'bool', _('Create a new page for each note')
             ),  # T: checkbox in Quick Note dialog
            ('basename', 'string', _('Title'))  # T: text entry field
        ))
        self.form.update({
            'page': page,
            'namespace': namespace,
            'new_page': True,
            'basename': basename,
        })

        self.uistate.setdefault('open_page', True)
        self.uistate.setdefault('new_page', True)

        if basename:
            self.uistate['new_page'] = True  # Be consistent with input

        # Set up the inputs and set page/ namespace to switch on
        # toggling the checkbox
        self.form.widgets['page'].set_no_show_all(True)
        self.form.widgets['namespace'].set_no_show_all(True)
        if append is None:
            self.form['new_page'] = bool(self.uistate['new_page'])
        else:
            self.form['new_page'] = not append

        def switch_input(*a):
            if self.form['new_page']:
                self.form.widgets['page'].hide()
                self.form.widgets['namespace'].show()
                self.form.widgets['basename'].set_sensitive(True)
            else:
                self.form.widgets['page'].show()
                self.form.widgets['namespace'].hide()
                self.form.widgets['basename'].set_sensitive(False)

        switch_input()
        self.form.widgets['new_page'].connect('toggled', switch_input)

        self.open_page = gtk.CheckButton(
            _('Open _Page'))  # T: Option in quicknote dialog
        # Don't use "O" as accelerator here to avoid conflict with "Ok"
        self.open_page.set_active(self.uistate['open_page'])
        self.action_area.pack_start(self.open_page, False)
        self.action_area.set_child_secondary(self.open_page, True)

        # Add the main textview and hook up the basename field to
        # sync with first line of the textview
        window, textview = ScrolledTextView()
        self.textview = textview
        self.textview.set_editable(True)
        self.vbox.add(window)

        self.form.widgets['basename'].connect('changed', self.on_title_changed)
        self.textview.get_buffer().connect('changed', self.on_text_changed)

        # Initialize text from template
        file = data_file('templates/plugins/quicknote.txt')
        template = GenericTemplate(file.readlines(), name=file)
        template_options.update({
            'text': text or '',
            'strftime': StrftimeFunction(),
        })
        output = template.process(template_options)
        buffer = self.textview.get_buffer()
        buffer.set_text(''.join(output))
        begin, end = buffer.get_bounds()
        buffer.place_cursor(begin)

        buffer.set_modified(False)

        self.connect('delete-event', self.do_delete_event)
Example #26
0
    def __call__(self, environ, start_response):
        '''Main function for handling a single request. Follows the
		WSGI API.

		@param environ: dictionary with environment variables for the
		request and some special variables. See the PEP for expected
		variables.

		@param start_response: a function that can be called to set the
		http response and headers. For example::

			start_response(200, [('Content-Type', 'text/plain')])

		@returns: the html page content as a list of lines
		'''
        headerlist = []
        headers = Headers(headerlist)
        path = environ.get('PATH_INFO', '/')
        try:
            methods = ('GET', 'HEAD')
            if not environ['REQUEST_METHOD'] in methods:
                raise WWWError('405', headers=[('Allow', ', '.join(methods))])

            # cleanup path
            #~ print 'INPUT', path
            path = path.replace('\\', '/')  # make it windows save
            isdir = path.endswith('/')
            parts = [p for p in path.split('/') if p and not p == '.']
            if [p for p in parts if p.startswith('.')]:
                # exclude .. and all hidden files from possible paths
                raise WebPathNotValidError()
            path = '/' + '/'.join(parts)
            if isdir and not path == '/':
                path += '/'
            #~ print 'PATH', path

            if not path:
                path = '/'
            elif path == '/favicon.ico':
                path = '/+resources/favicon.ico'
            else:
                path = urllib.unquote(path)

            if path == '/':
                headers.add_header('Content-Type',
                                   'text/html',
                                   charset='utf-8')
                content = self.render_index()
            elif path.startswith('/+docs/'):
                dir = self.notebook.document_root
                if not dir:
                    raise WebPageNotFoundError(path)
                file = dir.file(path[7:])
                content = [file.raw()]
                # Will raise FileNotFound when file does not exist
                headers['Content-Type'] = file.get_mimetype()
            elif path.startswith('/+file/'):
                file = self.notebook.dir.file(path[7:])
                # TODO: need abstraction for getting file from top level dir ?
                content = [file.raw()]
                # Will raise FileNotFound when file does not exist
                headers['Content-Type'] = file.get_mimetype()
            elif path.startswith('/+resources/'):
                if self.template.resources_dir:
                    file = self.template.resources_dir.file(path[12:])
                    if not file.exists():
                        file = data_file('pixmaps/%s' % path[12:])
                else:
                    file = data_file('pixmaps/%s' % path[12:])

                if file:
                    content = [file.raw()]
                    # Will raise FileNotFound when file does not exist
                    headers['Content-Type'] = file.get_mimetype()
                else:
                    raise WebPageNotFoundError(path)
            else:
                # Must be a page or a namespace (html file or directory path)
                headers.add_header('Content-Type',
                                   'text/html',
                                   charset='utf-8')
                if path.endswith('.html'):
                    pagename = path[:-5].replace('/', ':')
                elif path.endswith('/'):
                    pagename = path[:-1].replace('/', ':')
                else:
                    raise WebPageNotFoundError(path)

                path = self.notebook.pages.lookup_from_user_input(pagename)
                try:
                    page = self.notebook.get_page(path)
                    if page.hascontent:
                        content = self.render_page(page)
                    elif page.haschildren:
                        content = self.render_index(page)
                    else:
                        raise WebPageNotFoundError(path)
                except PageNotFoundError:
                    raise WebPageNotFoundError(path)
        except Exception as error:
            headerlist = []
            headers = Headers(headerlist)
            headers.add_header('Content-Type', 'text/plain', charset='utf-8')
            if isinstance(error, (WWWError, FileNotFoundError)):
                logger.error(error.msg)
                if isinstance(error, FileNotFoundError):
                    error = WebPageNotFoundError(path)
                    # show url path instead of file path
                if error.headers:
                    for key, value in error.headers:
                        headers.add_header(key, value)
                start_response(error.status, headerlist)
                content = unicode(error).splitlines(True)
            # TODO also handle template errors as special here
            else:
                # Unexpected error - maybe a bug, do not expose output on bugs
                # to the outside world
                logger.exception('Unexpected error:')
                start_response('500 Internal Server Error', headerlist)
                content = ['Internal Server Error']
            if environ['REQUEST_METHOD'] == 'HEAD':
                return []
            else:
                return [string.encode('utf-8') for string in content]
        else:
            start_response('200 OK', headerlist)
            if environ['REQUEST_METHOD'] == 'HEAD':
                return []
            elif 'utf-8' in headers['Content-Type']:
                return [string.encode('utf-8') for string in content]
            else:
                return content
Example #27
0
def main(*args):
    options = {}
    template_options = {}
    for arg in args:
        if arg.startswith("option:"):
            arg = arg[7:]
            dict = template_options
        else:
            dict = options

        if "=" in arg:
            key, value = arg.split("=", 1)
            dict[key] = value
        else:
            dict[arg] = True
    # ~ print 'OPTIONS:', options, template_options

    if "help" in options:
        print usagehelp
        return

    if "notebook" in options:
        notebook, page = resolve_notebook(options["notebook"])
    else:
        notebook = None

    if "append" in options:
        if options["append"].lower() == "true":
            options["append"] = True
        else:
            options["append"] = False

    if "input" in options:
        if options["input"] == "stdin":
            import sys

            text = sys.stdin.read()
        elif options["input"] == "clipboard":
            text = SelectionClipboard.get_text() or Clipboard.get_text()
    else:
        text = options.get("text")

    if text and options.get("encoding"):
        if options["encoding"] == "base64":
            import base64

            text = base64.b64decode(text)
        elif options["encoding"] == "url":
            from zim.parsing import url_decode, URL_ENCODE_DATA

            text = url_decode(text, mode=URL_ENCODE_DATA)
        else:
            raise AssertionError, "Unknown encoding: %s" % options["encoding"]

    if text and not isinstance(text, unicode):
        text = text.decode("utf-8")

    icon = data_file("zim.png").path
    gtk_window_set_default_icon()

    dialog = QuickNoteDialog(
        None,
        notebook,
        options.get("namespace"),
        options.get("basename"),
        options.get("append"),
        text,
        template_options,
        options.get("attachments"),
    )
    dialog.run()
Example #28
0
 def icon(self, name):
     """Returns a path or url for an icon"""
     if not name in self._icons:
         self._icons[name] = data_file("pixmaps/%s.png" % name).uri
     return self._icons[name]
Example #29
0
	def __init__(self, server):
		'''Constructor needs a Server object to control'''
		gtk.Window.__init__(self)
		self.set_icon_from_file(data_file('zim.png').path)
			# TODO new icon for WWW frontend
		self.set_border_width(10)
		self.connect('destroy', lambda a: gtk.main_quit())

		self.server = server
		self.server.connect_after('started', self.do_server_started)
		self.server.connect_after('stopped', self.do_server_stopped)

		def _start(*a):
			self.server.set_notebook(
				self.notebookcombobox.get_notebook() )
			self.server.start()

		def _stop(*a): self.server.stop()

		# Build the interface
		vbox = gtk.VBox()
		self.add(vbox)

		# first some art work
		#~ path = data_file('globe_banner_small.png').path
		#~ image = gtk.Image()
		#~ image.set_from_file(path) # new_from_file not in 2.6
		#~ align = gtk.Alignment(0,0.5, 0,0)
		#~ align.add(image)
		#~ vbox.add(align)

		# Table with status
		table = gtk.Table(4, 2, False)
		table.set_col_spacings(12)
		table.set_row_spacings(5)
		hbox = gtk.HBox()
		hbox.pack_start(table, False)
		vbox.pack_start(hbox, False)

		self.status_icon = gtk.image_new_from_stock(*stock_stopped)
		table.attach(self.status_icon, 0,2, 0,2)
		self.status_label = gtk.Label()
		self.status_label.set_markup('<i>'+_('Server not started')+'</i>')
			# T: Status in web server gui
		table.attach(self.status_label, 4,5, 0,1)
		self.link_button = gtk.LinkButton('') # FIXME since 2.10
		self.link_button.set_sensitive(False)
		gtk.link_button_set_uri_hook(lambda o, url: webbrowser.open(url))
		table.attach(self.link_button, 4,5, 1,2)

		start_button = IconButton('gtk-media-play')
		start_button.connect('clicked', _start)
		table.attach(start_button, 2,3, 0,1)
		stop_button = IconButton('gtk-media-stop')
		stop_button.connect('clicked', _stop)
		table.attach(stop_button, 3,4, 0,1)

		# Table with server properties
		table = gtk.Table(3, 3, False)
		table.set_col_spacings(12)
		table.set_row_spacings(5)
		vbox.add(table)

		table.attach(gtk.Label(_('Notebook')+': '), 0,1, 0,1)
			# T: Field in web server gui
		self.notebookcombobox = NotebookComboBox(current=server.interface.notebook)
		self.notebookcombobox.connect('changed', _stop)
		table.attach(self.notebookcombobox, 1,2, 0,1)

		open_button = IconButton('gtk-index')
		open_button.connect('clicked', lambda *a: NotebookDialog(self).run())
		table.attach(open_button, 2,3, 0,1)

		table.attach(gtk.Label(_('Port')+': '), 0,1, 1,2)
			# T: Field in web server gui for HTTLP port (e.g. port 80)
		self.portentry = gtk.SpinButton()
		self.portentry.set_numeric(True)
		self.portentry.set_range(80, 10000)
		self.portentry.set_increments(1, 80)
		self.portentry.set_value(self.server.port)
		self.portentry.connect('value-changed', _stop)
		self.portentry.connect('value-changed',
			lambda o: self.server.set_port(self.portentry.get_value_as_int()))
		table.attach(self.portentry, 1,2, 1,2)
    def __init__(self, notebook, page=None, fullscreen=False, geometry=None):
        '''Constructor
		@param notebook: the L{Notebook} to show in this window
		@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.preferences = ConfigManager.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
        self.uistate = notebook.state['MainWindow']
        self.uistate.setdefault('windowpos', None, check=value_is_coord)
        self.uistate.setdefault('windowsize', (600, 450), check=value_is_coord)
        self.uistate.setdefault('windowmaximized', False)
        self.uistate.setdefault('active_tabs', None, tuple)
        self.uistate.setdefault('show_toolbar', True)
        self.uistate.setdefault('show_statusbar', True)
        self.uistate.setdefault('readonly', False)

        self.history = History(notebook, notebook.state)

        # 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, 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)
        self.statusbar.set_property('spacing', 0)

        def statusbar_element(string, size):
            frame = Gtk.Frame()
            frame.set_shadow_type(Gtk.ShadowType.NONE)
            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_insert_label = statusbar_element('INS', 60)
        self.statusbar_style_label = statusbar_element('<style>', 110)

        # 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.NONE)
        self.statusbar.pack_end(Gtk.Separator(), False, True, 0)
        self.statusbar.pack_end(frame, False, True, 0)
        self.statusbar.pack_end(Gtk.Separator(), 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.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)
        # don't use mnemonics on macOS to allow alt-<letter> shortcuts
        global MENU_ACTIONS
        if sys.platform == "darwin":
            MENU_ACTIONS = tuple(
                (t[0], t[1], t[2].replace('_', '')) for t in MENU_ACTIONS)
        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())
        self.pageview.emit(
            'ui-init')  # Needs to trigger after default menus are build

        # Do this last, else menu items show up in wrong place
        self._customtools = CustomToolManagerUI(self.uimanager, 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()
Example #31
0
File: __init__.py Project: gdw2/zim
	def icon(self, name):
		'''Returns an url for an icon'''
		if not name in self._icons:
			self._icons[name] = data_file('pixmaps/%s.png' % name).uri
		return self._icons[name]
Example #32
0
    def export_all(self, dir, callback=None):
        '''Export all pages in the notebook

		Will also copy all attachments and created a folder with icons
		for checkboxes etc. So the resulting folder should contain all
		the notebook information.

		@param dir: a L{Dir} object for the target folder
		@param callback: a callback function that will be called after
		each page being exported with the page object as single argument.
		If the function returns C{False} the export is canceled.

		@returns: C{False} if the action was cancelled, C{True} otherwise
		'''
        logger.info('Exporting notebook to %s', dir)
        self.linker.target_dir = dir  # Needed to resolve icons

        # Copy icons
        for name in ('checked-box', 'unchecked-box', 'xchecked-box'):
            icon = data_file('pixmaps/%s.png' % name)
            file = dir.file('_resources/' + name + '.png')
            icon.copyto(file)

        # Copy template resources (can overwrite icons)
        if self.template and self.template.resources_dir \
        and self.template.resources_dir.exists():
            resources = dir.subdir('_resources')
            self.template.resources_dir.copyto(resources)

        # Set special pages
        if self.index_page:
            indexpage = Page(Path(self.index_page))
        else:
            indexpage = None

        pages = {
            'index': indexpage,
            'home': self.notebook.get_home_page(),
        }

        # Export the pages
        prev, current, next = None, None, None
        for page in self.notebook.walk():
            if page.hascontent:
                prev, current, next = current, next, page  # shift
                if current:
                    pages['previous'] = prev
                    pages['next'] = next
                    self.export_page(dir, current, pages, use_namespace=True)
                    if callback and not callback(current):
                        logger.warn('Export canceled')
                        return False

        prev, current, next = current, next, None  # shift once more
        if current:
            pages['previous'] = prev
            pages['next'] = next
            self.export_page(dir, current, pages, use_namespace=True)
            if callback and not callback(current):
                logger.warn('Export canceled')
                return False

        # Generate index page
        if indexpage:
            _page = IndexPage(self.notebook, Path(':'))
            # Bit of a HACK here - need better support for these index pages
            indexpage.readonly = False
            indexpage.set_parsetree(_page.get_parsetree())
            indexpage.readonly = True
            self.export_page(dir, indexpage, use_namespace=True)

        self.linker.target_dir = None  # reset
        logger.info('Export done')
        return True
Example #33
0
 def __init__(self):
     file = data_file('templates/plugins/equationeditor.tex')
     assert file, 'BUG: could not find templates/plugins/equationeditor.tex'
     self.template = GenericTemplate(file.readlines(), name=file)
     self.texfile = TmpFile(self.scriptname)
Example #34
0
    def __init__(self, notebook, page=None, fullscreen=False, geometry=None):
        '''Constructor
		@param notebook: the L{Notebook} to show in this window
		@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.preferences = ConfigManager.preferences['GtkInterface']
        self.preferences.define(
            toggle_on_ctrlspace=Boolean(False),
            always_use_last_cursor_pos=Boolean(True),
        )
        self.preferences.connect('changed', self.do_preferences_changed)

        self.maximized = False
        self.isfullscreen = False
        self._init_fullscreen_headerbar()
        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
        self.uistate = notebook.state['MainWindow']
        self.uistate.setdefault('windowpos', None, check=value_is_coord)
        self.uistate.setdefault('windowsize', (600, 450), check=value_is_coord)
        self.uistate.setdefault('windowmaximized', False)
        self.uistate.setdefault('active_tabs', None, tuple)
        self.uistate.setdefault('readonly', False)

        self.history = History(notebook, notebook.state)

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

        # setup menubar
        self.add_accel_group(self.uimanager.get_accel_group())
        self.menubar = self.uimanager.get_widget('/menubar')
        self.add_bar(self.menubar, position=TOP)

        self.pageview = NotebookView(self.notebook, self.navigation)
        self.connect_object('readonly-changed', NotebookView.set_readonly,
                            self.pageview)

        self.add(self.pageview)

        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.navigation)
        self.__zim_extension_objects__.append(
            self._uiactions)  # HACK to make actions discoverable
        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)

        self.open_page_back.set_sensitive(False)
        self.open_page_forward.set_sensitive(False)

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

        # header Bar
        self._headerbar = Gtk.HeaderBar()
        self._headerbar.set_show_close_button(True)
        self.set_titlebar(self._headerbar)

        self._populate_headerbars()

        # Do this last, else menu items show up in wrong place
        self._customtools = CustomToolManagerUI(self.uimanager, 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()

        PluginManager.register_new_extendable(self.pageview)
        initialize_actiongroup(self, 'win')

        self.pageview.grab_focus()
Example #35
0
	def __call__(self, environ, start_response):
		'''Main function for handling a single request. Arguments are the file
		handle to write the output to and the path to serve. Any exceptions
		will result in a error response being written.

		First argument is a dictionary with environment variables and some special
		variables. See the PEP for expected variables. The second argument is a
		function that can be called for example like:

			start_response(200, [('Content-Type', 'text/plain')])

		This method is supposed to take care of sending the response line and
		the headers.

		The return value of this call is a list of lines with the content to
		be served.
		'''
		headerlist = []
		headers = Headers(headerlist)
		path = environ.get('PATH_INFO', '/')
		try:
			methods = ('GET', 'HEAD')
			if not environ['REQUEST_METHOD'] in methods:
				raise WWWError('405', headers=[('Allow', ', '.join(methods))])

			# TODO clean up path from any '../' (and ..\)

			if not path:
				path = '/'
			elif path == '/favicon.ico':
				path = '/+icons/favicon.ico'
			elif path in icons:
				# TODO FIXME HACK - this translation needs to be done when exporting
				path = '/+icons/' + icons[path]

			if self.notebook is None:
				raise NoConfigError
			elif path == '/':
				headers.add_header('Content-Type', 'text/html', charset='utf-8')
				content = self.render_index()
			elif path.startswith('/+docs/'):
				pass # TODO document root
			elif path.startswith('/+file/'):
				pass # TODO attachment or raw source
			elif path.startswith('/+icons/'):
				# TODO check if favicon is overridden or something
				file = data_file('pixmaps/%s' % path[8:])
				if path.endswith('.png'):
					headers['Content-Type'] = 'image/png'
				elif path.endswith('.ico'):
					headers['Content-Type'] = 'image/vnd.microsoft.icon'
				content = [file.read(encoding=None)]
			else:
				# Must be a page or a namespace (html file or directory path)
				headers.add_header('Content-Type', 'text/html', charset='utf-8')
				if path.endswith('.html'):
					pagename = path[:-5].replace('/', ':')
				elif path.endswith('/'):
					pagename = path[:-1].replace('/', ':')
				else:
					raise PageNotFoundError(path)

				pagename = urllib.unquote(pagename)
				path = self.notebook.resolve_path(pagename)
				page = self.notebook.get_page(path)
				if page.hascontent:
					content = self.render_page(page)
				elif page.haschildren:
					content = self.render_index(page)
				else:
					raise PageNotFoundError(page)
		except Exception, error:
			headerlist = []
			headers = Headers(headerlist)
			headers.add_header('Content-Type', 'text/plain', charset='utf-8')
			if isinstance(error, WWWError):
				logger.error(error.msg)
				if error.headers:
					header.extend(error.headers)
				start_response(error.status, headerlist)
				content = unicode(error).splitlines(True)
			# TODO also handle template errors as special here
			else:
				# Unexpected error - maybe a bug, do not expose output on bugs
				# to the outside world
				logger.exception('Unexpected error:')
				start_response('500 Internal Server Error', headerlist)
				content = ['Internal Server Error']
			if environ['REQUEST_METHOD'] == 'HEAD':
				return []
			else:
				return [string.encode('utf-8') for string in content]
Example #36
0
    def export_all(self, dir, callback=None):
        '''Export all pages in the notebook

        Will also copy all attachments and created a folder with icons
        for checkboxes etc. So the resulting folder should contain all
        the notebook information.

        @param dir: a L{Dir} object for the target folder
        @param callback: a callback function that will be called after
        each page being exported with the page object as single argument.
        If the function returns C{False} the export is canceled.

        @returns: C{False} if the action was cancelled, C{True} otherwise
        '''
        logger.info('Exporting notebook to %s', dir)
        self.linker.target_dir = dir # Needed to resolve icons

        # Copy icons
        for name in ('checked-box', 'unchecked-box', 'xchecked-box'):
            icon = data_file('pixmaps/%s.png' % name)
            file = dir.file('_resources/' + name + '.png')
            icon.copyto(file)

        # Copy template resources (can overwrite icons)
        if self.template and self.template.resources_dir \
        and self.template.resources_dir.exists():
            resources = dir.subdir('_resources')
            self.template.resources_dir.copyto(resources)

        # Set special pages
        if self.index_page:
            indexpage = Page(Path(self.index_page))
        else:
            indexpage = None

        pages = {
            'index': indexpage,
            'home': self.notebook.get_home_page(),
        }

        # Export the pages
        prev, current, next = None, None, None
        for page in self.notebook.walk():
            if page.hascontent:
                prev, current, next = current, next, page # shift
                if current:
                    pages['previous'] = prev
                    pages['next'] = next
                    self.export_page(dir, current, pages, use_namespace=True)
                    if callback and not callback(current):
                        logger.warn('Export canceled')
                        return False

        prev, current, next = current, next, None # shift once more
        if current:
            pages['previous'] = prev
            pages['next'] = next
            self.export_page(dir, current, pages, use_namespace=True)
            if callback and not callback(current):
                logger.warn('Export canceled')
                return False

        # Generate index page
        if indexpage:
            _page = IndexPage(self.notebook, Path(':'))
            # Bit of a HACK here - need better support for these index pages
            indexpage.readonly = False
            indexpage.set_parsetree(_page.get_parsetree())
            indexpage.readonly = True
            self.export_page(dir, indexpage, use_namespace=True)

        self.linker.target_dir = None # reset
        logger.info('Export done')
        return True
Example #37
0
    def __init__(self, notebook, page, anchor, navigation, editable=True):
        Window.__init__(self)
        self._block_toggle_panes = False
        self._sidepane_autoclose = False
        self.navigation = navigation
        self.notebook = notebook
        self.page = notebook.get_page(page)
        self._headerbar = Gtk.HeaderBar()
        self._headerbar.set_show_close_button(True)
        self.set_titlebar(self._headerbar)

        self._init_fullscreen_headerbar()
        self._populate_headerbars()

        if self.notebook.readonly or self.page.readonly:
            title = page.name + ' [' + _(
                'readonly') + ']'  # T: page status for title bar
        else:
            title = page.name
        self.set_title(title)
        #if ui.notebook.icon:
        #	try:
        #		self.set_icon_from_file(ui.notebook.icon)
        #	except (GObject.GError, GLib.Error):
        #		logger.exception('Could not load icon %s', ui.notebook.icon)

        self.uistate = notebook.state['PageWindow']
        self.uistate.setdefault('windowsize', (500, 400), check=value_is_coord)
        w, h = self.uistate['windowsize']
        self.set_default_size(w, h)

        self.pageview = PageView(notebook, navigation)
        self.connect_object('readonly-changed', PageView.set_readonly,
                            self.pageview)
        self.pageview.set_page(self.page)
        self.add(self.pageview)

        # Need UIManager & menubar to make accelerators and plugin actions work
        self.uimanager = Gtk.UIManager()
        self.add_accel_group(self.uimanager.get_accel_group())

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

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

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

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

        self.menubar = self.uimanager.get_widget('/menubar')
        self.add_bar(self.menubar, position=TOP)

        # Close window when page is moved or deleted
        def on_notebook_change(o, path, *a):
            if path == self.page or self.page.ischild(path):
                logger.debug('Close PageWindow for %s (page is gone)',
                             self.page)
                self.save_uistate()
                self.destroy()

        notebook.connect('deleted-page', on_notebook_change)
        notebook.connect('moved-page', on_notebook_change)

        # setup state
        self.setup_toggle_editable_state(editable)

        # on close window
        def do_delete_event(*a):
            logger.debug('Close PageWindow for %s', self.page)
            self.save_uistate()

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

        PluginManager.register_new_extendable(self.pageview)
        initialize_actiongroup(self, 'win')

        if anchor:
            self.pageview.navigate_to_anchor(anchor)

        self.pageview.grab_focus()
Example #38
0
    def __call__(self, environ, start_response):
        '''Main function for handling a single request. Follows the
		WSGI API.

		@param environ: dictionary with environment variables for the
		request and some special variables. See the PEP for expected
		variables.

		@param start_response: a function that can be called to set the
		http response and headers. For example::

			start_response(200, [('Content-Type', 'text/plain')])

		@returns: the html page content as a list of lines
		'''
        if self.auth_creds:
            import base64

            def bad_auth():
                body = 'Please authenticate'
                realm = 'zimAuth'
                logger.info('Requesting Basic HTTP-Authentication')
                headers = [('Content-Type', 'text/plain'),
                           ('Content-Length', str(len(body))),
                           ('WWW-Authenticate', 'Basic realm="%s"' % realm)]
                start_response('401 Unauthorized', headers)
                return [body.encode()]

            auth = environ.get('HTTP_AUTHORIZATION')
            if auth:
                scheme, data = auth.split(None, 1)
                assert scheme.lower() == 'basic'
                username, password = base64.b64decode(data).decode(
                    'UTF-8').split(':')
                if username != self.auth_creds[
                        0] or password != self.auth_creds[1]:
                    return bad_auth()
                environ['REMOTE_USER'] = username
                del environ['HTTP_AUTHORIZATION']
            else:
                return bad_auth()

        headerlist = []
        headers = Headers(headerlist)
        path = environ.get('PATH_INFO', '/')
        path = path.encode('iso-8859-1').decode('UTF-8')
        # The WSGI standard mandates iso-8859-1, but we want UTF-8. See:
        # - https://www.python.org/dev/peps/pep-3333/#unicode-issues
        # - https://code.djangoproject.com/ticket/19468
        try:
            methods = ('GET', 'HEAD')
            if not environ['REQUEST_METHOD'] in methods:
                raise WWWError('405', headers=[('Allow', ', '.join(methods))])

            # cleanup path
            path = path.replace('\\', '/')  # make it windows save
            isdir = path.endswith('/')
            parts = [p for p in path.split('/') if p and not p == '.']
            if [p for p in parts if p.startswith('.')]:
                # exclude .. and all hidden files from possible paths
                raise WebPathNotValidError()
            path = '/' + '/'.join(parts)
            if isdir and not path == '/':
                path += '/'

            if not path:
                path = '/'
            elif path == '/favicon.ico':
                path = '/+resources/favicon.ico'
            else:
                path = urllib.parse.unquote(path)

            if path == '/':
                headers.add_header('Content-Type',
                                   'text/html',
                                   charset='utf-8')
                content = self.render_index()
            elif path.startswith('/+docs/'):
                dir = self.notebook.document_root
                if not dir:
                    raise WebPageNotFoundError(path)
                file = dir.file(path[7:])
                content = [file.raw()]
                # Will raise FileNotFound when file does not exist
                headers['Content-Type'] = file.get_mimetype()
            elif path.startswith('/+file/'):
                file = self.notebook.folder.file(path[7:])
                # TODO: need abstraction for getting file from top level dir ?
                content = [file.read_binary()]
                # Will raise FileNotFound when file does not exist
                headers['Content-Type'] = file.mimetype()
            elif path.startswith('/+resources/'):
                if self.template.resources_dir:
                    file = self.template.resources_dir.file(path[12:])
                    if not file.exists():
                        file = data_file('pixmaps/%s' % path[12:])
                else:
                    file = data_file('pixmaps/%s' % path[12:])

                if file:
                    content = [file.raw()]
                    # Will raise FileNotFound when file does not exist
                    headers['Content-Type'] = file.get_mimetype()
                else:
                    raise WebPageNotFoundError(path)
            else:
                # Must be a page or a namespace (html file or directory path)
                headers.add_header('Content-Type',
                                   'text/html',
                                   charset='utf-8')
                if path.endswith('.html'):
                    pagename = path[:-5].replace('/', ':')
                elif path.endswith('/'):
                    pagename = path[:-1].replace('/', ':')
                else:
                    raise WebPageNotFoundError(path)

                path = self.notebook.pages.lookup_from_user_input(pagename)
                try:
                    page = self.notebook.get_page(path)
                    if page.hascontent:
                        content = self.render_page(page)
                    elif page.haschildren:
                        content = self.render_index(page)
                    else:
                        raise WebPageNotFoundError(path)
                except PageNotFoundError:
                    raise WebPageNotFoundError(path)
        except Exception as error:
            headerlist = []
            headers = Headers(headerlist)
            headers.add_header('Content-Type', 'text/plain', charset='utf-8')
            if isinstance(error, (WWWError, FileNotFoundError)):
                logger.error(error.msg)
                if isinstance(error, FileNotFoundError):
                    error = WebPageNotFoundError(path)
                    # show url path instead of file path
                if error.headers:
                    for key, value in error.headers:
                        headers.add_header(key, value)
                start_response(error.status, headerlist)
                content = str(error).splitlines(True)
            # TODO also handle template errors as special here
            else:
                # Unexpected error - maybe a bug, do not expose output on bugs
                # to the outside world
                logger.exception('Unexpected error:')
                start_response('500 Internal Server Error', headerlist)
                content = ['Internal Server Error']

            if environ['REQUEST_METHOD'] == 'HEAD':
                return []
            else:
                return [c.encode('UTF-8') for c in content]
        else:
            start_response('200 OK', headerlist)
            if environ['REQUEST_METHOD'] == 'HEAD':
                return []
            elif content and isinstance(content[0], str):
                return [c.encode('UTF-8') for c in content]
            else:
                return content
Example #39
0
	def _init_inputs(self, namespace, basename, append, text, template_options, custom=None):
		if template_options is None:
			template_options = {}
		else:
			template_options = template_options.copy()

		if namespace is not None and basename is not None:
			page = namespace + ':' + basename
		else:
			page = namespace or basename

		self.form.add_inputs( (
				('page', 'page', _('Page')),
				('namespace', 'namespace', _('Namespace')), # T: text entry field
				('new_page', 'bool', _('Create a new page for each note')), # T: checkbox in Quick Note dialog
				('basename', 'string', _('Title')) # T: text entry field
			) )
		self.form.update({
				'page': page,
				'namespace': namespace,
				'new_page': True,
				'basename': basename,
			} )

		self.uistate.setdefault('open_page', True)
		self.uistate.setdefault('new_page', True)

		if basename:
			self.uistate['new_page'] = True # Be consistent with input

		# Set up the inputs and set page/ namespace to switch on
		# toggling the checkbox
		self.form.widgets['page'].set_no_show_all(True)
		self.form.widgets['namespace'].set_no_show_all(True)
		if append is None:
			self.form['new_page'] = bool(self.uistate['new_page'])
		else:
			self.form['new_page'] = not append

		def switch_input(*a):
			if self.form['new_page']:
				self.form.widgets['page'].hide()
				self.form.widgets['namespace'].show()
				self.form.widgets['basename'].set_sensitive(True)
			else:
				self.form.widgets['page'].show()
				self.form.widgets['namespace'].hide()
				self.form.widgets['basename'].set_sensitive(False)

		switch_input()
		self.form.widgets['new_page'].connect('toggled', switch_input)

		self.open_page = gtk.CheckButton(_('Open _Page')) # T: Option in quicknote dialog
			# Don't use "O" as accelerator here to avoid conflict with "Ok"
		self.open_page.set_active(self.uistate['open_page'])
		self.action_area.pack_start(self.open_page, False)
		self.action_area.set_child_secondary(self.open_page, True)

		# Add the main textview and hook up the basename field to
		# sync with first line of the textview
		window, textview = ScrolledTextView()
		self.textview = textview
		self.textview.set_editable(True)
		self.vbox.add(window)

		self.form.widgets['basename'].connect('changed', self.on_title_changed)
		self.textview.get_buffer().connect('changed', self.on_text_changed)

		# Initialize text from template
		file = data_file('templates/plugins/quicknote.txt')
		template = GenericTemplate(file.readlines(), name=file)
		template_options.update({
			'text': text or '',
			'strftime': StrftimeFunction(),
		} )
		output = template.process(template_options)
		buffer = self.textview.get_buffer()
		buffer.set_text(''.join(output))
		begin, end = buffer.get_bounds()
		buffer.place_cursor(begin)

		buffer.set_modified(False)

		self.connect('delete-event', self.do_delete_event)
Example #40
0
 def __init__(self):
     file = data_file('templates/plugins/gnu_r_editor.r')
     assert file, 'BUG: could not find templates/plugins/gnu_r_editor.r'
     self.template = GenericTemplate(file.readlines(), name=file)
     self.plotscriptfile = TmpFile(self.scriptname)
Example #41
0
def main(*args):
	options = {}
	template_options = {}
	for arg in args:
		if arg.startswith('option:'):
			arg = arg[7:]
			dict = template_options
		else:
			dict = options

		if '=' in arg:
			key, value = arg.split('=', 1)
			dict[key] = value
		else:
			dict[arg] = True
	#~ print 'OPTIONS:', options, template_options

	if 'help' in options:
		print usagehelp
		return

	if 'notebook' in options:
		notebook, page = resolve_notebook(options['notebook'])
	else:
		notebook = None

	if 'append' in options:
		if options['append'].lower() == 'true':
			options['append'] = True
		else:
			options['append'] = False

	if 'input' in options:
		if options['input'] == 'stdin':
			import sys
			text = sys.stdin.read()
		elif options['input'] == 'clipboard':
			text = \
				SelectionClipboard.get_text() \
				or Clipboard.get_text()
	else:
		text = options.get('text')

	if text and options.get('encoding'):
		if options['encoding'] == 'base64':
			import base64
			text = base64.b64decode(text)
		elif options['encoding'] == 'url':
			from zim.parsing import url_decode, URL_ENCODE_DATA
			text = url_decode(text, mode=URL_ENCODE_DATA)
		else:
			raise AssertionError, 'Unknown encoding: %s' % options['encoding']

	if text and not isinstance(text, unicode):
		text = text.decode('utf-8')

	icon = data_file('zim.png').path
	gtk_window_set_default_icon()

	dialog = QuickNoteDialog(None,
		notebook,
		options.get('namespace'), options.get('basename'),
		options.get('append'),
		text,
		template_options,
		options.get('attachments')
	)
	dialog.run()