Ejemplo n.º 1
0
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
Ejemplo n.º 3
0
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