def reload(self): # sanity checks if not self.sanityChecks(self.open_project): return # clear the widgets self.browser.clear() self.finder.clear() # parse the ignore list (used further down the call stack) self.ignore_list = self.get_option("ignore") if self.ignore_list: self.ignore_list = [x.strip() for x in self.ignore_list.split(",")] else: self.ignore_list = [] # init the dir watcher self.dir_watcher = KDirWatch() QObject.connect(self.dir_watcher, SIGNAL("dirty ( const QString & )"), self.dirDirtied) QObject.connect(self.dir_watcher, SIGNAL("deleted ( const QString & )"), self.dirRemoved) # time and output the building of the tree t1 = time() self.addItem(QFileInfo(self.open_project), self.browser) kate.debug("project (re)load took %f seconds" % (time() - t1))
class DirectoryProject: def __init__(self, tool_widget): # we have to init the config first because all the widget __init__ methods below need it too self.initConfig() # all of our "child" widget self.browser = DPBrowser(tool_widget) self.finder = DPFinder(self) self.settings = DPSettings(self) self.dir_watcher = None self.open_project = None QObject.connect(self.browser, SIGNAL("doubleClicked ( QListViewItem *, const QPoint &, int )"), self.openItem) QObject.connect( self.finder.list_view, SIGNAL("doubleClicked ( QListViewItem *, const QPoint &, int )"), self.openItem ) self.initMenu() last_project_path = self.config.get("general", "last") if last_project_path: self.openProject(last_project_path) def initMenu(self): # ugh, we gotta get a KActionCollection instance somehow action_collection = kate.sip.cast(kate.mainWidget().topLevelWidget(), KMainWindow).actionCollection() # because our KPopupMenu has no parent, we have to keep it from going out of scope self.menu = KPopupMenu() # Open action = KAction("&Open...", "fileopen", KShortcut("Ctrl+Shift+O"), self.menuOpen, action_collection) action.plug(self.menu) # Close action = KAction("&Close", "fileclose", KShortcut.null(), self.menuClose, action_collection) action.plug(self.menu) # Reload action = KAction("&Reload", "reload", KShortcut("Shift+F5"), self.menuReload, action_collection) action.plug(self.menu) self.menu.insertSeparator() # Find Files action = KAction("&Find Files...", "find", KShortcut("Ctrl+H"), self.menuFindFiles, action_collection) action.plug(self.menu) self.menu.insertSeparator() # Settings action = KAction("&Settings...", "configure", KShortcut.null(), self.menuSettings, action_collection) action.plug(self.menu) # insert the menu into the menu bar menu_bar = kate.mainWidget().topLevelWidget().menuBar() menu_bar.insertItem("&Project", self.menu, -1, 4) def initConfig(self): kate.debug("initConfig()") config_path = kate.pate.pluginDirectories[1] + "/%s/%s.conf" % (__name__, __name__) config_file = QFileInfo(config_path) if not config_file.exists(): open(config_path, "w").close() config = ConfigParser() config.read(config_path) # init the DEFAULT options if they don't exist # the DEFAULT section is special and doesn't need to be created: if not config.has_section('DEFAULT'): config.add_section('DEFAULT') if not config.has_option("DEFAULT", "ignore"): config.set("DEFAULT", "ignore", "") if not config.has_option("DEFAULT", "filter"): config.set("DEFAULT", "filter", "*") if not config.has_option("DEFAULT", "finder_size"): config.set("DEFAULT", "finder_size", "400x450") if not config.has_option("DEFAULT", "config_size"): config.set("DEFAULT", "config_size", "300x350") if not config.has_option("DEFAULT", "search_type"): config.set("DEFAULT", "search_type", "word") # create the general section if it doesn't exist if not config.has_section("general"): config.add_section("general") # flush the config file config.write(open(config_path, "w")) # save the config object and config path as instance vars for use later self.config = config self.config_path = config_path # end def initConfig() # convenience method to get a config option for the currently open project def get_option(self, option_name): return self.config.get(self.open_project, option_name) # convenience method that sets a config option for the currently open project def set_option(self, name, value): self.config.set(self.open_project, name, value) # convenience method to save the config file def saveConfig(self): self.config.write(open(self.config_path, "w")) def reload(self): # sanity checks if not self.sanityChecks(self.open_project): return # clear the widgets self.browser.clear() self.finder.clear() # parse the ignore list (used further down the call stack) self.ignore_list = self.get_option("ignore") if self.ignore_list: self.ignore_list = [x.strip() for x in self.ignore_list.split(",")] else: self.ignore_list = [] # init the dir watcher self.dir_watcher = KDirWatch() QObject.connect(self.dir_watcher, SIGNAL("dirty ( const QString & )"), self.dirDirtied) QObject.connect(self.dir_watcher, SIGNAL("deleted ( const QString & )"), self.dirRemoved) # time and output the building of the tree t1 = time() self.addItem(QFileInfo(self.open_project), self.browser) kate.debug("project (re)load took %f seconds" % (time() - t1)) # end def reload() def openProject(self, project_path): # clean up the input project_path = str(project_path).strip() # sanity checks if not self.sanityChecks(project_path): return # little debug info kate.debug("opening new project: " + project_path) # set the open project self.open_project = project_path # init its config section if need be if not self.config.has_section(project_path): self.config.add_section(project_path) # update the last open project in the config section self.config.set("general", "last", project_path) # write the config so we always stay in sync self.saveConfig() # build the project tree! self.reload() # end def openProject() def passIgnore(self, file_info): file_name = file_info.fileName() if file_name == ".": return False if file_name == "..": return False if file_name in self.ignore_list: return False return True # end def passIgnore() def sanityChecks(self, project_path): file_info = QFileInfo(project_path) if not file_info.exists(): kate.debug("project dir does not exist: %s" % project_path) return False if not file_info.isDir(): kate.debug("project dir is not a directory: %s" % project_path) return False return True # end def sanityChecks() def openItem(self, item, trash1, trash2): self.openItems((item,)) def openItems(self, items): for item in items: if not item: continue # what the hell? something is broken if item.is_dir == False: kate.debug("file dbl clicked") kate.documentManager.open(item.path) d = kate.documentManager.get(item.path) kate.application.activeMainWindow().viewManager().activateView(d.number) self.finder.close() else: kate.debug("dir dbl clicked") self.browser.setOpen(item, not self.browser.isOpen(item)) # we only care about files and added dirs here. def dirDirtied(self, path): path = str(path) kate.debug("dirDirtied: " + path) # find the list view item for the watched directory lvi = self.browser.findItem(path, 1) if not lvi: kate.debug("cannot find directory: " + path) return # create a set of all it's children our_set = set() p = lvi.firstChild() while p: our_set.add(str(p.text(1))) p = p.nextSibling() # create a set of all the actual directory's children real_set = set() d = QDir(path) for file_info in d.entryInfoList(): if file_info.fileName() == ".": continue if file_info.fileName() == "..": continue real_set.add(str(file_info.absFilePath())) # difference the set and those are our adds set_diff = real_set.difference(our_set) for path in set_diff: file_info = QFileInfo(path) self.addItem(file_info, lvi) kate.debug("added files/dirs: " + str(set_diff)) # differece the other way and those are our deletes set_diff = our_set.difference(real_set) kate.debug("removing files/dirs: " + str(set_diff)) for path in set_diff: self.removeItem(path) # we only care about removed dirs here. def dirRemoved(self, path): kate.debug("dirRemoved: " + str(path)) # unlike browser and finder's addItem(), this is recursive def addItem(self, file_info, parent): # base case (file) if file_info.isFile(): if self.passIgnore(file_info): p = self.browser.addItem(file_info, parent) self.finder.addItem(file_info, p.pixmap(0)) # recursive case (dir) else: d = QDir(file_info.absFilePath()) if not self.passIgnore(file_info): return parent = self.browser.addItem(file_info, parent) # watch this dir for changes self.dir_watcher.addDir(file_info.absFilePath()) # do directories first d.setFilter(QDir.Dirs) for file_info in d.entryInfoList(): self.addItem(file_info, parent) # now do files d.setFilter(QDir.Files) d.setNameFilter(self.config.get(self.open_project, "filter")) for file_info in d.entryInfoList(): self.addItem(file_info, parent) # unlike browser and finder's removeItem(), this is recursive def removeItem(self, path): p = self.browser.findItem(path, 1) # base case (file) if p.childCount() == 0: self.browser.removeItem(path) self.finder.removeItem(path) # recursive case (dir) else: n = p.firstChild() while n: temp = n # the ole linked list gotcha: if we delete n, then n.nextSibling() will return None n = n.nextSibling() self.removeItem(temp.text(1)) self.browser.removeItem(path) self.dir_watcher.removeDir(path) def menuOpen(self): kate.debug("menuOpen()") project_path = KFileDialog.getExistingDirectory() if project_path: self.openProject(project_path) def menuClose(self): kate.debug("menuClose()") self.browser.clear() self.finder.clear() self.open_project = None self.config.set("general", "last", "") self.saveConfig() def menuFindFiles(self): kate.debug("menuFindFiles()") if not self.open_project: KMessageBox.information(kate.mainWidget(), "Open a project first.", "No Project Open") else: self.finder.show() def menuReload(self): kate.debug("menuReload()") if self.open_project: self.reload() else: KMessageBox.information(kate.mainWidget(), "There is no project open to reload.", "No Project Open") def menuSettings(self): kate.debug("menuSettings()") self.settings.show()