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)
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)
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)
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']
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()
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()
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)))
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)))
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))
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)) )
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)) )
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__)
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)
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]
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')
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
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)
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]
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()
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)
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)
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
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()
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]
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()
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
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)
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()
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]
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()
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
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)
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)
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()