def __init__(self, app): """ Set up the initial thread for monitoring the directory """ QThread.__init__(self) self.dw = KDirWatch() self.app = app
def init(self): self._keywords = {} self._bookmarks = [] self._googleBaseURL = ChromiumRunner.DEFAULT_GOOGLE_URL # FIXME: Should go to config homePath = os.environ.get("HOME") self._pathWebData = os.path.join(homePath, ".config/chromium/Default/Web Data") self._pathLocalState = os.path.join(homePath, ".config/chromium/Local State") self._pathBookmarks = os.path.join(homePath, ".config/chromium/Default/Bookmarks") self.setSyntaxes([ Plasma.RunnerSyntax( "<Chromium keyword> :q:", "Search for :q: using Chromium keyword"), Plasma.RunnerSyntax( ":q:", "Search for :q: in your Chromium bookmarks") ]) # Initially read data self._readKeywords() self._readBookmarks() self._readLastKnownGoogleUrl() # Watch the files for changes self._watcher = KDirWatch(self) self._watcher.addFile(self._pathWebData) self._watcher.addFile(self._pathLocalState) self._watcher.addFile(self._pathBookmarks) self.connect(self._watcher, SIGNAL("created(QString)"), self._updateData) self.connect(self._watcher, SIGNAL("dirty(QString)"), self._updateData)
def __init__ (self, parent, path="", relative=False, busName=None, busPath=None): SatyrObject.__init__ (self, parent, busName, busPath) self.songs= [] self.count= 0 # (re)defined by an aggregator if we're in one of those self.offset= 0 # BUG: path is not reread from the config file! # it breaks rescanning self.configValues= ( ('path', str, path), ) self.loadConfig () # print busPath, self.path # if the user requests a new path, use it if self.path!=path and path!="": path= os.path.abspath (path) self.path= path self.forceScan= True logger.info ("new path, forcing (re)scan") else: self.forceScan= False self.relative= relative logger.debug ("Collection(): %s", self.path) self.watch= KDirWatch (self) self.watch.addDir (self.path, KDirWatch.WatchMode (KDirWatch.WatchFiles|KDirWatch.WatchSubDirs)) self.watch.created.connect (self.newFiles) self.scanners= [] self.scanning= False self.loadMetadata= False if busPath is not None: self.collectionFile= str (KStandardDirs.locateLocal ('data', 'satyr/%s.tdb' % self.dbusName (busPath))) else: self.collectionFile= str (KStandardDirs.locateLocal ('data', 'satyr/collection.tdb'))
def init(self): """ Setup plasma layout """ # Set initial paths self.project_path = '~/.sublimetext2/projects' self.projects = "" self.exe_path = '~/Sublime Text 2/sublime_text' self.exe = "" self.project_map = {} # Watch the project directory for updates self.dirwatch = KDirWatch(self.applet) self.dirwatch.addDir(QString(self.project_path)) self.connect(self.dirwatch, SIGNAL("dirty(QString)"), self.configChanged) # Setup layout self.setHasConfigurationInterface(True) self.setAspectRatioMode(Plasma.IgnoreAspectRatio) self.layout = QGraphicsLinearLayout(self.applet) self.makeWidget() self.layout.addItem(self.list_view) self.setLayout(self.layout) self.resize(300,200)
class ChromiumRunner(plasmascript.Runner): DEFAULT_GOOGLE_URL = "https://www.google.com" def init(self): self._keywords = {} self._bookmarks = [] self._googleBaseURL = ChromiumRunner.DEFAULT_GOOGLE_URL # FIXME: Should go to config homePath = os.environ.get("HOME") self._pathWebData = os.path.join(homePath, ".config/chromium/Default/Web Data") self._pathLocalState = os.path.join(homePath, ".config/chromium/Local State") self._pathBookmarks = os.path.join(homePath, ".config/chromium/Default/Bookmarks") self.setSyntaxes([ Plasma.RunnerSyntax( "<Chromium keyword> :q:", "Search for :q: using Chromium keyword"), Plasma.RunnerSyntax( ":q:", "Search for :q: in your Chromium bookmarks") ]) # Initially read data self._readKeywords() self._readBookmarks() self._readLastKnownGoogleUrl() # Watch the files for changes self._watcher = KDirWatch(self) self._watcher.addFile(self._pathWebData) self._watcher.addFile(self._pathLocalState) self._watcher.addFile(self._pathBookmarks) self.connect(self._watcher, SIGNAL("created(QString)"), self._updateData) self.connect(self._watcher, SIGNAL("dirty(QString)"), self._updateData) @pyqtSlot() def _updateData(self, path): """ Called by KDirWatch if a watched dir has changed (dirty). """ if path == self._pathWebData: self._readKeywords() elif path == self._pathLocalState: self._readLastKnownGoogleUrl() elif path == self._pathBookmarks: self._readBookmarks() @pyqtSlot() def _readKeywords(self): """ Read chromium keywords. """ # Copy Chromium Web Data as it is locked if Chromium running... This is # risky as sqlite could be in the middle of performing some transaction! if os.path.isfile(self._pathWebData) and os.access(self._pathWebData, os.R_OK): _, dbfile = mkstemp("krunner-chromium") copy2(self._pathWebData, dbfile) cur = sqlite3.connect(dbfile).cursor() try: cur.execute("SELECT short_name, keyword, url FROM keywords") self._keywords = {} for shortName, keyword, url in cur.fetchall(): if not keyword in self._keywords: self._keywords[keyword] = (shortName, url) # order matters finally: cur.close() os.unlink(dbfile) @pyqtSlot() def _readBookmarks(self): """ Read Chromium bookmarks. """ with open(self._pathBookmarks, 'r') as bfile: def walk(element): for item in element: if item["type"] == "url": tmp = (QString(item["name"]), QString(item["url"])) # order matters if not tmp in self._bookmarks: self._bookmarks.append(tmp) elif item["type"] == "folder": walk(item["children"]) self._bookmarks = [] jsonRoots = json.load(bfile).get("roots", {}) for key in (v for v in jsonRoots.itervalues() if type(v) is dict): walk(key.get("children", {})) @pyqtSlot() def _readLastKnownGoogleUrl(self): """ Read the last_known_google_url from `Local State`. """ with open(self._pathLocalState, 'r') as localStateFile: self._googleBaseURL = json.load(localStateFile)\ .get("browser", {})\ .get("last_known_google_url", ChromiumRunner.DEFAULT_GOOGLE_URL) def match(self, context): """ Inspect the current query and provide appropriate matches. """ if not context.isValid(): return query = context.query().trimmed() # Look for keywords for keyword in self._keywords: if query.startsWith(keyword + " "): searchTerms = query[len(keyword)+1:] if len(searchTerms) >= 2: self._matchKeyword(context, query, searchTerms, keyword) # Look for bookmarks flt = lambda (bmName, _): bmName.contains(query, Qt.CaseInsensitive) for bookmark in filter(flt, self._bookmarks): self._matchBookmark(context, query, bookmark) def _matchBookmark(self, context, query, matchedBookmark): """ Add a bookmark match for the given `query` to `context`. """ name, url = matchedBookmark m = Plasma.QueryMatch(self.runner) m.setText("\"%s\"\n%s" % (name, url)) m.setType(Plasma.QueryMatch.ExactMatch) m.setIcon(KIcon("bookmarks")) m.setData(url) context.addMatch(query, m) def _matchKeyword(self, context, query, searchTerms, matchedKeyword): """ Add a keyword match for the given `query` to `context`. """ shortName, url = self._keywords[matchedKeyword] # This explicit "cast" to QString is necessary in order to prevent # python from interpreting `url` as a regular string. This way, # unicode handling is a lot easier. url = QString(url).replace("{searchTerms}", searchTerms) # Default google search URL is some freaky contruction like: # {google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}{google:searchFieldtrialParameter}{google:instantFieldTrialGroupParameter}sourceid=chrome&client=ubuntu&channel=cs&ie={inputEncoding}&q=%s # google:baseURL is in attr "last_known_google_url" in ~./config/chromium/Local State # Quick workaround... if url.startsWith("{google:baseURL}"): url = QUrl("%s/search" % self._googleBaseURL) url.addQueryItem("q", searchTerms) url.addQueryItem("qf", "f") url = url.toString() m = Plasma.QueryMatch(self.runner) m.setText("Query \"%s\" for '%s'\n%s" % (shortName, searchTerms, url)) m.setType(Plasma.QueryMatch.ExactMatch) m.setIcon(KIcon("chromium-browser")) m.setData(url) context.addMatch(query, m) def run(self, context, match): if context.isValid(): KToolInvocation.invokeBrowser(match.data().toString())
class SublimeText2Applet(plasmascript.Applet): def __init__(self,parent,args=None): plasmascript.Applet.__init__(self,parent) def init(self): """ Setup plasma layout """ # Set initial paths self.project_path = '~/.sublimetext2/projects' self.projects = "" self.exe_path = '~/Sublime Text 2/sublime_text' self.exe = "" self.project_map = {} # Watch the project directory for updates self.dirwatch = KDirWatch(self.applet) self.dirwatch.addDir(QString(self.project_path)) self.connect(self.dirwatch, SIGNAL("dirty(QString)"), self.configChanged) # Setup layout self.setHasConfigurationInterface(True) self.setAspectRatioMode(Plasma.IgnoreAspectRatio) self.layout = QGraphicsLinearLayout(self.applet) self.makeWidget() self.layout.addItem(self.list_view) self.setLayout(self.layout) self.resize(300,200) def makeWidget(self): """ Create the TreeView widget and connect the clicked signal """ self.list_view = Plasma.TreeView() self.list_view.nativeWidget().header().hide() self.list_view.nativeWidget().setRootIsDecorated(False) self.st2_model = QStandardItemModel() self.list_view.setModel(self.st2_model) self.initSessionFiles() self.connect(self.list_view.nativeWidget(), SIGNAL("activated(const QModelIndex &)"), self.slotOnItemClicked) def initSessionFiles(self): """ Create the list items for the TreeView from the project directory """ index = 1 item = QStandardItem() item.setData("Start Sublime Text 2 (New Project)", role=Qt.DisplayRole) item.setIcon(KIcon("document-new")) item.setData(index, role=Qt.UserRole+1) self.st2_model.appendRow(item) index += 1 item = QStandardItem() item.setData("Start Sublime Text 2 (Previous Session)", role=Qt.DisplayRole) item.setIcon(KIcon("document-edit")) item.setData(index, role=Qt.UserRole+1) self.st2_model.appendRow(item) fnames = sorted(glob.iglob(self.project_path+"/*.sublime-project")) for fname in fnames: name = os.path.basename(fname).rsplit('.')[0] if name == 'blank': continue index += 1 item = QStandardItem() item.setData(name, role=Qt.DisplayRole) item.setData(index, role=Qt.UserRole+1) self.st2_model.appendRow(item) self.project_map[index] = fname def slotOnItemClicked(self,selection): """ Launch the application with the correct arguments """ index = selection.data(Qt.UserRole+1).toInt()[0] if index == 1: """ Hack: create a blank project to open to simulate a new blank project similar to Kate's behavior. Hopefully in the future there will be a flag for a new project in sublime text that does not also open previous session files. """ with open(self.project_path+"/blank.sublime-project",'w') as blank_proj: blank_proj.write('{ "folders":[{}] }') with open(self.project_path+"/blank.sublime-workspace",'w') as blank_proj: blank_proj.write('''{ "auto_complete": { "selected_items": [ ] }, "buffers": [ ], "build_system": "", "command_palette": { "height": 345.0, "selected_items": [ ], "width": 449.0 }, "console": { "height": 0.0 }, "distraction_free": { "menu_visible": true, "show_minimap": false, "show_open_files": false, "show_tabs": false, "side_bar_visible": false, "status_bar_visible": false }, "file_history": [ ], "find": { "height": 0.0 }, "find_in_files": { "height": 0.0, "where_history": [ ] }, "find_state": { "case_sensitive": false, "find_history": [ ], "highlight": true, "in_selection": false, "preserve_case": false, "regex": false, "replace_history": [ ], "reverse": false, "show_context": true, "use_buffer2": true, "whole_word": false, "wrap": true }, "groups": [ { "sheets": [ ] } ], "incremental_find": { "height": 0.0 }, "input": { "height": 0.0 }, "layout": { "cells": [ [ 0, 0, 1, 1 ] ], "cols": [ 0.0, 1.0 ], "rows": [ 0.0, 1.0 ] }, "menu_visible": true, "replace": { "height": 0.0 }, "save_all_on_build": true, "select_file": { "height": 0.0, "selected_items": [ ], "width": 0.0 }, "select_project": { "height": 0.0, "selected_items": [ ], "width": 0.0 }, "show_minimap": true, "show_open_files": true, "show_tabs": false, "side_bar_visible": true, "side_bar_width": 303.0, "status_bar_visible": true }''') pid = Popen([self.exe_path,'--project','%s' % self.project_path+"/blank.sublime-project"]).pid elif index == 2: # Open a new window with the previus contents pid = Popen([self.exe_path,'-n']).pid else: # Open a specific project file pid = Popen([self.exe_path,'--project','%s' % self.project_map[index]]).pid def createConfigurationInterface(self, dlg): """ Create the settings menu item to allow the user to set the paths """ self.groupBox = QGroupBox() self.groupBox.setTitle('Projects') self.projects = QLineEdit(QString(self.project_path)) self.exe = QLineEdit(QString(self.exe_path)) self.vbox = QVBoxLayout() self.vbox.addWidget(QLabel(QString('Path to project files'))) self.vbox.addWidget(self.projects) self.vbox.addWidget(QLabel(QString('Path to Sublime Text 2 executable'))) self.vbox.addWidget(self.exe) self.groupBox.setLayout(self.vbox) p = dlg.addPage(self.groupBox, "Settings" ) p.setIcon( KIcon("preferences-system-windows-actions") ) dlg.setButtons(KDialog.ButtonCode(KDialog.Ok | KDialog.Cancel)) self.connect(dlg, SIGNAL("okClicked()"), self.configChanged) def configChanged(self): """ A change was made so update the list of projects """ if self.projects and os.path.exists(self.projects.text()): self.dirwatch.removeDir(QString(self.project_path)) self.project_path = str(self.projects.text()) self.dirwatch.addDir(QString(self.project_path)) self.dirwatch.startScan() if self.exe and os.path.exists(str(self.exe.text())): self.exe_path = str(self.exe.text()) self.st2_model.clear() self.project_map = {} self.initSessionFiles()
class Collection (SatyrObject): """A Collection of Albums""" newSongs= pyqtSignal () scanBegins= pyqtSignal () scanFinished= pyqtSignal () def __init__ (self, parent, path="", relative=False, busName=None, busPath=None): SatyrObject.__init__ (self, parent, busName, busPath) self.songs= [] self.count= 0 # (re)defined by an aggregator if we're in one of those self.offset= 0 # BUG: path is not reread from the config file! # it breaks rescanning self.configValues= ( ('path', str, path), ) self.loadConfig () # print busPath, self.path # if the user requests a new path, use it if self.path!=path and path!="": path= os.path.abspath (path) self.path= path self.forceScan= True logger.info ("new path, forcing (re)scan") else: self.forceScan= False self.relative= relative logger.debug ("Collection(): %s", self.path) self.watch= KDirWatch (self) self.watch.addDir (self.path, KDirWatch.WatchMode (KDirWatch.WatchFiles|KDirWatch.WatchSubDirs)) self.watch.created.connect (self.newFiles) self.scanners= [] self.scanning= False self.loadMetadata= False if busPath is not None: self.collectionFile= str (KStandardDirs.locateLocal ('data', 'satyr/%s.tdb' % self.dbusName (busPath))) else: self.collectionFile= str (KStandardDirs.locateLocal ('data', 'satyr/collection.tdb')) def loadOrScan (self): if self.forceScan or not self.load (): self.scan () def load (self): logger.info ('loading from', self.collectionFile) try: # we must remove the trailing newline # we could use strip(), but filenames ending with any other whitespace # (think of the users!) would be loaded incorrectly # this oneliner seems to be the fastest against: # * fp= []; f= open(); for line in f.readlines(): fp.append (line) # * fp= []; f= open(); for line in f: fp.append (line) filepaths= [ line[:-1] for line in open (self.collectionFile) ] self.add (filepaths) ans= True except IOError, e: logger.warning ("no database!") logger.warning ('FAILED!', e) ans= False return ans