def testRemoveTemplate(self): dialog = TemplateEditorDialog(None) select_by_name(dialog.view, 'foo_test') file = LocalFile(XDG_DATA_HOME.file('zim/templates/html/foo_test.html').path) self.assertTrue(file.exists()) dialog.on_delete() self.assertFalse(file.exists())
def _db_check(self): try: if self.get_property('db_version') == DB_VERSION: pass else: logger.debug('Index db_version out of date') self._db_init() except sqlite3.OperationalError: # db is there but table does not exist logger.debug('Operational error, init tabels') self._db_init() except sqlite3.DatabaseError: assert not self.dbpath == ':memory:' logger.warning('Overwriting possibly corrupt database: %s', self.dbpath) self.db.close() file = LocalFile(self.dbpath) try: file.remove() except: logger.exception('Could not delete: %s', file) # TODO: how to recover form this ? - seems fatal finally: self._db = self._new_connection() self._db_init()
def testCopyTemplate(self): dialog = TemplateEditorDialog(None) select_by_name(dialog.view, 'foo_test') def do_copy(dialog): dialog.set_input(name='new_foo_test') dialog.assert_response_ok() with tests.DialogContext(do_copy): dialog.on_copy() file = LocalFile(XDG_DATA_HOME.file('zim/templates/html/new_foo_test.html').path) self.assertTrue(file.exists())
def _db_recover(self): assert not self.dbpath == ':memory:' logger.warning('Overwriting possibly corrupt database: %s', self.dbpath) file = LocalFile(self.dbpath) try: file.remove(cleanup=False) except: logger.error( 'Could not access database file, running in-memory database') self.dbpath = ':memory:' finally: self._db = sqlite3.Connection(self.dbpath) self._db.row_factory = sqlite3.Row self._db_init()
def __init__(self, file, page=None): '''Constructor @param file: a L{File} object @param page: an optional L{Path} object for the top level page ''' if isinstance(file, OldFile): file = LocalFile(file.path) self.file = file basename = file.basename if '.' in basename: basename, x = basename.rsplit('.', 1) self.dir = file.parent().folder(basename + '_files') self.relative_root = file.parent() self.namespace = page
def on_drag_data_received(self, iconview, dragcontext, x, y, selectiondata, info, time): assert selectiondata.get_target().name() in URI_TARGET_NAMES names = unpack_urilist(selectiondata.get_data()) files = [LocalFile(uri) for uri in names if uri.startswith('file://')] action = dragcontext.get_selected_action() logger.debug('Drag received %s, %s', action, files) if action == Gdk.DragAction.MOVE: self._move_files(files) elif action == Gdk.DragAction.ASK: menu = Gtk.Menu() item = Gtk.MenuItem.new_with_mnemonic( _('_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.new_with_mnemonic( _('_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.new_with_mnemonic( _('Cancel')) # T: popup menu action on drag-drop of a file # cancel action needs no action menu.append(item) menu.show_all() gtk_popup_at_pointer(menu) else: # Assume Gdk.DragAction.COPY or Gdk.DragAction.DEFAULT # on windows we get "0" which is not mapped to any action self._copy_files(files)
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 = [LocalFile(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 copy_imagegenerator_src_files(src_file, folder): # Helper method to allow copy-paste dealing with image files generated # by a BackwardImageGeneratorObjectType instance # We want to be agnostic of the exact image object type, so we just look # at any files that share the same basename as the image being copied basename = src_file.basename i = basename.rfind('.') basename = basename[:i] src_files = [] for f in src_file.parent(): if f.basename.startswith(basename) \ and not '.' in f.basename[len(basename)+1:]: src_files.append(f) def check_new_file(new_file): for f in src_files: new_f = _stitch_fileextension(new_file, f.basename) if new_f.exists(): return False else: return True new_file = folder.new_file(src_file.basename, check_new_file) for f in src_files: new_f = _stitch_fileextension(new_file, f.basename) f.copyto(LocalFile(new_f.path)) return new_file
def __init__(self, file, page, ext): '''Constructor @param file: a L{File} object @param page: a L{Path} object for the top level page @param ext: the file extension to be used for sub-pages, e.g. 'html' ''' if isinstance(file, OldFile): file = LocalFile(file.path) self.file = file self.namespace = page self.ext = ext basename = file.basename if '.' in basename: basename, x = basename.rsplit('.', 1) self.dir = file.parent().folder(basename + '_files') self.relative_root = file.parent()
def adapt_from_oldfs(file): from zim.newfs import LocalFile, LocalFolder if isinstance(file, File): return LocalFile(file.path) elif isinstance(file, Dir): return LocalFolder(file.path) else: return file
def _replace_links_to_interwiki_and_copy_images(src_interwiki, notebook, new_path, node): if node.tag == LINK: abs_href = node.attrib.pop('_href', None) if abs_href: my_type = link_type(abs_href) if my_type == 'page': oldhref = HRef.new_from_wiki_link( node.get('href')) # *not* abs_href new_href = src_interwiki + '?' + abs_href new_href += '#' + oldhref.anchor if oldhref.anchor else '' elif my_type == 'file': # NOTE: no proper syntax for this type of link - just abs file link # should be improved - e.g. path:./file style links like in docuwiki new_href = abs_href else: logger.warn('Could not update link of type "%s": %s', my_type, abs_href) raise VisitorSkip if node.gettext() == node.get('href'): # *not* abs_href node[:] = [new_href] node.set('href', new_href) return node else: raise VisitorSkip elif node.tag == IMAGE: # Just copy all images - image links to other notebook don't make sense abs_src = node.attrib.pop('_src', None) if abs_src: src_file = LocalFile(abs_src) return _copy_image(notebook, new_path, src_file, node) else: raise VisitorSkip elif node.tag == OBJECT: abs_src = node.attrib.pop('_src', None) if abs_src and node.get('type').startswith('image+'): src_file = LocalFile(abs_src) return _copy_image_object(notebook, new_path, src_file, node) else: raise VisitorSkip else: raise AssertionError('unknown tag')
def build_mhtml_file_exporter(file, template, **opts): '''Returns an L{Exporter} that is suitable for exporting a set of pages to a single mhtml file ''' from zim.export.exporters.mhtml import MHTMLExporter if isinstance(file, File): file = LocalFile(file.path) template = get_template('html', template) return MHTMLExporter(file, template, **opts)
def _db_connect(self): # NOTE: for a locked database, different errors happen on linux and # on windows, so test both platforms when modifying here if self.dbpath != ':memory:': logger.debug('Connecting to database file: %s', self.dbpath) file = LocalFile(self.dbpath) file.parent().touch() else: logger.debug('Connecting to in-memory database') try: self._db = sqlite3.Connection(self.dbpath) except: self._db_recover() self._db.row_factory = sqlite3.Row try: self._db.execute('PRAGMA synchronous=OFF;') # Don't wait for disk writes, we can recover from crashes # anyway. Allows us to use commit more frequently. if self.get_property('db_version') != DB_VERSION: logger.info('Index db_version out of date') self._db_init() elif self.get_property('db_sortkey_format') != natural_sort_key( DB_SORTKEY_CONTENT): logger.info('Index db_sortkey_format out of date') self._db_init() self.set_property('db_version', DB_VERSION) # Ensure we can write except sqlite3.OperationalError: # db is there but table does not exist logger.debug('Operational error, init tabels') try: self._db_init() except: self._db_recover() except sqlite3.DatabaseError: self._db_recover()
def build_single_file_exporter(file, format, template, namespace=None, **opts): '''Returns an L{Exporter} that is suitable for exporting a set of pages to a single file ''' from zim.export.layouts import SingleFileLayout from zim.export.exporters.files import SingleFileExporter if isinstance(file, File): file = LocalFile(file.path) template = get_template(format, template) layout = SingleFileLayout(file) return SingleFileExporter(layout, template, format, **opts)
def on_delete(self, *a): # Only delete custom, may result in reset to default custom, default = self.view.get_selected() if custom is None or not custom.exists(): return # Should not have been sensitive try: TrashHelper().trash(LocalFile(custom.path)) except TrashNotSupportedError: # TODO warnings custom.remove() self.view.refresh()
def build_page_exporter(file, format, template, page, **opts): '''Returns an L{Exporter} that is suitable for exporting a page with subpages to a file and a folder (e.g. "page.html" with "page_files/") ''' from zim.export.layouts import FileLayout from zim.export.exporters.files import MultiFileExporter if isinstance(file, File): file = LocalFile(file.path) template = get_template(format, template) ext = get_format(format).info['extension'] layout = FileLayout(file, page, ext) return MultiFileExporter(layout, template, format, **opts)
def _replace_links_to_page_and_copy_images(notebook, old_folder, new_path, node): if node.tag == LINK: abs_href = node.attrib.pop('_href', None) if abs_href: my_type = link_type(abs_href) if my_type == 'page': target = Path(abs_href) oldhref = HRef.new_from_wiki_link( node.get('href')) # *not* abs_href return notebook._update_link_tag(node, new_path, target, oldhref) elif my_type == 'file': new_href = notebook.relative_filepath(LocalFile(abs_href), new_path) if new_href is None: return node # could be VisitorSkip, but want to get rid of _href else: if node.gettext() == node.get('href'): # *not* abs_href node[:] = [new_href] node.set('href', new_href) return node else: logger.warn('Could not update link of type "%s": %s', my_type, abs_href) raise VisitorSkip else: raise VisitorSkip elif node.tag == IMAGE: # Only copy direct attachments - else the image already was a link # to a file outside of the attachment folder abs_src = node.attrib.pop('_src', None) if abs_src: src_file = LocalFile(abs_src) if src_file.ischild(old_folder): return _copy_image(notebook, new_path, src_file, node) else: return _update_image(notebook, new_path, src_file, node) else: raise VisitorSkip elif node.tag == OBJECT: abs_src = node.attrib.pop('_src', None) if abs_src and node.get('type').startswith('image+'): src_file = LocalFile(abs_src) if src_file.ischild(old_folder): return _copy_image_object(notebook, new_path, src_file, node) else: return _update_image(notebook, new_path, src_file, node) else: raise VisitorSkip else: raise AssertionError('unknown tag')
def testQueue(self): queue = ThumbnailQueue() self.assertTrue(queue.queue_empty()) # Test input / output src_file = self.setUpFolder(mock=tests.MOCK_ALWAYS_REAL).file('test.txt') src_file.write('Test 123\n') queue.queue_thumbnail_request(src_file, 64) # put an error in the queue dir = tests.ZIM_DATA_FOLDER.folder('pixmaps') pixmaps = set() for basename in dir.list_names(): if not basename.endswith('.svg'): file = dir.file(basename) pixmaps.add(file.path) queue.queue_thumbnail_request(file, 64) self.assertFalse(queue.queue_empty()) with tests.LoggingFilter('zim.plugins.attachmentbrowser', 'Exception'): queue.start() seen = set() i = len(pixmaps) while i > 0: i -= 1 file, size, thumbfile, pixbuf, mtime = queue.get_ready_thumbnail(block=True) seen.add(file.path) self.assertEqual(size, 64) self.assertTrue(thumbfile.exists()) self.assertIsInstance(pixbuf, GdkPixbuf.Pixbuf) self.assertEqual(mtime, file.mtime()) self.assertEqual(seen, pixmaps) # Test clear self.assertTrue(queue.queue_empty()) for path in pixmaps: file = LocalFile(path) queue.queue_thumbnail_request(file, 64) self.assertFalse(queue.queue_empty()) queue.start() time.sleep(0.1) queue.clear_queue() self.assertTrue(queue.queue_empty())
def _checkargs(self, cwd, args): assert args is None or isinstance(args, (tuple, list)) argv = self._cmd(args) # Expand home dir if argv[0].startswith('~'): cmd = LocalFile(argv[0]).path argv = list(argv) argv[0] = cmd # if it is a python script, insert interpreter as the executable if argv[0].endswith('.py') and not _main_is_frozen(): argv = list(argv) argv.insert(0, sys.executable) # TODO: consider an additional commandline arg to re-use compiled python interpreter if hasattr(cwd, 'path'): cwd = cwd.path return cwd, argv
def relative_filepath(self, file, path=None): '''Get a file path relative to the notebook or page Intended as the counter part of L{resolve_file()}. Typically this function is used to present the user with readable paths or to shorten the paths inserted in the wiki code. It is advised to use file URIs for links that can not be made relative with this method. The link can be relative: - to the I{document root} (link will start with "/") - the attachments dir (if a C{path} is given) or the notebook (links starting with "./" or "../") - or the users home dir (link like "~/user/") Relative file paths are always given with Unix path semantics (so "/" even on windows). But a leading "/" does not mean the path is absolute, but rather that it is relative to the X{document root}. @param file: L{File} object we want to link @keyword path: L{Path} object for the page where we want to link this file @returns: relative file path as string, or C{None} when no relative path was found ''' from zim.newfs import LocalFile, LocalFolder file = LocalFile(file.path) # XXX notebook_root = self.layout.root document_root = LocalFolder(self.document_root.path) if self.document_root else None# XXX rootdir = '/' mydir = '.' + SEP updir = '..' + SEP # Look within the notebook if path: attachments_dir = self.get_attachments_dir(path) if file.ischild(attachments_dir): return mydir + file.relpath(attachments_dir) elif document_root and notebook_root \ and document_root.ischild(notebook_root) \ and file.ischild(document_root) \ and not attachments_dir.ischild(document_root): # special case when document root is below notebook root # the case where document_root == attachment_folder is # already caught by above if clause return rootdir + file.relpath(document_root) elif notebook_root \ and file.ischild(notebook_root) \ and attachments_dir.ischild(notebook_root): parent = file.commonparent(attachments_dir) uppath = attachments_dir.relpath(parent) downpath = file.relpath(parent) up = 1 + uppath.replace('\\', '/').count('/') return updir * up + downpath else: if document_root and notebook_root \ and document_root.ischild(notebook_root) \ and file.ischild(document_root): # special case when document root is below notebook root return rootdir + file.relpath(document_root) elif notebook_root and file.ischild(notebook_root): return mydir + file.relpath(notebook_root) # If that fails look for global folders if document_root and file.ischild(document_root): return rootdir + file.relpath(document_root) # Finally check HOME or give up path = file.userpath return path if path.startswith('~') else None
def edit_page(cmd): file = LocalFile(cmd[-1]) self.assertEqual(file, self.page.source_file) file.write('New text\n')
def show_debug_log(self): from zim.newfs import LocalFile file = LocalFile(zim.debug_log_file) open_file(self.widget, file, mimetype='text/plain')
def open_file(args): got = LocalFile(args[-1]) want = LocalFile(XDG_DATA_HOME.file('zim/templates/html/foo_test.html').path) self.assertEqual(got, want)