def testSaveCopyDialog(self): '''Test SaveCopyDialog''' tmp_dir = self.create_tmp_dir('testSaveCopyDialog') file = File((tmp_dir, 'save_copy.txt')) self.assertFalse(file.exists()) dialog = zim.gui.SaveCopyDialog(self.ui) dialog.set_file(file)
def get_template(format, template): '''Returns a Template object for a template name, file path, or File object''' # NOTE: here the "category" needs to be a format at the same time ! if isinstance(template, File): file = template else: if not is_path_re.match(template): file = None path = list(data_dirs(('templates', format))) path.reverse() for dir in path: for basename in dir.list(): name = basename.rsplit('.')[0] # robust if no '.' in basename if name == template: file = dir.file(basename) if file.exists(): # is a file break if not file: file = File(template) else: file = File(template) logger.info('Loading template from: %s', file) if not file.exists(): raise AssertionError, 'No such file: %s' % file basename, ext = file.basename.rsplit('.', 1) resources = file.dir.subdir(basename) return Template(file.readlines(), format, name=file.path, resources_dir=resources)
class DiagramGenerator(ImageGeneratorClass): uses_log_file = False type = 'diagram' scriptname = 'diagram.dot' imagename = 'diagram.png' def __init__(self): self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4 def generate_image(self, text): if isinstance(text, basestring): text = text.splitlines(True) # Write to tmp file self.dotfile.writelines(text) # Call GraphViz try: dot = Application(dotcmd) dot.run((self.pngfile, self.dotfile)) except ApplicationError: return None, None # Sorry, no log else: return self.pngfile, None def cleanup(self): self.dotfile.remove() self.pngfile.remove()
class DitaaGenerator(ImageGeneratorClass): uses_log_file = False object_type = "shaape" scriptname = "shaape.dia" imagename = "shaape.png" def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + ".png") # len('.dot') == 4 def generate_image(self, text): # Write to tmp file self.dotfile.write(text) # Call GraphViz try: dot = Application(dotcmd) dot.run(("-o", self.pngfile, self.dotfile)) except ApplicationError: return None, None # Sorry, no log else: return self.pngfile, None def cleanup(self): self.dotfile.remove() self.pngfile.remove()
class DiagramGenerator(object): # TODO: generic base class for image generators type = 'diagram' basename = 'diagram.dot' def __init__(self): self.dotfile = TmpFile('diagram-editor.dot') self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4 def generate_image(self, text): if isinstance(text, basestring): text = text.splitlines(True) # Write to tmp file self.dotfile.writelines(text) # Call GraphViz dot = Application(dotcmd) dot.run((self.pngfile, self.dotfile)) return self.pngfile, None def cleanup(self): self.dotfile.remove() self.pngfile.remove()
class PlantumlGenerator(ImageGeneratorClass): uses_log_file = False object_type = 'plantuml' scriptname = 'plantuml.pu' imagename = 'plantuml.png' def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-3] + '.png') # len('.pu') == 3 def generate_image(self, text): if isinstance(text, basestring): text = text.splitlines(True) # Write to tmp file self.dotfile.writelines(text) # Call PlantUML try: dot = Application(dotcmd) dot.run(('', self.dotfile)) except ApplicationError: return None, None # Sorry, no log else: return self.pngfile, None def cleanup(self): self.dotfile.remove() self.pngfile.remove()
class SequenceDiagramGenerator(ImageGeneratorClass): uses_log_file = False object_type = 'seqdiagram' scriptname = 'seqdiagram.diag' imagename = 'seqdiagram.png' def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.diagfile = TmpFile(self.scriptname) self.diagfile.touch() self.pngfile = File(self.diagfile.path[:-5] + '.png') # len('.diag') == 5 def generate_image(self, text): # Write to tmp file self.diagfile.write(text) # Call seqdiag try: diag = Application(diagcmd) diag.run((self.pngfile, self.diagfile)) except ApplicationError: return None, None # Sorry, no log else: return self.pngfile, None def cleanup(self): self.diagfile.remove() self.pngfile.remove()
def testImportPageDialog(self): '''Test ImportPageDialog''' tmp_dir = self.create_tmp_dir('testImportPageDialog') file = File((tmp_dir, 'import_page.txt')) file.write('test 123\n') self.assertTrue(file.exists()) dialog = zim.gui.ImportPageDialog(self.ui) dialog.set_file(file)
def runTest(self): from pprint import pprint from zim.fs import File file = File('./tests/data/TestTemplate.html') templ = Template(file) #~ pprint(templ.parts) # parser output output = [] templ.process(output, { 'title': 'THIS IS THE TITLE', 'generator': { 'name': 'ZIM VERSION', }, 'navigation': { 'prev': None, 'next': None, }, 'links': {}, 'pages': [ { # page 'name': 'page', 'heading': 'HEAD', 'body': 'BODY', 'properties': { 'type': 'PAGE', }, 'backlinks': [ {'name': 'LINK1'}, {'name': 'LINK2'}, {'name': 'LINK3'}, ], 'attachments': [ {'name': 'FILE1', 'basename': 'FILE1', 'size': '1k'}, {'name': 'FILE2', 'basename': 'FILE2', 'size': '1k'}, ], }, ], 'uri': ExpressionFunction(lambda l: "URL:%s" % l['name']), 'anchor': ExpressionFunction(lambda l: "ANCHOR:%s" % l['name']), }) #~ print ''.join(output) # TODO assert something ### Test empty template OK as well dir = Dir(self.create_tmp_dir()) file = dir.file('empty.html') self.assertRaises(FileNotFoundError, Template, file) file.touch() templ = Template(file) output = [] templ.process(output, {}) self.assertEqual(output, [])
def testPropertiesDialog(self): '''Test PropertiesDialog''' from zim.gui.propertiesdialog import PropertiesDialog self.ui.readonly = True dialog = PropertiesDialog(self.ui) dialog.assert_response_ok() from zim.config import INIConfigFile notebook = self.ui.notebook file = notebook.dir.file('notebook.zim') notebook.config = NotebookConfig(file) self.ui.readonly = False config1 = { 'name': 'Notebook Foo', 'interwiki': None, 'home': Path('Home'), 'icon': './icon.png', 'document_root': File('/foo').path, # win32 save test 'shared': False, 'profile': None, } config2 = { 'name': 'Notebook Bar', 'interwiki': 'FooBar', 'home': Path('HomeSweetHome'), 'icon': './picture.png', 'document_root': File('/bar').path, # win32 save test 'shared': True, 'profile': 'foo', } notebook.save_properties(**config1) for key in config1: self.assertEqual(notebook.config['Notebook'][key], config1[key]) dialog = PropertiesDialog(self.ui) dialog.assert_response_ok() for key in config1: self.assertEqual(notebook.config['Notebook'][key], config1[key]) self.assertEqual(notebook.name, config1['name']) self.assertEqual(notebook.get_home_page(), config1['home']) self.assertEqual(notebook.icon, notebook.dir.file(config1['icon']).path) self.assertEqual(notebook.document_root, Dir(config1['document_root'])) dialog = PropertiesDialog(self.ui) dialog.form.update(config2) dialog.assert_response_ok() for key in config1: self.assertEqual(notebook.config['Notebook'][key], config2[key]) self.assertEqual(notebook.name, config2['name']) self.assertEqual(notebook.get_home_page(), config2['home']) self.assertEqual(notebook.icon, notebook.dir.file(config2['icon']).path) self.assertEqual(notebook.document_root, Dir(config2['document_root']))
def set_basedirs(_ignore_test=False): '''This method sets the global configuration paths for according to the freedesktop basedir specification. Called automatically when module is first loaded, should be called explicitly only when environment has changed. ''' global ZIM_DATA_DIR global XDG_DATA_HOME global XDG_DATA_DIRS global XDG_CONFIG_HOME global XDG_CONFIG_DIRS global XDG_CACHE_HOME # Cast string to folder import zim zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data') if zim_data_dir.exists(): ZIM_DATA_DIR = zim_data_dir if os.name == 'nt': APPDATA = os.environ['APPDATA'] XDG_DATA_HOME = Dir( os.environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data')) XDG_DATA_DIRS = \ _split_environ_dir_list(os.environ.get('XDG_DATA_DIRS'), ('~/.local/share/',)) # Backwards compatibility XDG_CONFIG_HOME = Dir( os.environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config')) XDG_CONFIG_DIRS = \ _split_environ_dir_list(os.environ.get('XDG_CONFIG_DIRS'), ('~/.config/',)) # Backwards compatibility XDG_CACHE_HOME = Dir( os.environ.get('XDG_CACHE_HOME', APPDATA + r'\zim\cache')) else: XDG_DATA_HOME = Dir( os.environ.get('XDG_DATA_HOME', '~/.local/share/')) XDG_DATA_DIRS = \ _split_environ_dir_list(os.environ.get('XDG_DATA_DIRS'), ('/usr/share/', '/usr/local/share/')) XDG_CONFIG_HOME = Dir( os.environ.get('XDG_CONFIG_HOME', '~/.config/')) XDG_CONFIG_DIRS = \ _split_environ_dir_list(os.environ.get('XDG_CONFIG_DIRS'), ('/etc/xdg/',)) XDG_CACHE_HOME = Dir( os.environ.get('XDG_CACHE_HOME', '~/.cache')) if os.environ.get('ZIM_TEST_RUNNING') and not _ignore_test: # See tests/__init__.py, we load more folders then we really want # because the needs of Gtk, but want to restrict it here for all # zim internal use XDG_DATA_DIRS = [Dir(os.environ['TEST_XDG_DATA_DIRS'])]
def runTest(self): tmp_dir = self.create_tmp_dir() file = File((tmp_dir, 'test.txt')) file.write('test 123') self.assertTrue(file.exists()) dialog = FileDialog(None, 'Test') dialog.set_file(file)
def _get_path_object(path): if isinstance(path, str): file = File(path) if file.exists(): # exists and is a file path = file else: path = Dir(path) else: assert isinstance(path, (File, Dir)) return path
def build_notebook(location): '''Create a L{Notebook} object for a file location Tries to automount file locations first if needed @param location: a L{FilePath} or a L{NotebookInfo} @returns: a L{Notebook} object and a L{Path} object or C{None} @raises FileNotFoundError: if file location does not exist and could not be mounted ''' uri = location.uri page = None # Decipher zim+file:// uris if uri.startswith('zim+file://'): uri = uri[4:] if '?' in uri: uri, page = uri.split('?', 1) page = url_decode(page) page = Path(page) # Automount if needed filepath = FilePath(uri) if not (filepath.exists() or filepath.__add__('zim.notebook').exists()): # The folder of a mount point can exist, so check for specific content mount_notebook(filepath) if not filepath.exists(): raise FileNotFoundError(filepath) # Figure out the notebook dir if filepath.isdir(): dir = Dir(uri) file = None else: file = File(uri) dir = file.dir if file and file.basename == 'notebook.zim': file = None else: parents = list(dir) parents.reverse() for parent in parents: if parent.file('notebook.zim').exists(): dir = parent break # Resolve the page for a file if file: path = file.relpath(dir) if '.' in path: path, _ = path.rsplit('.', 1) # remove extension path = path.replace('/', ':') page = Path(path) # And finally create the notebook notebook = Notebook.new_from_dir(dir) return notebook, page
def get_file(self): file = File(self.uistate['output_file']) if file.exists(): ok = QuestionDialog(self, ( _('File exists'), # T: message heading _('This file already exists.\n' 'Do you want to overwrite it?') # T: detailed message, answers are Yes and No )).run() if not ok: return None return file
def get_file(self): file = File(self.uistate['output_file']) if file.exists(): ok = QuestionDialog(self, ( _('File exists'), # T: message heading _('This file already exists.\n' 'Do you want to overwrite it?' ) # T: detailed message, answers are Yes and No ) ).run() if not ok: return None return file
def delete_file(self, file=None, refresh=False): '''Deletes a file and refreshes the treeview if refresh == True''' if not file: file = self.selected_file refresh = True logger.debug('Deleting %s' % file) file = File(file) if file.exists(): file.cleanup() if refresh: self.treeview.model.remove(self.iter)
def get_template(format, name): '''Returns a Template object for a tempalte name or a file path''' if is_path_re.match(name): file = File(name) else: templates = list_templates(format) #~ if not name in templates: FIXME exception type #~ raise file = File(templates[name]) logger.info('Loading template from: %s', file) return Template(file.readlines(), format, name=file)
def _append(self, info): path = File(info.uri).path text = '<b>%s</b>\n<span foreground="#5a5a5a" size="small">%s</span>' % \ (encode_markup_text(info.name), encode_markup_text(path)) # T: Path label in 'open notebook' dialog if info.icon and File(info.icon).exists(): w, h = gtk.icon_size_lookup(gtk.ICON_SIZE_BUTTON) pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(File(info.icon).path, w, h) else: pixbuf = None self.append((False, info.name, text, pixbuf, info))
def set_basedirs(): '''This method sets the global configuration paths for according to the freedesktop basedir specification. Called automatically when module is first loaded, should be called explicitly only when environment has changed. ''' global ZIM_DATA_DIR global XDG_DATA_HOME global XDG_DATA_DIRS global XDG_CONFIG_HOME global XDG_CONFIG_DIRS global XDG_CACHE_HOME # Cast string to folder import zim zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data') if zim_data_dir.exists(): ZIM_DATA_DIR = zim_data_dir if os.name == 'nt': APPDATA = environ['APPDATA'] XDG_DATA_HOME = Dir( environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data')) XDG_DATA_DIRS = map(Dir, environ.get_list('XDG_DATA_DIRS', '~/.local/share/')) # Backwards compatibility XDG_CONFIG_HOME = Dir( environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config')) XDG_CONFIG_DIRS = map(Dir, environ.get_list('XDG_CONFIG_DIRS', '~/.config/')) # Backwards compatibility XDG_CACHE_HOME = Dir( environ.get('XDG_CACHE_HOME', APPDATA + r'\zim\cache')) else: XDG_DATA_HOME = Dir( environ.get('XDG_DATA_HOME', '~/.local/share/')) XDG_DATA_DIRS = map(Dir, environ.get_list('XDG_DATA_DIRS', ('/usr/share/', '/usr/local/share/'))) XDG_CONFIG_HOME = Dir( environ.get('XDG_CONFIG_HOME', '~/.config/')) XDG_CONFIG_DIRS = map(Dir, environ.get_list('XDG_CONFIG_DIRS', ('/etc/xdg/',))) XDG_CACHE_HOME = Dir( environ.get('XDG_CACHE_HOME', '~/.cache'))
def resolve_file(self, filename, path=None): '''Resolve a file or directory path relative to a page or Notebook This method is intended to lookup file links found in pages and turn resolve the absolute path of those files. File URIs and paths that start with '~/' or '~user/' are considered absolute paths. Also windows path names like 'C:\\user' are recognized as absolute paths. Paths that starts with a '/' are taken relative to the to the I{document root} - this can e.g. be a parent directory of the notebook. Defaults to the filesystem root when no document root is set. (So can be relative or absolute depending on the notebook settings.) Paths starting with any other character are considered attachments. If C{path} is given they are resolved relative to the I{attachment folder} of that page, otherwise they are resolved relative to the I{notebook folder} - if any. The file is resolved purely based on the path, it does not have to exist at all. @param filename: the (relative) file path or uri as string @param path: a L{Path} object for the page @returns: a L{File} object. ''' assert isinstance(filename, str) filename = filename.replace('\\', '/') if filename.startswith('~') or filename.startswith('file:/'): return File(filename) elif filename.startswith('/'): dir = self.document_root or Dir('/') return dir.file(filename) elif is_win32_path_re.match(filename): if not filename.startswith('/'): filename = '/' + filename # make absolute on Unix return File(filename) else: if path: dir = self.get_attachments_dir(path) return File( (dir.path, filename) ) # XXX LocalDir --> File -- will need get_abspath to resolve else: dir = Dir(self.layout.root.path) # XXX return File((dir, filename))
def testFS(self): '''Test async FS operations''' self.path = self.create_tmp_dir('testFS')+'/file.txt' file = File(self.path) op1 = file.write_async('foo bar 1\n') op2 = file.write_async('foo bar 2\n') op1.wait() op2.wait() self.assertEqual(file.read(), 'foo bar 2\n')
def get_template(category, template): '''Returns a Template object for a template name or file path @param category: the template category (e.g. "html"). Use to resolve the template if a template name is given @param template: the template name or file path ''' assert isinstance(template, basestring) if is_path_re.match(template): file = File(template) else: file = None for dir in data_dirs(('templates', category)): for basename in dir.list(): name = basename.rsplit('.')[0] # robust if no '.' in basename if basename == template or name == template: file = dir.file(basename) if file.exists(): # is a file break if file and file.exists(): break else: file = File(template) if not file.exists(): raise PathLookupError, _('Could not find template "%s"') % template # T: Error message in template lookup if not file.exists(): raise PathLookupError, _('No such file: %s') % file # T: Error message in template lookup logger.info('Loading template from: %s', file) #~ basename, ext = file.basename.rsplit('.', 1) #~ resources = file.dir.subdir(basename) return Template(file)
def _link_tree(links, notebook, path): # Convert a list of links (of any type) into a parsetree #~ print('LINKS: ', links) #~ print('NOTEBOOK and PATH:', notebook, path) builder = ParseTreeBuilder() builder.start(FORMATTEDTEXT) for i in range(len(links)): if i > 0: builder.text(' ') link = links[i] type = link_type(link) isimage = False if type == 'file': try: file = File(link) isimage = file.isimage() except: pass logger.debug('Pasting link: %s (type: %s, isimage: %s)', link, type, isimage) if isimage: src = notebook.relative_filepath(file, path) or file.uri builder.append(IMAGE, {'src': src}) elif link.startswith('@'): # FIXME - is this ever used ?? builder.append(TAG, {'name': links[i][1:]}, links[i]) else: name = None if type == 'page': target = Path(Path.makeValidPageName( link)) # Assume links are always absolute href = notebook.pages.create_link(path, target) link = href.to_wiki_link() if notebook.config['Notebook']['short_relative_links']: name = href.parts()[-1] elif type == 'file': file = File(link) # Assume links are always URIs link = notebook.relative_filepath(file, path) or file.uri builder.append(LINK, {'href': link}, name or link) builder.end(FORMATTEDTEXT) tree = builder.get_parsetree() tree.resolve_images(notebook, path) tree.decode_urls() return tree
def _append(self, info): path = File(info.uri).path text = '<b>%s</b>\n<span foreground="#5a5a5a" size="small">%s</span>' % \ (encode_markup_text(info.name), encode_markup_text(path)) # T: Path label in 'open notebook' dialog if info.icon and File(info.icon).exists(): w, h = strip_boolean_result( Gtk.icon_size_lookup(Gtk.IconSize.BUTTON)) pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( File(info.icon).path, w, h) else: pixbuf = None self.append((False, info.name, text, pixbuf, info))
def _link_tree(links, notebook, path): # Convert a list of links (of any type) into a parsetree #~ print 'LINKS: ', links #~ print 'NOTEBOOK and PATH:', notebook, path builder = TreeBuilder() builder.start('zim-tree') for i in range(len(links)): if i > 0: builder.data(' ') link = links[i] type = link_type(link) isimage = False if type == 'file': try: file = File(link) isimage = file.isimage() except: pass logger.debug('Pasting link: %s (type: %s, isimage: %s)', link, type, isimage) if isimage: src = notebook.relative_filepath(file, path) or file.uri builder.start('img', {'src': src}) builder.end('img') elif link.startswith('@'): # FIXME - is this ever used ?? builder.start('tag', {'name': links[i][1:]}) builder.data(links[i]) builder.end('tag') else: if type == 'page': href = Path(notebook.cleanup_pathname(link)) # Assume links are always absolute link = notebook.relative_link(path, href) or link elif type == 'file': file = File(link) # Assume links are always URIs link = notebook.relative_filepath(file, path) or file.uri builder.start('link', {'href': link}) builder.data(link) builder.end('link') builder.end('zim-tree') tree = ParseTree(builder.close()) tree.resolve_images(notebook, path) tree.decode_urls() return tree
def parse_old_format(self, text): '''Parses the config and cache and populates the list Method for backward compatibility with list format with no section headers and a whitespace separator between notebook name and uri. @param text: a string or a list of lines ''' # Old format is name, value pair, separated by whitespace # with all other whitespace escaped by a \ # Default was _default_ which could refer a notebook name. if isinstance(text, str): text = text.splitlines(True) fields_re = re.compile( r'(?:\\.|\S)+') # match escaped char or non-whitespace escaped_re = re.compile(r'\\(.)') # match single escaped char default = None defaulturi = None uris = [] for line in text: if not line or line.isspace() or line.startswith('#'): continue cols = fields_re.findall(line.strip()) if len(cols) == 2: name = escaped_re.sub(r'\1', cols[0]) path = escaped_re.sub(r'\1', cols[1]) if name == '_default_': default = path else: uri = File(path).uri uris.append(uri) if name == default: defaulturi = uri if default and not defaulturi: defaulturi = File(default).uri # Populate ourselves for uri in uris: info = NotebookInfo(uri) self.append(info) if defaulturi: self.set_default(defaulturi)
def runTest(self): for creator in self.creators: thumbdir = Dir(self.create_tmp_dir(creator.__name__)) dir = Dir('./data/pixmaps') for i, basename in enumerate(dir.list()): file = dir.file(basename) thumbfile = thumbdir.file('thumb--' + basename) self.assertFalse(thumbfile.exists()) pixbuf = creator(file, thumbfile, THUMB_SIZE_NORMAL) self.assertIsInstance(pixbuf, gtk.gdk.Pixbuf) self.assertTrue(thumbfile.exists()) pixbuf = gtk.gdk.pixbuf_new_from_file(thumbfile.encodedpath) self.assertEqual(pixbuf.get_option('tEXt::Thumb::URI'), file.uri) self.assertTrue(pixbuf.get_option('tEXt::Thumb::URI').startswith('file:///')) # Specific requirement of spec to use file:/// and not file://localhost/ self.assertEqual(int(pixbuf.get_option('tEXt::Thumb::MTime')), int(file.mtime())) self.assertTrue(i > 3) thumbfile = thumbdir.file('thumb-test.txt') self.assertRaises( ThumbnailCreatorFailure, creator, File('./README.txt'), thumbfile, THUMB_SIZE_NORMAL )
def generate_image(self, text): if isinstance(text, basestring): text = text.splitlines(True) plotscriptfile = self.plotscriptfile pngfile = File(plotscriptfile.path[:-2] + '.png') plot_script = "".join(text) template_vars = { 'gnu_r_plot_script': plot_script, 'png_fname': pngfile.path.replace('\\', '/'), # Even on windows, GNU R expects unix path seperator } # Write to tmp file usign the template for the header / footer plotscriptfile.writelines( self.template.process(template_vars) ) #print '>>>%s<<<' % plotscriptfile.read() # Call GNU R try: gnu_r = Application(gnu_r_cmd) #~ gnu_r.run(args=('-f', plotscriptfile.basename, ), cwd=plotscriptfile.dir) gnu_r.run(args=('-f', plotscriptfile.basename, '--vanilla'), cwd=plotscriptfile.dir) except: return None, None # Sorry, no log else: return pngfile, None
def generate_image(self, text): plotscriptfile = self.plotscriptfile pngfile = File(plotscriptfile.path[:-4] + '.png') template_vars = { # they go in the template 'gnuplot_script': text, 'png_fname': pngfile.path, } if self.attachment_folder and self.attachment_folder.exists(): template_vars['attachment_folder'] = self.attachment_folder.path else: template_vars['attachment_folder'] = '' # Write to tmp file using the template for the header / footer lines = [] self.template.process(lines, template_vars) plotscriptfile.writelines(lines) #~ print '>>>\n%s<<<' % plotscriptfile.read() # Call Gnuplot try: gnu_gp = Application(gnuplot_cmd) gnu_gp.run(args=(plotscriptfile.basename, ), cwd=plotscriptfile.dir) # you call it as % gnuplot output.plt except ApplicationError: return None, None # Sorry - no log else: return pngfile, None
def __init__(self, ui, tool=None): Dialog.__init__(self, ui, _('Edit Custom Tool')) # T: Dialog title self.set_help(':Help:Custom Tools') self.vbox.set_spacing(12) if tool: name = tool.name comment = tool.comment execcmd = tool.execcmd readonly = tool.isreadonly toolbar = tool.showintoolbar else: name = '' comment = '' execcmd = '' readonly = False toolbar = False self.add_form(( ('Name', 'string', _('Name')), # T: Input in "Edit Custom Tool" dialog ('Comment', 'string', _('Description')), # T: Input in "Edit Custom Tool" dialog ('X-Zim-ExecTool', 'string', _('Command')), # T: Input in "Edit Custom Tool" dialog ), { 'Name': name, 'Comment': comment, 'X-Zim-ExecTool': execcmd, }, trigger_response=False) # FIXME need ui builder to take care of this as well self.iconbutton = IconChooserButton(stock=gtk.STOCK_EXECUTE) if tool and tool.icon and tool.icon != gtk.STOCK_EXECUTE: try: self.iconbutton.set_file(File(tool.icon)) except Exception, error: logger.exception('Could not load: %s', tool.icon)
def testAttachFileDialogCallback(self): from zim.gui.widgets import PromptExistingFileDialog notebook = self.setUpNotebook(mock=tests.MOCK_ALWAYS_REAL, content={'Foo': 'test123'}) self.ui = setupGtkInterface(self, notebook=notebook) path = Path('Foo') file = File('data/zim.png') self.ui.do_attach_file(path, file) def do_overwrite(dialog): assert isinstance(dialog, PromptExistingFileDialog) dialog.do_response_overwrite() def do_new_file(dialog): assert isinstance(dialog, PromptExistingFileDialog) dialog.do_response_ok() with tests.DialogContext(do_overwrite): self.ui.do_attach_file(path, file) with tests.DialogContext(do_new_file): self.ui.do_attach_file(path, file)
def on_item_activated(self, iconview, path): from zim.fs import File store = iconview.get_model() iter = store.get_iter(path) file = self.folder.file(store[iter][BASENAME_COL]) file = File(file) self.opener.open_file(file)
def on_drag_data_received(self, iconview, dragcontext, x, y, selectiondata, info, time): assert selectiondata.target in URI_TARGET_NAMES names = unpack_urilist(selectiondata.data) files = [File(uri) for uri in names if uri.startswith('file://')] action = dragcontext.action logger.debug('Drag received %s, %s', action, files) if action == gtk.gdk.ACTION_MOVE: self._move_files(files) elif action == gtk.gdk.ACTION_ASK: menu = gtk.Menu() item = gtk.MenuItem( _('_Move Here')) # T: popup menu action on drag-drop of a file item.connect('activate', lambda o: self._move_files(files)) menu.append(item) item = gtk.MenuItem( _('_Copy Here')) # T: popup menu action on drag-drop of a file item.connect('activate', lambda o: self._copy_files(files)) menu.append(item) menu.append(gtk.SeparatorMenuItem()) item = gtk.MenuItem( _('Cancel')) # T: popup menu action on drag-drop of a file # cancel action needs no action menu.append(item) menu.show_all() menu.popup(None, None, None, 1, time) else: # Assume gtk.gdk.ACTION_COPY or gtk.gdk.ACTION_DEFAULT # on windows we get "0" which is not mapped to any action self._copy_files(files)
def testUIInterface(self): # test ui.new_page_from_text() name = 'foo:new page quicknote' text = '''\ ======= New Page ======= Test 1 2 3 attachment {{./zim16.png}} ''' wanted = '''\ <?xml version='1.0' encoding='utf-8'?> <zim-tree><h level="1">New Page</h> <p>Test 1 2 3 </p> <p>attachment <img src="./zim16.png" /> </p></zim-tree>''' dirname = self.create_tmp_dir(name='import_source') File('./icons/zim16.png').copyto(Dir(dirname)) ui = setupGtkInterface(self) path = ui.new_page_from_text(text, name, attachments=dirname) page = ui.notebook.get_page(path) attachments = ui.notebook.get_attachments_dir(path) self.assertEqual(page.get_parsetree().tostring(), wanted) self.assertIn('zim16.png', Dir(attachments.path).list())
def dump_img(self, tag, attrib, strings=None): imagepath = self.linker.img(attrib['src']) if not self.is_supported_image(imagepath): attrib.setdefault('href', attrib['src']) return self.dump_link(tag, attrib, strings) # We try to get images about the same visual size, # therefore need to specify dot density 96 dpi seems to be # common for computer monitors dpi = 96 if 'width' in attrib and not 'height' in attrib: options = 'width=%fin, keepaspectratio=true' \ % (float(attrib['width']) / dpi) elif 'height' in attrib and not 'width' in attrib: options = 'height=%fin, keepaspectratio=true' \ % (float(attrib['height']) / dpi) elif 'height' in attrib and 'width' in attrib: options = 'height=%fin, width=%fin' \ % (float(attrib['height']) / dpi, float(attrib['width']) / dpi) else: options = '' if imagepath.startswith('file://'): imagepath = File(imagepath).path # avoid URIs here image = '\\includegraphics[%s]{%s}' % (options, imagepath) if 'href' in attrib: href = self.linker.link(attrib['href']) return ['\\href{%s}{%s}' % (href, image)] else: return [image]
def _stitch_fileextension(self, file, basename): '''Stitches the file extension from 'basename' to the path of 'file' and returns a File object. ''' i = basename.rfind('.') j = file.path.rfind('.') return File(file.path[:j] + basename[i:])
def init_uistate(self): # Switch between folder selection or file selection based # on whether we selected full notebook or single page in the # first page self.uistate.setdefault('output_folder', None, Dir) self.uistate.setdefault('index_page', '') self.uistate.setdefault('output_file', None, File) show_file = self.uistate.get('selection') == 'page' if show_file: self.form.widgets['folder'].set_sensitive(False) self.form.widgets['folder'].hide() self.form.widgets['file'].set_sensitive(True) self.form.widgets['file'].show() else: self.form.widgets['folder'].set_sensitive(True) self.form.widgets['folder'].show() self.form.widgets['file'].set_sensitive(False) self.form.widgets['file'].hide() if show_file: basename = self.uistate['selected_page'].basename ext = zim.formats.get_format( self.uistate['format']).info['extension'] if self.uistate['output_file'] \ and isinstance(self.uistate['output_file'], File): dir = self.uistate['output_file'].dir file = dir.file(encode_filename(basename + '.' + ext)) else: file = File('~/' + encode_filename(basename + '.' + ext)) self.uistate['output_file'] = file self.form['file'] = self.uistate['output_file'] self.form['folder'] = self.uistate['output_folder']
def runTest(self): '''Test FileEntry widget''' from zim.fs import adapt_from_newfs, Dir dir = Dir(self.notebook.folder) # XXX path = Path('Foo:Bar') entry = self.entry entry.set_use_relative_paths(self.notebook, path) home = Dir('~') for file, text in ( (home.file('zim-test.txt'), '~/zim-test.txt'), (dir.file('Foo/Bar/test.txt'), './test.txt'), (File('/test.txt'), File('/test.txt').path), # win32 save ): entry.set_file(file) self.assertEqual(entry.get_text(), os_native_path(text)) self.assertEqual(entry.get_file(), file) self.notebook.config['Notebook'][ 'document_root'] = './notebook_document_root' doc_root = self.notebook.document_root self.assertEqual(doc_root, dir.subdir('notebook_document_root')) for file, text in ( (home.file('zim-test.txt'), os_native_path('~/zim-test.txt')), (dir.file('Foo/Bar/test.txt'), os_native_path('./test.txt')), (File('/test.txt'), File('/test.txt').uri), # win32 save (doc_root.file('test.txt'), '/test.txt'), ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file) entry.set_use_relative_paths(self.notebook, None) for file, text in ( (home.file('zim-test.txt'), os_native_path('~/zim-test.txt')), (dir.file('Foo/Bar/test.txt'), os_native_path('./Foo/Bar/test.txt')), (File('/test.txt'), File('/test.txt').uri), # win32 save (doc_root.file('test.txt'), '/test.txt'), ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file) entry.set_use_relative_paths(notebook=None) for file, text in ( (home.file('zim-test.txt'), '~/zim-test.txt'), #~ (dir.file('Foo/Bar/test.txt'), './test.txt'), (File('/test.txt'), File('/test.txt').path), # win32 save ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file)
def runTest(self): '''Test FileEntry widget''' path = Path('Foo:Bar') entry = self.entry entry.set_use_relative_paths(self.notebook, path) home = Dir('~') dir = self.notebook.dir for file, text in ( (home.file('zim-test.txt'), '~/zim-test.txt'), (dir.file('Foo/Bar/test.txt'), './test.txt'), (File('/test.txt'), File('/test.txt').path), # win32 save ): entry.set_file(file) self.assertEqual(entry.get_text(), os_native_path(text)) self.assertEqual(entry.get_file(), file) self.notebook.config['Notebook'][ 'document_root'] = './notebook_document_root' self.notebook.do_properties_changed() # parse config doc_root = self.notebook.document_root self.assertEqual(doc_root, dir.subdir('notebook_document_root')) for file, text in ( (home.file('zim-test.txt'), os_native_path('~/zim-test.txt')), (dir.file('Foo/Bar/test.txt'), os_native_path('./test.txt')), (File('/test.txt'), File('/test.txt').uri), # win32 save (doc_root.file('test.txt'), '/test.txt'), ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file) entry.set_use_relative_paths(self.notebook, None) for file, text in ( (home.file('zim-test.txt'), os_native_path('~/zim-test.txt')), (dir.file('Foo/Bar/test.txt'), os_native_path('./Foo/Bar/test.txt')), (File('/test.txt'), File('/test.txt').uri), # win32 save (doc_root.file('test.txt'), '/test.txt'), ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file) entry.set_use_relative_paths(notebook=None) for file, text in ( (home.file('zim-test.txt'), '~/zim-test.txt'), #~ (dir.file('Foo/Bar/test.txt'), './test.txt'), (File('/test.txt'), File('/test.txt').path), # win32 save ): entry.set_file(file) self.assertEqual(entry.get_text(), text) self.assertEqual(entry.get_file(), file)
def testResolveFile(self): '''Test notebook.resolve_file()''' path = Path('Foo:Bar') dir = self.notebook.dir self.notebook.config['Notebook']['document_root'] = './notebook_document_root' self.notebook.do_properties_changed() # parse config doc_root = self.notebook.document_root self.assertEqual(doc_root, dir.subdir('notebook_document_root')) for link, wanted, cleaned in ( ('~/test.txt', File('~/test.txt'), '~/test.txt'), (r'~\test.txt', File('~/test.txt'), '~/test.txt'), ('file:///test.txt', File('file:///test.txt'), None), ('file:/test.txt', File('file:///test.txt'), None), ('file://localhost/test.txt', File('file:///test.txt'), None), ('/test.txt', doc_root.file('test.txt'), '/test.txt'), ('../../notebook_document_root/test.txt', doc_root.file('test.txt'), '/test.txt'), ('./test.txt', dir.file('Foo/Bar/test.txt'), './test.txt'), (r'.\test.txt', dir.file('Foo/Bar/test.txt'), './test.txt'), ('../test.txt', dir.file('Foo/test.txt'), '../test.txt'), (r'..\test.txt', dir.file('Foo/test.txt'), '../test.txt'), ('../Bar/Baz/test.txt', dir.file('Foo/Bar/Baz/test.txt'), './Baz/test.txt'), (r'C:\foo\bar', File('file:///C:/foo/bar'), None), (r'Z:\foo\bar', File('file:///Z:/foo/bar'), None), ): #~ print link, '>>', self.notebook.resolve_file(link, path) self.assertEqual( self.notebook.resolve_file(link, path), wanted) self.assertEqual( self.notebook.relative_filepath(wanted, path), cleaned) # check relative path without Path self.assertEqual( self.notebook.relative_filepath(doc_root.file('foo.txt')), '/foo.txt') self.assertEqual( self.notebook.relative_filepath(dir.file('foo.txt')), './foo.txt')
def _link_tree(links, notebook, path): # Convert a list of links (of any type) into a parsetree #~ print 'LINKS: ', links #~ print 'NOTEBOOK and PATH:', notebook, path builder = ParseTreeBuilder() builder.start(FORMATTEDTEXT) for i in range(len(links)): if i > 0: builder.text(' ') link = links[i] type = link_type(link) isimage = False if type == 'file': try: file = File(link) isimage = file.isimage() except: pass logger.debug('Pasting link: %s (type: %s, isimage: %s)', link, type, isimage) if isimage: src = notebook.relative_filepath(file, path) or file.uri builder.append(IMAGE, {'src': src}) elif link.startswith('@'): # FIXME - is this ever used ?? builder.append(TAG, {'name': links[i][1:]}, links[i]) else: if type == 'page': href = Path(notebook.cleanup_pathname( link)) # Assume links are always absolute link = notebook.relative_link(path, href) or link elif type == 'file': file = File(link) # Assume links are always URIs link = notebook.relative_filepath(file, path) or file.uri builder.append(LINK, {'href': link}, link) builder.end(FORMATTEDTEXT) tree = builder.get_parsetree() tree.resolve_images(notebook, path) tree.decode_urls() return tree
class DiagramGenerator(ImageGeneratorClass): uses_log_file = False object_type = 'diagram' scriptname = 'diagram.dot' imagename = 'diagram.png' def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4 def generate_image(self, text): if isinstance(text, basestring): text = text.splitlines(True) # Write to tmp file self.dotfile.writelines(text) # Call GraphViz try: dot = Application(dotcmd) dot.run((self.pngfile, self.dotfile)) except ApplicationError: return None, None # Sorry, no log else: if self.pngfile.exists(): return self.pngfile, None else: # When supplying a dot file with a syntax error, the dot command # doesn't return an error code (so we don't raise # ApplicationError), but we still don't have a png file to # return, so return None. return None, None def cleanup(self): self.dotfile.remove() self.pngfile.remove()
def generate_image(self, text): (version, text) = self.extract_version(text) text = ''.join(text) #~ print '>>>%s<<<' % text # Write to tmp file using the template for the header / footer scorefile = self.scorefile lines = [] self.template.process(lines, { 'score': text, 'version': version or '', 'include_header': self.include_header or '', 'include_footer': self.include_footer or '', } ) scorefile.writelines(lines) #~ print '>>>%s<<<' % scorefile.read() # Call convert-ly to convert document of current version of # Lilypond. clogfile = File(scorefile.path[:-3] + '-convertly.log') # len('.ly) == 3 try: convertly = Application(convertly_cmd) convertly.run((scorefile.basename,), cwd=scorefile.dir) except ApplicationError: clogfile.write('convert-ly failed.\n') return None, clogfile # Call lilypond to generate image. logfile = File(scorefile.path[:-3] + '.log') # len('.ly') == 3 try: lilypond = Application(lilypond_cmd) lilypond.run(('-dlog-file=' + logfile.basename[:-4], scorefile.basename,), cwd=scorefile.dir) except ApplicationError: # log should have details of failure return None, logfile pngfile = File(scorefile.path[:-3] + '.png') # len('.ly') == 3 return pngfile, logfile
def testError(self): def creator_with_failure(*a): raise ThumbnailCreatorFailure def creator_with_error(*a): raise ValueError file = File('./data/zim.png') self.assertTrue(file.exists()) self.assertTrue(file.isimage()) for creator in creator_with_failure, creator_with_error: #~ print ">>", creator.__name__ queue = ThumbnailQueue(creator) queue.queue_thumbnail_request(file, 64) with tests.LoggingFilter('zim.plugins.attachmentbrowser', 'Exception'): queue.start() while not queue.queue_empty(): r = queue.get_ready_thumbnail() self.assertIsNone(r[0], None)
def __init__(self, path, file=None): '''Constructor @param path: either basename as string or tuple with relative path, is resolved relative to the default config dir for zim. @param file: optional argument for some special case to override the base file in the home folder. ''' if isinstance(path, basestring): path = (path,) self._path = tuple(path) if file: self.file = file else: self.file = File((XDG_CONFIG_HOME, 'zim') + self._path)
def testAttachFileDialog(self): '''Test AttachFileDialog''' tmp_dir = self.create_tmp_dir('testAttachFileDialog') file = File((tmp_dir, 'file_to_be_attached')) file.write('Test 1 2 3\n') newfile = File((tmp_dir, 'attachments', 'Test', 'foo', 'file_to_be_attached')) self.assertTrue(file.exists()) self.assertFalse(newfile.exists()) dialog = zim.gui.AttachFileDialog(self.ui, path=Path('Test:foo')) dialog.set_file(file)
def __init__(self): self.dotfile = TmpFile('diagram-editor.dot') self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4
def runTest(self): plugins = PluginManager.list_installed_plugins() self.assertTrue(len(plugins) > 10) self.assertTrue('spell' in plugins) self.assertTrue('linkmap' in plugins) pluginindex = File('data/manual/Plugins.txt').read() seen = { 'name': set(), 'description': set(), 'help': set(), } for name in plugins: #~ print '>>', name klass = PluginManager.get_plugin_class(name) # test plugin info for key in ('name', 'description', 'author'): self.assertTrue( klass.plugin_info.get(key), 'Plugin %s misses info field \'%s\'' % (name, key) ) for key in ('name', 'description', 'help'): self.assertIn(key, klass.plugin_info, 'Plugin %s missing "%s"' % (name, key)) value = klass.plugin_info[key] self.assertFalse( value in seen[key], 'Value for \'%s\' in %s seen before - copy-paste error ?' % (key, name) ) seen[key].add(value) # test manual page present and at least documents preferences page = klass.plugin_info['help'] self.assertTrue(page.startswith('Plugins:'), 'Help page for %s not valid' % name) rellink = "+%s" % page[8:] self.assertIn(rellink, pluginindex, 'Missing links "%s" in manual/Plugins.txt' % rellink) file = File('data/manual/' + page.replace(':', '/').replace(' ', '_') + '.txt') self.assertTrue(file.exists(), 'Missing file: %s' % file) manual = file.read() for pref in klass.plugin_preferences: label = pref[2] if '\n' in label: label, x = label.split('\n', 1) label = label.rstrip(',') self.assertIn(label, manual, 'Preference "%s" for %s plugin not documented in manual page' % (label, name)) # test dependencies data dep = klass.check_dependencies() self.assertTrue(isinstance(dep,tuple)) check, dep = dep self.assertTrue(isinstance(check,bool)) self.assertTrue(isinstance(dep,list)) for i in range(len(dep)): self.assertTrue(isinstance(dep[i],tuple)) self.assertTrue(isinstance(dep[i][0],str)) self.assertTrue(isinstance(dep[i][1],bool)) self.assertTrue(isinstance(dep[i][2],bool))
def set_basedirs(): '''This method sets the global configuration paths for according to the freedesktop basedir specification. Called automatically when module is first loaded, should be called explicitly only when environment has changed. ''' global ZIM_DATA_DIR global XDG_DATA_HOME global XDG_DATA_DIRS global XDG_CONFIG_HOME global XDG_CONFIG_DIRS global XDG_CACHE_HOME # Cast string to folder import zim zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data') if zim_data_dir.exists(): ZIM_DATA_DIR = zim_data_dir if os.name == 'nt': APPDATA = environ['APPDATA'] XDG_DATA_HOME = Dir( environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data')) XDG_DATA_DIRS = map(Dir, environ.get_list('XDG_DATA_DIRS', '~/.local/share/')) # Backwards compatibility XDG_CONFIG_HOME = Dir( environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config')) XDG_CONFIG_DIRS = map(Dir, environ.get_list('XDG_CONFIG_DIRS', '~/.config/')) # Backwards compatibility try: import _winreg as wreg wreg_key = wreg.OpenKey( wreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders') cache_dir = str(wreg.QueryValueEx(wreg_key, "Cache")[0].replace(u'%USERPROFILE%', environ['USERPROFILE'])) wreg.CloseKey(wreg_key) except: cache_dir = APPDATA + r'\zim\cache' # Not using TMP here because it is cleaned too often XDG_CACHE_HOME = Dir( environ.get('XDG_CACHE_HOME', cache_dir + r'\zim')) else: XDG_DATA_HOME = Dir( environ.get('XDG_DATA_HOME', '~/.local/share/')) XDG_DATA_DIRS = map(Dir, environ.get_list('XDG_DATA_DIRS', ('/usr/share/', '/usr/local/share/'))) XDG_CONFIG_HOME = Dir( environ.get('XDG_CONFIG_HOME', '~/.config/')) XDG_CONFIG_DIRS = map(Dir, environ.get_list('XDG_CONFIG_DIRS', ('/etc/xdg/',))) XDG_CACHE_HOME = Dir( environ.get('XDG_CACHE_HOME', '~/.cache'))
def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.diagfile = TmpFile(self.scriptname) self.diagfile.touch() self.pngfile = File(self.diagfile.path[:-5] + '.png') # len('.diag') == 5
def __init__(self, plugin): ImageGeneratorClass.__init__(self, plugin) self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + ".png") # len('.dot') == 4
class ConfigFile(object): '''Container object for a config file Maps to a "base" file in the home folder, used to write new values, and one or more default files, e.g. in C{/usr/share/zim}, which are the fallback to get default values @ivar file: the underlying file object for the base config file in the home folder @note: this class implement similar API to the L{File} class but is explicitly not a sub-class of L{File} because config files should typically not be moved, renamed, etc. It just implements the reading and writing methods. ''' def __init__(self, path, file=None): '''Constructor @param path: either basename as string or tuple with relative path, is resolved relative to the default config dir for zim. @param file: optional argument for some special case to override the base file in the home folder. ''' if isinstance(path, basestring): path = (path,) self._path = tuple(path) if file: self.file = file else: self.file = File((XDG_CONFIG_HOME, 'zim') + self._path) def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.file.path) def __eq__(self, other): return isinstance(other, ConfigFile) \ and other._path == self._path \ and other.file == self.file @property def basename(self): return self.file.basename def default_files(self): '''Generator that yields default config files (read-only) to use instead of the standard file when it is still empty. Typically only the first one is used. ''' for dir in config_dirs(): default = dir.file(self._path) if default.exists(): yield default def touch(self): '''Ensure the custom file in the home folder exists. Either by copying a default config file, or touching an empty file. Intended to be called before trying to edit the file with an external editor. ''' if not self.file.exists(): for file in self.default_files(): file.copyto(self.file) break else: self.file.touch() # create empty file def read(self, fail=False): '''Read the base file or first default file @param fail: if C{True} a L{FileNotFoundError} error is raised when neither the base file or a default file are found. If C{False} it will return C{''} for a non-existing file. @returns: file content as a string ''' try: return self.file.read() except FileNotFoundError: for file in self.default_files(): return file.read() else: if fail: raise else: return '' def readlines(self, fail=False): '''Read the base file or first default file @param fail: if C{True} a L{FileNotFoundError} error is raised when neither the base file or a default file are found. If C{False} it will return C{[]} for a non-existing file. @returns: file content as a list of lines ''' try: return self.file.readlines() except FileNotFoundError: for file in self.default_files(): return file.readlines() else: if fail: raise else: return [] # Not implemented: read_async and readlines_async def write(self, text): '''Write base file, see L{File.write()}''' self.file.write(text) def writelines(self, lines): '''Write base file, see L{File.writelines()}''' self.file.writelines(lines) def write_async(self, text, callback=None, data=None): '''Write base file async, see L{File.write_async()}''' return self.file.write_async(text, callback=callback, data=data) def writelines_async(self, lines, callback=None, data=None): '''Write base file async, see L{File.writelines_async()}''' return self.file.writelines_async(lines, callback=callback, data=data) def remove(self): '''Remove user file, leaves default files in place''' if self.file.exists(): return self.file.remove()
def main(argv): """Run the main program Depending on the commandline given and whether or not there is an instance of zim running already, this method may return immediatly, or go into the mainloop untill the program is exitted. @param argv: commandline arguments, e.g. from C{sys.argv} @raises UsageError: when number of arguments is not correct @raises GetOptError: when invalid options are found """ global ZIM_EXECUTABLE # FIXME - this returns python.exe on my windows test ZIM_EXECUTABLE = argv[0] zim_exec_file = File(ZIM_EXECUTABLE) if zim_exec_file.exists(): # We were given an absolute path, e.g. "python ./zim.py" ZIM_EXECUTABLE = zim_exec_file.path # Check for special commandline args for ipc, does not return # if handled import zim.ipc zim.ipc.handle_argv() # Let getopt parse the option list short = "".join(shortopts.keys()) for s, l in shortopts.items(): if l.endswith("="): short = short.replace(s, s + ":") long = list(longopts) + list(commands) for opts in commandopts.values(): long.extend(opts) opts, args = gnu_getopt(argv[1:], short, long) # First figure out which command to execute cmd = "gui" # default if opts: o = opts[0][0].lstrip("-") if o in shortopts: o = shortopts[o].rstrip("=") if o in commands: opts.pop(0) cmd = o # If it is a simple command execute it and return if cmd == "version": print "zim %s\n" % __version__ print __copyright__, "\n" print __license__ return elif cmd == "help": print usagehelp.replace("zim", argv[0]) print optionhelp return # Otherwise check the number of arguments if cmd in maxargs and len(args) > maxargs[cmd]: raise UsageError # --manual is an alias for --gui /usr/share/zim/manual if cmd == "manual": cmd = "gui" args.insert(0, data_dir("manual").path) # Now figure out which options are allowed for this command allowedopts = list(longopts) allowedopts.extend(commandopts[cmd]) # Convert options into a proper dict optsdict = {} for o, a in opts: o = str(o.lstrip("-")) # str() -> no unicode for keys if o in shortopts: o = shortopts[o].rstrip("=") if o + "=" in allowedopts: o = o.replace("-", "_") optsdict[o] = a elif o in allowedopts: o = o.replace("-", "_") optsdict[o] = True else: raise GetoptError, ("--%s is not allowed in combination with --%s" % (o, cmd), o) # --port is the only option that is not of type string if "port" in optsdict and not optsdict["port"] is None: try: optsdict["port"] = int(optsdict["port"]) except ValueError: raise GetoptError, ("--port takes an integer argument", "port") # set logging output level for logging root (format has been set in zim.py) if not ZIM_EXECUTABLE[-4:].lower() == ".exe": # for most platforms level = logging.WARN else: # if running from Windows compiled .exe level = logging.ERROR if optsdict.pop("verbose", False): level = logging.INFO if optsdict.pop("debug", False): level = logging.DEBUG # no "elif" ! logging.getLogger().setLevel(level) logger.info("This is zim %s", __version__) if level == logging.DEBUG: logger.debug("Python version is %s", str(sys.version_info)) logger.debug("Platform is %s", os.name) logger.debug(get_zim_revision()) log_basedirs() # Now we determine the class to handle this command # and start the application ... logger.debug("Running command: %s", cmd) if cmd in ("export", "index", "search"): if not len(args) >= 1: default = _get_default_or_only_notebook() if not default: raise UsageError handler = NotebookInterface(notebook=default) else: handler = NotebookInterface(notebook=args[0]) handler.load_plugins() # should this go somewhere else ? if cmd == "search": if not len(args) == 2: raise UsageError optsdict["query"] = args[1] elif len(args) == 2: optsdict["page"] = args[1] method = getattr(handler, "cmd_" + cmd) method(**optsdict) elif cmd == "gui": notebook = None page = None if args: from zim.notebook import resolve_notebook notebook, page = resolve_notebook(args[0]) if not notebook: notebook = File(args[0]).uri # make sure daemon approves of this uri and proper # error dialog is shown as a result by GtkInterface if len(args) == 2: page = args[1] if "list" in optsdict: del optsdict["list"] # do not use default elif not notebook: import zim.notebook default = _get_default_or_only_notebook() if default: notebook = default logger.info("Opening default notebook") # DGT: HACK for debuger if "standalone" in optsdict or DEBUG: import zim.gui try: del optsdict["standalone"] except: pass if not notebook: import zim.gui.notebookdialog notebook = zim.gui.notebookdialog.prompt_notebook() if not notebook: return # User canceled notebook dialog handler = zim.gui.GtkInterface(notebook, page, **optsdict) handler.main() else: from zim.ipc import start_server_if_not_running, ServerProxy if not notebook: import zim.gui.notebookdialog notebook = zim.gui.notebookdialog.prompt_notebook() if not notebook: return # User canceled notebook dialog start_server_if_not_running() server = ServerProxy() gui = server.get_notebook(notebook) gui.present(page, **optsdict) logger.debug( """ NOTE FOR BUG REPORTS: At this point zim has send the command to open a notebook to a background process and the current process will now quit. If this is the end of your debug output it is probably not useful for bug reports. Please close all zim windows, quit the zim trayicon (if any), and try again. """ ) elif cmd == "server": standalone = optsdict.pop("standalone", False) # No daemon support for server, so no option doesn't # do anything for now gui = optsdict.pop("gui", False) if gui: import zim.gui.server zim.gui.server.main(*args, **optsdict) else: import zim.www zim.www.main(*args, **optsdict) elif cmd == "plugin": import zim.plugins try: pluginname = args.pop(0) except IndexError: raise UsageError module = zim.plugins.get_plugin_module(pluginname) module.main(*args)
def __init__(self): self.dotfile = TmpFile(self.scriptname) self.dotfile.touch() self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4