class GCalApplet(plasmascript.Applet): def __init__(self,parent,args=None): plasmascript.Applet.__init__(self,parent) self.parent = parent def init(self): self.settings = {} self.setHasConfigurationInterface(True) self.theme = Plasma.Svg(self) self.theme.setImagePath("widgets/background") self.setBackgroundHints(Plasma.Applet.DefaultBackground) self.setAspectRatioMode(Plasma.IgnoreAspectRatio) self.wallet = KWallet.Wallet.openWallet(KWallet.Wallet.LocalWallet(), 0, 1) self.timer = QTimer(self) # for polling network connectivity if offline self.storeUserAndDomain("", "") if self.wallet <> None: self.connect(self.wallet, SIGNAL("walletOpened(bool)"), self.walletOpened) self.layout = QGraphicsLinearLayout(Qt.Horizontal, self.applet) self.webview = Plasma.WebView(self.applet) # google's ugly 1995 gifs ruins the beauty of transparency :( palette = self.webview.palette() palette.setBrush(QPalette.Base, Qt.white) self.webview.page().setPalette(palette) self.webview.setAttribute(Qt.WA_OpaquePaintEvent, False) self.webview.setHtml(self.getSrc()) self.layout.addItem(self.webview) self.setLayout(self.layout) self.resize(300,400) def paintInterface(self, painter, option, rect): painter.save() painter.setPen(Qt.white) painter.setBrush(Qt.white) rectangle = QRectF(15.0, 15.0, self.size().width()-30.0, self.size().height()-30.0) painter.drawRoundedRect(rectangle, 6.0, 6.0) painter.restore() def createConfigurationInterface(self, parent): self.gcalsettings = Settings(self) p = parent.addPage(self.gcalsettings, i18n("Google Calendar Settings") ) self.connect(parent, SIGNAL("okClicked()"), self.configAccepted) self.connect(parent, SIGNAL("cancelClicked()"), self.configDenied) def showConfigurationInterface(self): dialog = KPageDialog() dialog.setFaceType(KPageDialog.Plain) dialog.setButtons( KDialog.ButtonCode(KDialog.Ok | KDialog.Cancel) ) self.createConfigurationInterface(dialog) dialog.resize(400,300) dialog.exec_() def configDenied(self): pass def configAccepted(self): self.settings = self.gcalsettings.getSettings() self.storeUserAndDomain(self.settings['username'], self.settings['password']) wallet = KWallet.Wallet.openWallet(KWallet.Wallet.LocalWallet(), 0) if wallet <> None: wallet.setFolder("gcal-plasmoid") for e in wallet.entryList(): wallet.removeEntry(e) wallet.writePassword(QString(self.settings['username']), QString(self.settings['password'])) wallet = None self.webview.setHtml(self.getSrc()) def storeUserAndDomain(self, username, password): re_email = re.compile('@(.+)') m = re_email.search(username) # if username is an email address with a domain name other than # gmail.com, assume it's a Google Apps for your Domain thingie and # change the url if m <> None and m.group(1) <> "gmail.com" and m.group(1) <> "googlemail.com": self.url = "http://google.com/calendar/hosted/" + m.group(1) + "/m" else: self.url = "http://google.com/calendar/m" self.settings['username'] = username self.settings['password'] = password def getSrc(self): try: webFile = urllib.urlopen(self.url) src = webFile.read() webFile.close() if self.timer.isActive(): self.timer.stop() except IOError, e: # NOTE: It appears that the Solid.Networking.notifier() function has # not be included in pyKDE4 as of now. This should be used when it # is included. For now, lets try every 5 seconds... if not self.timer.isActive(): self.timer.setInterval(5000) self.connect(self.timer, SIGNAL("timeout()"), self.connectionCheck) self.timer.start() src = """ <div style="text-align: center; color: #ee2222;"> <p> Network error: Could not connect to Google Calendar. </p> </div> """ if self.settings['username']: re_email = re.compile('@(.+)') username = re_email.sub('', self.settings['username']) src = src.replace("id=\"Email\"", "id=\"Email\" value=\""+username+"\"") src = src.replace("id=\"Passwd\"", "id=\"Passwd\" value=\""+self.settings['password']+"\"") src = src.replace("id=\"gaia_loginform\"", "id=\"gaia_loginform\" name=\"gaia_loginform\"") src = src.replace("</body>", "<script>document.gaia_loginform.submit()</script></body>") return src
class GalleryManager(): """ Main class of application """ CONFIGDIR = '.config' THUMBDIR = 'thumb' COOKIEFILE = 'cookies.yaml' THUMB_MAXSIZE = 180, 270 # reserved category (folder) names RESERVED = {'new_dir':'_new', 'unsorted_dir':'_unsorted'} def __init__(self, gallerypath=''): self.gallerypath = str(gallerypath) self.configpath = None self.thumbpath = None self.dbmodel = None self.settings = None self.ehfetcher = None self.fakkufetcher = None if self.gallerypath is not '': self.openPath(self.gallerypath) def close(self): """ Closes connection to gallery. """ self.dbmodel.closeDatabase() def openPath(self, path): """ Open path as a gallery and creates connection to its database. If path is not gallery creates empty gallery structure. """ self.gallerypath = os.path.abspath(str(path)) # checks if path is existing gallery. if not creates one. if self.isGallery(self.gallerypath) is False: self.initGallery(self.gallerypath) # def paths self.configpath = os.path.join(self.gallerypath, self.CONFIGDIR) self.thumbpath = os.path.join(self.configpath, self.THUMBDIR) # load settings self.settings = Settings(self.configpath) self.settings.loadSettings() # open connection to database self.dbmodel = DatabaseModel(self.configpath) self.dbmodel.openDatabase() # init fetchers self.ehfetcher = EHFetcher(self) self.fakkufetcher = FakkuFetcher() def isGallery(self, path): """ Checks if path leads to existing gallery. """ configpath = os.path.join(str(path), self.CONFIGDIR) thumbpath = os.path.join(configpath, self.THUMBDIR) if os.path.isdir(configpath): database_path = os.path.join(configpath, DatabaseModel.FILENAME) if os.path.isfile(database_path) and os.path.isdir(thumbpath): logger.debug('isGallery: given path is existing gallery.') return True logger.debug('isGallery: given path is not gallery.') return False def initGallery(self, path): """ Creates new gallery basic structure. """ logger.debug('Creating new gallery structure...') configpath = os.path.join(path, self.CONFIGDIR) thumbpath = os.path.join(configpath, self.THUMBDIR) # create config folder and files if not os.path.isdir(configpath): os.mkdir(configpath) if not os.path.isdir(thumbpath): os.mkdir(thumbpath) DatabaseModel(configpath) setmod = Settings(configpath) setmod.loadSettings() setmod.saveSettings() # create default category folders # TODO - show confirm dialog before touching files #self.initFolders(path, setmod) # disabled for now def initFolders(self, path, settings): # TODO - decide if use or remove """ Creates basic gallery folder structure """ configpath = os.path.join(path, self.CONFIGDIR) setmod = settings # create folder for files that dont has correct category fpath = os.path.join(path, self.RESERVED['unsorted_dir']) if not os.path.isdir(fpath): os.mkdir(fpath) # create folder for files that are not in database yet. (added by user) fpath = os.path.join(path, self.RESERVED['new_dir']) if not os.path.isdir(fpath): os.mkdir(fpath) # move all files from existing directiories to _new directory logger.debug('Getting list of files in gallery path...') filepathlist = [] for root, dirs, files in os.walk(unicode(path)): if os.path.commonprefix([configpath, root]) != configpath: paths = [os.path.join(root,f) for f in files] filepathlist+=paths logger.debug('Found '+str(len(filepathlist))+' files') logger.debug('Moving existing files to _new folder...') for filepath in filepathlist: logger.debug('Moving file '+filepath+' to new dir.') dest = os.path.join(path, os.path.join(self.RESERVED['new_dir'], os.path.basename(filepath))) if filepath == dest: logger.debug('source and destintion paths are identical') continue elif os.path.isfile(dest): logger.debug('There is allready file with same name in new directory, genereating hashes...') old_hash = self.getHash(dest) new_hash = self.getHash(filepath) if old_hash == new_hash: logger.debug('files are identical, overwritting the old one.') else: logger.debug('files are different, creating subdirectory for new file') n = 0 while os.path.isdir(os.path.join(path, os.path.join(self.RESERVED['new_dir'], str(n)))): n = random.randint(0,999999) fpath = os.path.join(path, os.path.join(self.RESERVED['new_dir'], str(n))) os.mkdir(fpath) dest = os.path.join(fpath, os.path.basename(filepath)) shutil.move(filepath, dest) # remove all old directories for folder in os.listdir(path): if folder in [self.RESERVED['unsorted_dir'], self.RESERVED['new_dir'], self.CONFIGDIR]: continue else: logger.debug('Removing folder '+folder) shutil.rmtree(os.path.join(path, folder)) # create new category folders for c in setmod.getSettings()['categories']: fpath = os.path.join(path, c) if not os.path.isdir(fpath): logger.debug('creating folder '+c) os.mkdir(fpath) def getSettings(self): return self.settings.getSettings() def getDefaultSettings(self): return self.settings.getDefaultSettings() def saveSettings(self, newSettings): # remove reserved category names from new settings for rc in self.RESERVED: if rc in newSettings['categories']: newSettings.remove(rc) logger.warning('saveSettings: Removing reserved name '+rc+' from new category list') # TODO - make/remove category folders self.settings.setSettings(newSettings) self.settings.saveSettings() def getHash(self, filepath): """ Returns hash of file. """ afile = open(filepath, 'rb') buf = afile.read() afile.close() hasher = hashlib.sha1() hasher.update(buf) filehash = hasher.hexdigest() logger.debug('Generated sha1 hash - '+str(filehash)) return filehash def addFile(self, filepath, filehash = None): """ Add fileinfo to database """ logger.debug('Processing file - '+filepath) if filehash is None: filehash = self.getHash(filepath) # get relative filepath to gallery path commonprefix = os.path.commonprefix([self.gallerypath, filepath]) if commonprefix != self.gallerypath: logger.error('File is not in child directory of gallery!!!'+ \ '\nfilepath: '+filepath+'\ngallerypath: '+ \ str(self.gallerypath)+'\ncommonprefix: '+commonprefix) return False elif len(self.getFileByHash(filehash))>0: logger.error('File with same hash is already in database') return False else: title = os.path.splitext(os.path.basename(filepath))[0] filepath_rel = os.path.relpath(filepath, commonprefix) logger.debug('File relative path -> '+filepath_rel) # add file to database self.dbmodel.addFile(filehash=filehash, filepath=filepath_rel, title=title) # get thumbnail try: self.getThumb(filepath, filehash) except Exception, e: logger.error('Other error when generating thumb: '+str(e)) return True
class MPDPlasmoidClient(plasmascript.Applet): def __init__(self, parent, args=None): plasmascript.Applet.__init__(self, parent) self.setApplet(Plasma.Applet(parent, [])) self.parent = parent def init(self): """Init plasmoid""" self.setHasConfigurationInterface(True) self.setAspectRatioMode(Plasma.IgnoreAspectRatio) ## Set full filename self.configFilename = ".MPDPCrc" pathToFile = os.path.join(os.path.expanduser("~"), self.configFilename) ## Trying to read settings from config file try: configParser = ConfigParser() configFile = open(pathToFile) configParser.readfp(configFile, pathToFile) host = configParser.get("general", "host") port = configParser.get("general", "port") orientation = configParser.get("general", "orientation") icons = configParser.get("general", "icons") stop = False if configParser.get("general", "stop") == "False" else True popup = False if configParser.get("general", "popup") == "False" else True cover = False if configParser.get("general", "cover") == "False" else True configFile.close() ## If it not successful then set default settings except: host = "localhost" port = 6600 orientation = "h" icons = "u" stop = False popup = True cover = True self._host = host self._port = port self._orientation = orientation self._icons = icons self._stop = stop self._popup = popup self._cover = cover ## Setup user interface self.setupInterface(self._orientation, self._icons) self.applet.setLayout(self.buttonsLayout) self.data = Plasma.ToolTipContent() # if self._popup: # Plasma.ToolTipManager.self().setContent(self.applet, self.data) # self.lastSong = -1 self.timer = QTimer() ## Every second check connect to server and icon for ppButton QObject.connect(self.timer, SIGNAL("timeout()"), self.checkConnect) QObject.connect(self.timer, SIGNAL("timeout()"), self.checkIcon) # QObject.connect(self.timer, SIGNAL("timeout()"), self.checkSong) self.timer.start(1000) def createConfigurationInterface(self, parent): """Create config interface for config dialog""" ## Create object, containing settings self.defaultSettings = { "host": self._host, "port": self._port, "orientation": self._orientation, "icons": self._icons, "stop": self._stop, "popup": self._popup, "cover": self._cover, } ## Create settings object ## And send settings to constructor self.settings = Settings(self, self.defaultSettings) settingsPage = parent.addPage(self.settings, ki18n("Main Options").toString()) settingsPage.setIcon(KIcon("applications-multimedia")) self.connect(parent, SIGNAL("okClicked()"), self.configAccepted) self.connect(parent, SIGNAL("cancelClicked()"), self.configDenied) def showConfigurationInterface(self): """Show created config dialog""" dialog = KPageDialog() dialog.setFaceType(KPageDialog.List) dialog.setButtons(KDialog.ButtonCode(KDialog.Ok | KDialog.Cancel)) self.createConfigurationInterface(dialog) dialog.resize(500, 500) dialog.exec_() def configDenied(self): pass def configAccepted(self): """This slot called, when "Ok" button pressed""" ## Load settings settingsObject = self.settings.getSettings() self._host = settingsObject["host"] self._port = settingsObject["port"] self._orientation = settingsObject["orientation"] self._icons = settingsObject["icons"] self._stop = settingsObject["stop"] self._popup = settingsObject["popup"] self._cover = settingsObject["cover"] ## Save settings to file configParser = ConfigParser() pathToFile = os.path.join(os.path.expanduser("~"), self.configFilename) configParser.read(pathToFile) if not configParser.has_section("general"): configParser.add_section("general") configParser.set("general", "host", settingsObject["host"]) configParser.set("general", "port", settingsObject["port"]) configParser.set("general", "orientation", settingsObject["orientation"]) configParser.set("general", "icons", settingsObject["icons"]) configParser.set("general", "stop", settingsObject["stop"]) configParser.set("general", "popup", settingsObject["popup"]) configParser.set("general", "cover", settingsObject["cover"]) pathToFile = os.path.join(os.path.expanduser("~"), self.configFilename) configFile = open(pathToFile, "w") configParser.write(configFile) configFile.close() ## Reload plasmoid interface with new settings self.removeIntarface() self.setupInterface(self._orientation, self._icons) def hoverEnterEvent(self, event): if not self.isConnected(): return """When mouse over plasmoid, update tooltip content""" if self._popup: self.updateToolTipInfo() else: Plasma.ToolTipManager.self().hide(self.applet) def updateToolTipInfo(self): """Show popup dialog with song info""" song = self.genInfo() if self._cover: self.data = Plasma.ToolTipContent() self.data.setMainText("<font size = +2>" + song["title"] + "</font>") self.data.setSubText("by <b>" + song["artist"] + "</b> from <b>" + song["album"] + "<b>") self.cover = QPixmap(song["cover"]) self.data.setImage(self.cover.scaled(80, 80, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) else: self.data = Plasma.ToolTipContent() self.data.setMainText("<font size = +2>" + song["title"] + "</font>") self.data.setSubText("by <b>" + song["artist"] + "</b> from <b>" + song["album"] + "<b>") Plasma.ToolTipManager.self().setContent(self.applet, self.data) def genInfo(self): """Generate song info""" currentSong = client.currentsong() song = {"title": "", "artist": "", "album": "", "cover": ""} ## If tag "title" not exists, take file name try: song["title"] = currentSong["title"] except: song["title"] = currentSong["file"].split("/")[-1] try: song["artist"] = currentSong["artist"] except: song["artist"] = "N/A" try: song["album"] = currentSong["album"] except: song["album"] = "N/A" pathToCover = unicode(os.path.expanduser("~")) + "/.covers/" + song["artist"] + "-" + song["album"] + ".jpg" if os.path.exists(pathToCover): song["cover"] = pathToCover else: song["cover"] = unicode(self.package().path()) + "contents/icons/nocover.jpg" return song def reconnect(self): try: client.disconnect() except: pass try: client.connect(self._host, self._port) except: pass def togglePlayback(self): if self.isConnected(): if client.status()["state"] == "play": client.pause() else: client.play() def previous(self): if self.isConnected(): client.previous() def stop(self): if self.isConnected(): client.stop() def next(self): if self.isConnected(): client.next() def disconnect(self): client.disconnect() def changeIcon(self): if client.status()["state"] == "play": self.ppButton.setIcon(self.pauseIcon) else: self.ppButton.setIcon(self.playIcon) def setupOrientation(self, orientation): if orientation == "h": self.buttonsLayout = QGraphicsLinearLayout(Qt.Horizontal, self.applet) else: self.buttonsLayout = QGraphicsLinearLayout(Qt.Vertical, self.applet) def setupIcons(self, iconTheme): if iconTheme == "u": self.prevIcon = QIcon(unicode(self.package().path()) + "contents/icons/prev.png") self.playIcon = QIcon(unicode(self.package().path()) + "contents/icons/play.png") self.pauseIcon = QIcon(unicode(self.package().path()) + "contents/icons/pause.png") self.stopIcon = QIcon(unicode(self.package().path()) + "contents/icons/stop.png") self.nextIcon = QIcon(unicode(self.package().path()) + "contents/icons/next.png") self.connectIcon = QIcon(unicode(self.package().path()) + "contents/icons/connect.png") else: self.prevIcon = QIcon(KIcon("media-skip-backward")) self.playIcon = QIcon(KIcon("media-playback-start")) self.pauseIcon = QIcon(KIcon("media-playback-pause")) self.nextIcon = QIcon(KIcon("media-skip-forward")) self.stopIcon = QIcon(KIcon("media-playback-stop")) self.connectIcon = QIcon(KIcon("media-record")) def removeIntarface(self): self.buttonsLayout.removeItem(self.prevButton) self.prevButton.hide() self.buttonsLayout.removeItem(self.ppButton) self.ppButton.hide() self.buttonsLayout.removeItem(self.stopButton) self.stopButton.hide() self.buttonsLayout.removeItem(self.nextButton) self.nextButton.hide() try: self.buttonsLayout.removeItem(self.connectButton) self.connectButton.hide() except: pass del self.prevButton del self.ppButton del self.stopButton del self.nextButton del self.connectButton def addButtons(self): self.buttonsLayout.removeItem(self.connectButton) self.connectButton.hide() self.buttonsLayout.addItem(self.prevButton) self.prevButton.show() self.buttonsLayout.addItem(self.ppButton) self.ppButton.show() self.buttonsLayout.addItem(self.stopButton) if self._stop: self.stopButton.show() else: self.stopButton.hide() self.buttonsLayout.removeItem(self.stopButton) self.buttonsLayout.addItem(self.nextButton) self.nextButton.show() self.applet.adjustSize() def removeButtons(self): self.buttonsLayout.removeItem(self.prevButton) self.prevButton.hide() self.buttonsLayout.removeItem(self.ppButton) self.ppButton.hide() self.buttonsLayout.removeItem(self.stopButton) self.stopButton.hide() self.buttonsLayout.removeItem(self.nextButton) self.nextButton.hide() self.buttonsLayout.addItem(self.connectButton) self.connectButton.show() self.applet.adjustSize() def setupInterface(self, o, i): self.setupOrientation(o) self.setupIcons(i) # === Previous Button === self.prevButton = Plasma.IconWidget(self.prevIcon, "", self.applet) self.prevButton.setMaximumWidth(36) self.prevButton.setMaximumHeight(36) self.prevButton.setContentsMargins(0, 0, 0, 0) # === Play/Pause button === self.ppButton = Plasma.IconWidget( self.pauseIcon if self.isConnected() and client.status()["state"] == "play" else self.playIcon, "", self.applet, ) self.ppButton.setMaximumWidth(36) self.ppButton.setMaximumHeight(36) self.ppButton.setContentsMargins(0, 0, 0, 0) # === Stop Button === self.stopButton = Plasma.IconWidget(self.stopIcon, "", self.applet) self.stopButton.setMaximumWidth(36) self.stopButton.setMaximumHeight(36) self.stopButton.setContentsMargins(0, 0, 0, 0) # === Next Button === self.nextButton = Plasma.IconWidget(self.nextIcon, "", self.applet) self.nextButton.setMaximumWidth(36) self.nextButton.setMaximumHeight(36) self.nextButton.setContentsMargins(0, 0, 0, 0) # === ConnectButton === self.connectButton = Plasma.IconWidget(self.connectIcon, "", self.applet) self.connectButton.setMaximumWidth(36) self.connectButton.setMaximumHeight(36) self.connectButton.setContentsMargins(0, 0, 0, 0) if self.isConnected(): self.addButtons() else: self.removeButtons() QObject.connect(self.prevButton, SIGNAL("clicked()"), self.previous) QObject.connect(self.ppButton, SIGNAL("clicked()"), self.togglePlayback) QObject.connect(self.ppButton, SIGNAL("clicked()"), self.changeIcon) QObject.connect(self.stopButton, SIGNAL("clicked()"), self.stop) QObject.connect(self.stopButton, SIGNAL("clicked()"), self.changeIcon) QObject.connect(self.nextButton, SIGNAL("clicked()"), self.next) # QObject.connect(self.connectButton, SIGNAL("clicked()"), \ # self.addButtons) QObject.connect(self.connectButton, SIGNAL("clicked()"), self.reconnect) def isConnected(self): try: client.ping() return True except: return False def showVolumeDialog(self): self.volumeDialog.move(self.popupPosition(self.dialog.sizeHint())) if self.volumeDialog.isVisible(): self.volumeDialog.hide() else: self.volumeDialog.show() def checkConnect(self): if not self.isConnected(): self.removeButtons() self.reconnect() if self.isConnected(): ## Add playback buttons self.addButtons() def checkIcon(self): try: if client.status()["state"] == "play": self.ppButton.setIcon(self.pauseIcon) else: self.ppButton.setIcon(self.playIcon) except: pass