Пример #1
8
    def download(self, sql):
        apiUrl = "http://{}.cartodb.com/api/v2/sql?api_key={}&format=spatialite&q={}".format(
            self.cartodbUser, self.apiKey, sql
        )
        url = QUrl(apiUrl)
        request = self._getRequest(url)

        def finished(reply):
            tempdir = tempfile.tempdir
            if tempdir is None:
                tempdir = tempfile.mkdtemp()

            tf = tempfile.NamedTemporaryFile(delete=False)
            sqlite = QFile(tf.name)
            tf.close()
            if sqlite.open(QIODevice.WriteOnly):
                sqlite.write(reply.readAll())
                sqlite.close()
                self.fetchContent.emit(tf.name)
            else:
                self.error.emit("Error saving downloaded file")

        manager = QNetworkAccessManager()
        manager.finished.connect(finished)

        reply = manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()
Пример #2
0
class FileCopier(QObject):
    """
    Copies files from network
    """

    finished = pyqtSignal()

    def __init__(self, file):
        super(FileCopier, self).__init__()
        self.file = QUrl("file:///{}".format(file))
        self.manager = QNetworkAccessManager(self)
        self.connect(self.manager, SIGNAL("finished(QNetworkReply*)"),
                     self.reply_finished)

    def reply_finished(self, reply):
        checkout_class = CheckoutStatusWindow()
        self.connect(reply, SIGNAL("downloadProgress(int, int)"),
                     checkout_class.update_progress_bar)
        self.reply = reply
        checkout_class.progressBar.setMaximum(reply.size())

    def run(self):
        """
        Start the download
        :return: None
        """
        self.manager.get(QNetworkRequest(self.file))
        self.finished.emit()
Пример #3
0
class VersionChecker(QObject):

    def getRequestUrl(self, uuid, use_stats):

        base_url = "http://comictagger1.appspot.com/latest"
        args = ""

        if use_stats:
            if platform.system() == "Windows":
                plat = "win"
            elif platform.system() == "Linux":
                plat = "lin"
            elif platform.system() == "Darwin":
                plat = "mac"
            else:
                plat = "other"
            args = "?uuid={0}&platform={1}&version={2}".format(
                uuid, plat, ctversion.version)
            if not getattr(sys, 'frozen', None):
                args += "&src=T"

        return base_url + args

    def getLatestVersion(self, uuid, use_stats=True):

        try:
            resp = urllib2.urlopen(self.getRequestUrl(uuid, use_stats))
            new_version = resp.read()
        except Exception as e:
            return None

        if new_version is None or new_version == "":
            return None
        return new_version.strip()

    versionRequestComplete = pyqtSignal(str)

    def asyncGetLatestVersion(self, uuid, use_stats):

        url = self.getRequestUrl(uuid, use_stats)

        self.nam = QNetworkAccessManager()
        self.nam.finished.connect(self.asyncGetLatestVersionComplete)
        self.nam.get(QNetworkRequest(QUrl(str(url))))

    def asyncGetLatestVersionComplete(self, reply):
        if (reply.error() != QNetworkReply.NoError):
            return

        # read in the response
        new_version = str(reply.readAll())

        if new_version is None or new_version == "":
            return

        self.versionRequestComplete.emit(new_version.strip())
Пример #4
0
class VersionChecker(QObject):
    def getRequestUrl(self, uuid, use_stats):

        base_url = "http://comictagger1.appspot.com/latest"
        args = ""

        if use_stats:
            if platform.system() == "Windows":
                plat = "win"
            elif platform.system() == "Linux":
                plat = "lin"
            elif platform.system() == "Darwin":
                plat = "mac"
            else:
                plat = "other"
            args = "?uuid={0}&platform={1}&version={2}".format(
                uuid, plat, ctversion.version)
            if not getattr(sys, 'frozen', None):
                args += "&src=T"

        return base_url + args

    def getLatestVersion(self, uuid, use_stats=True):

        try:
            resp = urllib2.urlopen(self.getRequestUrl(uuid, use_stats))
            new_version = resp.read()
        except Exception as e:
            return None

        if new_version is None or new_version == "":
            return None
        return new_version.strip()

    versionRequestComplete = pyqtSignal(str)

    def asyncGetLatestVersion(self, uuid, use_stats):

        url = self.getRequestUrl(uuid, use_stats)

        self.nam = QNetworkAccessManager()
        self.nam.finished.connect(self.asyncGetLatestVersionComplete)
        self.nam.get(QNetworkRequest(QUrl(str(url))))

    def asyncGetLatestVersionComplete(self, reply):
        if (reply.error() != QNetworkReply.NoError):
            return

        # read in the response
        new_version = str(reply.readAll())

        if new_version is None or new_version == "":
            return

        self.versionRequestComplete.emit(new_version.strip())
Пример #5
0
class URLLabel(QLabel):
    """ QLabel subclass to support the display of images via URL.
    
    """

    def __init__(self, parent):
        super(URLLabel, self).__init__(parent)
        self.connection = None
        self._original_pixmap = None
        self.connection = None

    def clear(self):
        self._original_pixmap = None
        super(URLLabel, self).clear()

    def setRemotePixmap(self, url):
        # Lazy creation of QNetworkManager, image download is asynchronous.
        # When the image download is complete (ie the "finished" signal),
        # the image data is read and drawn.
        if self.connection is None:
            self.connection = QNetworkAccessManager(self)
            self.connection.finished.connect(self.pixmapReceived)
        self.connection.get(QNetworkRequest(QUrl(url)))

    def pixmapReceived(self, reply):
        """ Slot for handling the return of the asynchronous image download. """
        if reply.error() != QNetworkReply.NoError:
            reply.deleteLater()
            return

        data = reply.readAll()
        pixmap = QPixmap()
        pixmap.loadFromData(data)
        # The original image is stored as an attribute and drawn manually
        # using an overridden paintEvent.  This is preferable to using the
        # setPixmap() functionality of QLabels because it allows more control
        # over the scaling of the pixmap and allows the size of the QLabel
        # to dictate the pixmap size, and not the other way around.
        self._original_pixmap = pixmap
        reply.deleteLater()
        self.update()

    def paintEvent(self, paintevent):
        super(URLLabel, self).paintEvent(paintevent)
        # Manually draw the downloaded pixmap, scaled to fit the size of the label.
        if self._original_pixmap:
            size = self.size()
            sized_pixmap = self._original_pixmap.scaled(size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            painter = QPainter(self)
            point = self.geometry().topLeft()
            painter.drawPixmap(point, sized_pixmap)
Пример #6
0
class SettingsProtocol(QObject):

    readSignal = pyqtSignal(bool, int, QString)

    def __init__(self, host, user, password):
        QObject.__init__(self)

        # Set the host
        self.host = host
        # Create a base64 encoded credential string from user name and password.
        # This is required for the HTTP basic access authentication, compare
        # also http://en.wikipedia.org/wiki/Basic_access_authentication
        self.userlogin = "******" % (user, password)
        self.login = "******" + QByteArray(self.userlogin).toBase64()

        # Create a new QNetworkAccessManager and connect it to the
        # authenticationRequired signal
        self.manager = QNetworkAccessManager(self)
        # self.connect(self.manager, SIGNAL("authenticationRequired( QNetworkReply*, QAuthenticator* )"), self.slotAuthenticationRequired)

    def read(self):
        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        url = "%s/config/geometrytaggroups" % self.host

        qUrl = QUrl(url)
        self.request = QNetworkRequest(qUrl)
        self.request.setRawHeader("Authorization", self.login)

        self.request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")

        self.manager.get(self.request)

        return url

    def readRequestFinished(self, reply):
        # Get the HTTP status code from the reply
        self.httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        data = reply.readAll()

        # Check the status code see also http://en.wikipedia.org/wiki/HTTP_status_code
        # In case of a successful upload we get a 201 status code back and the
        # "stylePosted" signal is emitted with the first parameter set to True.
        # If the query didn't succeed, the status code is 4xx indicating that
        # the host was not found, the authentication failed or a forbidden
        # action in case a style with the same name already exists. It's up to
        # the receiver to handle these status codes.
        self.readSignal.emit(self.httpStatusCode in (200, 201), self.httpStatusCode, QString(data))
Пример #7
0
    def cbUserData(self, data):
        if 'error' in data:
            # TODO Create image for error
            self.nameLB.setText(
                "<html><head/><body><p><span style=\" text-decoration: underline; color:red;\">error</span></p></body></html>"
            )
            self.error.emit(data['error'])
            return

        self.currentUserData = data
        self.settings.setValue('/CartoDBPlugin/selected', self.currentUser)
        manager = QNetworkAccessManager()
        manager.finished.connect(self.returnAvatar)

        if 's3.amazonaws.com' in data['avatar_url']:
            imageUrl = QUrl(data['avatar_url'])
        else:
            imageUrl = QUrl('http:' + data['avatar_url'])

        request = QNetworkRequest(imageUrl)
        request.setRawHeader('User-Agent', 'QGIS 2.x')
        reply = manager.get(request)
        loop = QEventLoop()
        reply.finished.connect(loop.exit)
        loop.exec_()
Пример #8
0
 def download(self, url, outfd=None):
     """
     Download a given URL using current cookies.
     
     @param url: URL or path to download
     @param outfd: Output file-like stream. If None, return data string.
     @return: Bytes downloaded (None if something went wrong)
     @note: If url is a path, the current base URL will be pre-appended.        
     """
     def _on_reply(reply):
         url = unicode(reply.url().toString())
         self._download_reply_status = not bool(reply.error())
     self._download_reply_status = None
     if not urlparse.urlsplit(url).scheme:
         url = urlparse.urljoin(self.url, url) 
     request = QNetworkRequest(QUrl(url))
     # Create a new manager to process this download        
     manager = QNetworkAccessManager()
     reply = manager.get(request)
     if reply.error():
         raise SpynnerError("Download error: %s" % reply.errorString())
     reply.downloaded_nbytes = 0
     manager.setCookieJar(self.manager.cookieJar())
     manager.connect(manager, SIGNAL('finished(QNetworkReply *)'), _on_reply)
     outfd_set = bool(outfd)
     if not outfd_set:
         outfd = StringIO()            
     self._start_download(reply, outfd)
     while self._download_reply_status is None:
         self._events_loop()
     if outfd_set:
         return (reply.downloaded_nbytes if not reply.error() else None)
     else:
         return outfd.getvalue()  
Пример #9
0
    def download(self, sql):
        apiUrl = 'http://{}.{}/api/v2/sql?api_key={}&format=spatialite&q={}'.format(
            self.cartodbUser, self.hostname, self.apiKey, sql)
        url = QUrl(apiUrl)
        request = self._getRequest(url)

        def finished(reply):
            tempdir = tempfile.tempdir
            if tempdir is None:
                tempdir = tempfile.mkdtemp()

            tf = tempfile.NamedTemporaryFile(delete=False)
            sqlite = QFile(tf.name)
            tf.close()
            if (sqlite.open(QIODevice.WriteOnly)):
                sqlite.write(reply.readAll())
                sqlite.close()
                self.fetchContent.emit(tf.name)
            else:
                self.error.emit('Error saving downloaded file')

        manager = QNetworkAccessManager()
        manager.finished.connect(finished)

        reply = manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()
Пример #10
0
class FileDownloader(QObject):
    def __init__(self, url, parent=None):
        QObject.__init__(self, parent)
        self.manager = QNetworkAccessManager()
        self._downloadedData = QByteArray()
        self.connect(self.manager, SIGNAL("finished(QNetworkReply*)"),
                     self.fileDownloaded)

        request = QNetworkRequest(url)
        reply = self.manager.get(request)
        loop = QEventLoop()
        self.connect(reply, SIGNAL('finished()'), loop, SLOT('quit()'))
        loop.exec()
        #reply.finished.connect(self.fileDownloaded, reply)
        #self._downloadedData = reply.readAll()
        #print(self._downloadedData)

    def quit(self):
        print('QUIT')

    def fileDownloaded(self, reply):
        #print('fileDownloaded')
        self._downloadedData = reply.readAll()
        # emit a signal
        #print(self._downloadedData)
        reply.deleteLater()
        self.emit(SIGNAL("downloaded()"))

    def downloadedData(self):
        return self._downloadedData
Пример #11
0
class Test:

    def __init__(self):

        request = QNetworkRequest(QUrl("http://www.riverbankcomputing.co.uk/news"))
        self.manager = QNetworkAccessManager()
        self.manager.finished.connect(self.handleReply)



        self.manager.get(request)

    def handleReply(self, reply):
	print reply.readAll()
        print reply.error()
        QCoreApplication.quit()
    def prepareInstallNanoCopy(self):
        #self.logMessage("installing")
        self.target="/instalador/nano"
        self.copying=True
        self.ui.WButons_2.setVisible(False)
        
        self.movieGreyIcon=QMovie(self.ui.icon_waitGrey)

        
        wantFormat=0
        if self.ui.CHFormatNano.isChecked():
            wantFormat=1
                
        # for pipe commands use idCommand="/bin/bash" idParam="-c" idParam2="shell | piped command"
        arch=str(self.execShellProcess("uname", "-m").replace("\n","").replace("b",""))[1:]
        mem=str(self.execShellProcess("/bin/bash", "-c", "cat /proc/meminfo  | grep MemTotal | awk ' { print $2 } '").replace("\n","").replace("b",""))[1:]
        persistentFilePath=str(self.target+"/persistent_/"+arch)
        if self.ui.CHChangesFile.isChecked():
            persistentFileSize=str(self.realChangeFileSize).split(".")[0]
        else:
            persistentFileSize=0
            
        self.installNanoKademarProcess=installNanoKademarProcess(self.target, self.selectedDeviceToInstall[0], wantFormat, self.pathInstaller, self.kademarType, persistentFilePath,persistentFileSize, self.totalSizeOfKademar)
        # FUNCIO COPIA
        self.connect(self.installNanoKademarProcess, SIGNAL("formated"), self.nanoEndedFormat)
        self.connect(self.installNanoKademarProcess, SIGNAL("endedCopy"), self.nanoEndedCopyProcess)
        self.connect(self.installNanoKademarProcess, SIGNAL("persistentFileCreated"), self.persistentFileCreated)
        self.connect(self.installNanoKademarProcess, SIGNAL("bootManagerInstalled"), self.bootManagerInstalled)
        #self.connect(self.installNanoKademarProcess, SIGNAL("progress"), self.updateProgressBar)
        
        if wantFormat:
            self.logMessage("Formating")
        self.installNanoKademarProcess.start()
        self.ui.iDisk.setPixmap(QPixmap(self.icon_greenTick))
        
        self.movieGreyIcon.start()
        self.ui.iFormating.setMovie(self.movieGreyIcon)

        #Statistics
        if self.internet:        
            from  PyQt4.QtNetwork import QNetworkRequest,QNetworkAccessManager
            nwam = QNetworkAccessManager()
            request = QNetworkRequest (QUrl("http://www.kademar.org/UserCounter/count.php?login=&pc=&type=usb&kademar="+self.kademarType+"&arch="+arch+"&mem="+mem))
            nwam.get(request)
Пример #13
0
 def run(self):
     loop = QtCore.QEventLoop()
     nm = QNetworkAccessManager()
     reply = nm.get(QNetworkRequest(self.url))
     reply.finished.connect(loop.quit)
     loop.exec_()
     data = reply.readAll()
     self.resourceLoaded.emit(self.res_type, self.url, data)
     reply.deleteLater()
     nm.deleteLater()
Пример #14
0
class Notifier(QThread):

    SERVER_URL = "http://127.0.0.1:6543"

    def __init__(self):
        QThread.__init__(self)

        # logging instance
        self.log = logging.getLogger('GDAIS.Notifier')

        # Network manager to send notifications
        self.manager = QNetworkAccessManager()
        self.manager.finished.connect(self._reply_finished)

        # Name of the equipment to notify (needs to be initialized before calling notify)
        self.equipment = ''

        # flag for when quit command is received
        self.exiting = False

    def quit(self):
        loop = QEventLoop()
        reply = self._make_request('quit')
        reply.finished.connect(loop.quit)
        loop.exec_()

        QThread.quit(self)

    def notify(self, event):
        self._make_request(event)

    def _make_request(self, event):
        url = QUrl("{0}/notify_{1}/{2}".format(self.SERVER_URL, event,
                                               self.equipment))
        self.log.debug("Sending notification for '{0}' event to {1}".format(
            event, url.toString()))
        reply = self.manager.get(QNetworkRequest(url))
        reply.error.connect(self._reply_error)
        return reply

    def _reply_finished(self, network_reply):
        self.log.debug("Reply received: {0}".format(network_reply.readAll()))

    def _reply_error(self, network_error):
        # TODO check if it is really an error
        self.log.error("Error receiving reply: {0}".format(network_error))
 def __tryAgain(self):
     """
     Private slot to retry the download.
     """
     self.__tryAgainButton.setEnabled(False)
     self.__closeButton.setEnabled(False)
     self.__stopButton.setEnabled(True)
     
     if self.__page:
         nam = self.__page.networkAccessManager()
     else:
         nam = QNetworkAccessManager()
     reply = nam.get(QNetworkRequest(self.__url))
     if self.__output.exists():
         self.__output.remove()
     self.__reply = reply
     self.initialize()
Пример #16
0
class InfoBagDialog(QDialog, Ui_Info):
    def __init__(self, gebouwnummer, iface, parent=None):
        super(InfoBagDialog, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle('BAG adressen')
        self.label.setText('Pand bevat de volgende adressen')

        self.actionButtonBox.button(QtGui.QDialogButtonBox.Close).setText("Sluiten")

        self.basewfs = "http://geo.zaanstad.nl/geoserver/wfs?request=GetFeature&version=2.0.0&outputFormat=JSON"
        self.iface = iface
        self.manager = QNetworkAccessManager(self)
        self.gebouwnummer = gebouwnummer
        self.getInfo(self.gebouwnummer)
        self.exec_()

    def getInfo(self, gebouwnummer):
        qurl = QUrl.fromUserInput(self.basewfs)
        qurl.addQueryItem('typeName', 'geo:bag_verblijfsobject')
        qurl.addQueryItem('filter', "<PropertyIsEqualTo><PropertyName>gebouwnummer</PropertyName><Literal>" + unicode(gebouwnummer) + "</Literal></PropertyIsEqualTo>")
        request = QNetworkRequest(qurl)
        reply = self.manager.get(request)
        reply.finished.connect(self.handleInfo)

    def handleInfo(self):
        reply = self.sender()
        error = reply.error()
        if error != QNetworkReply.NoError:
            self.iface.messageBar().pushMessage(reply.errorString(), level=QgsMessageBar.WARNING)
            reply.deleteLater()
            reply = None
        else:
            response_text = reply.readAll().data()
            data = json.loads(response_text)
            count = data['totalFeatures']
            self.tableWidget.clear()
            self.tableWidget.setColumnCount(1);
            self.tableWidget.setRowCount(count);
            features = data['features']
            for idx, feature in enumerate(features):
                text = QTableWidgetItem(feature['properties']['adres'] + ", " + feature['properties']['postcode'] + " (" + feature['properties']['gebruik'] + ")")
                self.tableWidget.setItem(idx,0,text)

            self.tableWidget.resizeColumnToContents(0)
Пример #17
0
    def test_access_without_credentials(self):
        loop = QEventLoop()
        proxy = get_network_proxy()
        manager = QNetworkAccessManager()

        manager.setProxy(proxy)
        manager.finished.connect(loop.exit)

        reply = manager.get(QNetworkRequest(QUrl('http://aws.amazon.com/')))
        loop.exec_(flags=QEventLoop.ExcludeUserInputEvents)

        if reply.isFinished():
            self.assertEquals(self.server.log.getvalue(),
                '407 Proxy Authentication Required\n\n')
        else:
            if reply.isRunning():
                self.failUnless(False, msg='The request has timed out.')
            else:
                self.failUnless(False, msg='A Network error occurred.')
Пример #18
0
    def test_access_without_credentials(self):
        loop = QEventLoop()
        proxy = get_network_proxy()
        manager = QNetworkAccessManager()

        manager.setProxy(proxy)
        manager.finished.connect(loop.exit)

        reply = manager.get(QNetworkRequest(QUrl('http://aws.amazon.com/')))
        loop.exec_(flags=QEventLoop.ExcludeUserInputEvents)

        if reply.isFinished():
            self.assertEquals(self.server.log.getvalue(),
                              '407 Proxy Authentication Required\n\n')
        else:
            if reply.isRunning():
                self.failUnless(False, msg='The request has timed out.')
            else:
                self.failUnless(False, msg='A Network error occurred.')
Пример #19
0
    def _request(self, url):
        ''' Request data from url
        @type url: str
        @rtype: QByteArray
        '''
        
        nam = QNetworkAccessManager()
        reply = nam.get(QNetworkRequest(QUrl(url)))
                
        loop = QEventLoop()
        QObject.connect(reply, SIGNAL('finished()'), loop, SLOT('quit()'))
        loop.exec_()
        
        redirect = reply.attribute(QNetworkRequest.RedirectionTargetAttribute)
        
        # Follow redirects
        if redirect.type() == QVariant.Url:
            return self._request(unicode(redirect.toUrl().resolved(QUrl('')).toString()))

        return reply.readAll()
Пример #20
0
    def cbUserData(self, data):
        self.currentUserData = data

        if self.toolbar.avatarImage is None:
            manager = QNetworkAccessManager()
            manager.finished.connect(self.returnAvatar)

            if 's3.amazonaws.com' in data['avatar_url']:
                imageUrl = QUrl(data['avatar_url'])
            else:
                imageUrl = QUrl('http:' + data['avatar_url'])

            request = QNetworkRequest(imageUrl)
            request.setRawHeader('User-Agent', 'QGIS 2.x')
            reply = manager.get(request)
            loop = QEventLoop()
            reply.finished.connect(loop.exit)
            loop.exec_()

        self.setUpUserData()
Пример #21
0
class Formaa(QObject):
  def __init__(self, parent=None):
      print "init"

  def proccess_finished(self, reply):
      print reply.header(QNetworkRequest.ContentTypeHeader).toString()
      QCoreApplication.quit()

  def readyRead(self, bytesReceived, bytesTotal):
      d = bytesReceived*100/bytesTotal
      print "bytesReceived: "+ str(d) + " bytesTotal: "+ str(bytesTotal) 

  def download(self):
      self.manager = QNetworkAccessManager() 

      QObject.connect(self.manager, SIGNAL("finished(QNetworkReply *)"),self.proccess_finished)
      self.request = QNetworkRequest(QUrl("http://hearablog.com/sites/a-smart-bear/post/taking-fail-fast-to-a-whole-nutha-level.mp3"))
      #self.request = QNetworkRequest(QUrl("http://www.google.com/"))
      self.request.setRawHeader('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US)')
      self.reply = self.manager.get(self.request)
      self.reply.downloadProgress.connect(self.readyRead)
Пример #22
0
    def _fetch_inventory(self, url):
        cache_dir = config.cache_dir()
        cache_dir = os.path.join(cache_dir, "help", type(self).__qualname__)

        try:
            os.makedirs(cache_dir)
        except OSError:
            pass

        url = QUrl(self.inventory)
        if not url.isLocalFile():
            # fetch and cache the inventory file.
            manager = QNetworkAccessManager(self)
            cache = QNetworkDiskCache()
            cache.setCacheDirectory(cache_dir)
            manager.setCache(cache)
            req = QNetworkRequest(url)

            self._reply = manager.get(req)
            manager.finished.connect(self._on_finished)
        else:
            self._load_inventory(open(str(url.toLocalFile()), "rb"))
Пример #23
0
    def cbUserData(self, data):
        if 'error' in data:
            # TODO Create image for error
            self.nameLB.setText("<html><head/><body><p><span style=\" text-decoration: underline; color:red;\">error</span></p></body></html>")
            self.error.emit(data['error'])
            return

        self.currentUserData = data
        self.settings.setValue('/CartoDBPlugin/selected', self.currentUser)
        manager = QNetworkAccessManager()
        manager.finished.connect(self.returnAvatar)

        if 's3.amazonaws.com' in data['avatar_url']:
            imageUrl = QUrl(data['avatar_url'])
        else:
            imageUrl = QUrl('http:' + data['avatar_url'])

        request = QNetworkRequest(imageUrl)
        request.setRawHeader('User-Agent', 'QGIS 2.x')
        reply = manager.get(request)
        loop = QEventLoop()
        reply.finished.connect(loop.exit)
        loop.exec_()
Пример #24
0
    def test_access_to_remote_succeeded(self):
        loop = QEventLoop()
        proxy = get_network_proxy()
        proxy.setUser(self.server.username)
        proxy.setPassword(self.server.password)
        manager = QNetworkAccessManager()

        manager.setProxy(proxy)
        manager.finished.connect(loop.exit)

        reply = manager.get(QNetworkRequest(QUrl('http://aws.amazon.com/')))
        loop.exec_(flags=QEventLoop.ExcludeUserInputEvents)

        if reply.isFinished():
            response_code = reply.attribute(
                QNetworkRequest.HttpStatusCodeAttribute).toString()
            self.assertEquals(response_code, '200')
            self.assertEquals(reply.url(), QUrl('http://aws.amazon.com/'))
        else:
            if reply.isRunning():
                self.failUnless(False, msg='The request has timed out.')
            else:
                self.failUnless(False, msg='A Network error occurred.')
    def _fetch_inventory(self):
        cache_dir = config.cache_dir()
        cache_dir = os.path.join(cache_dir, "help", "intersphinx")

        try:
            os.makedirs(cache_dir)
        except OSError:
            pass

        url = QUrl(self.inventory)

        if not self.islocal:
            # fetch and cache the inventory file
            manager = QNetworkAccessManager(self)
            cache = QNetworkDiskCache()
            cache.setCacheDirectory(cache_dir)
            manager.setCache(cache)
            req = QNetworkRequest(url)

            self._reply = manager.get(req)
            manager.finished.connect(self._on_finished)
        else:
            self._load_inventory(open(unicode(url.toLocalFile()), "rb"))
Пример #26
0
    def test_access_to_remote_succeeded(self):
        loop = QEventLoop()
        proxy = get_network_proxy()
        proxy.setUser(self.server.username)
        proxy.setPassword(self.server.password)
        manager = QNetworkAccessManager()

        manager.setProxy(proxy)
        manager.finished.connect(loop.exit)

        reply = manager.get(QNetworkRequest(QUrl('http://aws.amazon.com/')))
        loop.exec_(flags=QEventLoop.ExcludeUserInputEvents)

        if reply.isFinished():
            response_code = reply.attribute(
                QNetworkRequest.HttpStatusCodeAttribute).toString()
            self.assertEquals(response_code, '200')
            self.assertEquals(reply.url(), QUrl('http://aws.amazon.com/'))
        else:
            if reply.isRunning():
                self.failUnless(False, msg='The request has timed out.')
            else:
                self.failUnless(False, msg='A Network error occurred.')
Пример #27
0
    def _fetch_inventory(self):
        cache_dir = config.cache_dir()
        cache_dir = os.path.join(cache_dir, "help", "intersphinx")

        try:
            os.makedirs(cache_dir)
        except OSError:
            pass

        url = QUrl(self.inventory)

        if not self.islocal:
            # fetch and cache the inventory file
            manager = QNetworkAccessManager(self)
            cache = QNetworkDiskCache()
            cache.setCacheDirectory(cache_dir)
            manager.setCache(cache)
            req = QNetworkRequest(url)

            self._reply = manager.get(req)
            manager.finished.connect(self._on_finished)
        else:
            self._load_inventory(open(unicode(url.toLocalFile()), "rb"))
Пример #28
0
class BagadresString(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.basewfs = "http://geo.zaanstad.nl/geoserver/wfs?request=GetFeature&version=2.0.0&outputFormat=JSON"
        self.manager = QNetworkAccessManager(self)
        self.timer = QTimer()
        self.loop = QEventLoop()
        self.reply = None
        
    def request(self, gebouwnummer):
        qurl = QUrl.fromUserInput(self.basewfs)
        qurl.addQueryItem('typeName', 'geo:bag_verblijfsobject')
        qurl.addQueryItem('filter', "<PropertyIsEqualTo><PropertyName>gebouwnummer</PropertyName><Literal>" + unicode(gebouwnummer) + "</Literal></PropertyIsEqualTo>")
        request = QNetworkRequest(qurl)
        
        self.reply = self.manager.get(request)
        self.reply.finished.connect(self.loop.quit)

        self.timer.start(5000)
        self.loop.exec_()

        if self.timer.isActive():
            self.timer.stop()
            r = self.handleReply()
        else:
            raise Exception("Timeout error.")

        return r

    def handleReply(self):
        reply = self.reply
        response_text = reply.readAll().data()
        data = json.loads(response_text)
        feature = data['features'][0]
        reply.deleteLater()
        return feature['properties']['adres'] + " (" + feature['properties']['gebruik'] + ")"
Пример #29
0
    def download(self, url, outfd=None):
        """
        Download a given URL using current cookies.
        
        @param url: URL or path to download
        @param outfd: Output file-like stream. If None, return data string.
        @return: Bytes downloaded (None if something went wrong)
        @note: If url is a path, the current base URL will be pre-appended.        
        """
        def _on_reply(reply):
            url = unicode(reply.url().toString())
            self._download_reply_status = not bool(reply.error())

        self._download_reply_status = None
        if not urlparse.urlsplit(url).scheme:
            url = urlparse.urljoin(self.url, url)
        request = QNetworkRequest(QUrl(url))
        # Create a new manager to process this download
        manager = QNetworkAccessManager()
        reply = manager.get(request)
        if reply.error():
            raise SpynnerError("Download error: %s" % reply.errorString())
        reply.downloaded_nbytes = 0
        manager.setCookieJar(self.manager.cookieJar())
        manager.connect(manager, SIGNAL('finished(QNetworkReply *)'),
                        _on_reply)
        outfd_set = bool(outfd)
        if not outfd_set:
            outfd = StringIO()
        self._start_download(reply, outfd)
        while self._download_reply_status is None:
            self._events_loop()
        if outfd_set:
            return (reply.downloaded_nbytes if not reply.error() else None)
        else:
            return outfd.getvalue()
Пример #30
0
class Browser(QApplication):
    """The browser application that comprises a parser, interpreter, renderer,
    and other core components of a browser.
    """

    APPLICATION_NAME = 'Internet Exploder 164'

    def __init__(self, tmlParser, cs164Parser, interpreter, renderer):
        QApplication.__init__(self, [Browser.APPLICATION_NAME])
        self.tmlParser = tmlParser
        self.cs164Parser = cs164Parser
        self.interpreter = interpreter
        self.renderer = renderer
        self.network = QNetworkAccessManager(self)

        self.window = Window()
        self.window.resize(610, 410)
        self.window.center()
        self.window.show()

        self.timers = {}
        self.networkReplies = []

        self.focused = None

    def load(self, url):
        self.reset(self.window)
        connection = urlopen(url)
        try:
            dom = self.tmlParser.parse(connection.read())
            self.renderer.render(dom, self.window.canvas)
        finally:
            connection.close()

    def createTimer(self):
        timer = QTimer()
        timer.start()
        self.timers[timer.timerId()] = timer
        print >> sys.stderr, 'Created new timer with ID', timer.timerId()
        return timer

    def createNetworkReply(self, uri):
        url = QUrl(uri, QUrl.TolerantMode)
        request = QNetworkRequest(url)
        reply = self.network.get(request)
        self.networkReplies.append(reply)
        return reply

    def setFocus(self, node):
        node['__qt'].setFocus()

    def clear(self, window):
        self.renderer.clear(window.canvas)

    def reset(self, window):
        self.clear(window)

        # Clear all of the timers.
        for timerId, timer in self.timers.items():
            timer.stop()
            timer.timeout.disconnect()
        self.timers = {}

        # Close up all HTTP connections.
        for reply in self.networkReplies:
            reply.finished.disconnect()
            reply.abort()
        self.networkReplies = []

    def relayout(self):
        self.execFun('relayout')

    def execScript(self, code, env={}):
        ast = self.cs164Parser.parse(code)
        self.interpreter.ExecGlobal(ast, env.copy())

    def execFun(self, funName):
        self.interpreter.ExecFun(self.interpreter.globEnv[funName], [])

    @staticmethod
    def run():
        """Launches the browser and returns its exit status code when
        closed. This method may never return; for example, if the OS
        immediately shuts down, further code may never run.
        """
        # TODO: Perhaps run this in another thread.
        return QApplication.exec_()
Пример #31
0
class RestRequest(QObject):

    restApiUrl = ''  #

    done = pyqtSignal(dict, name='done')

    def __init__(self, url, parentWindow, done, params=None):  # parent not used
        super(RestRequest, self).__init__()
        # private
        self._manager = QNetworkAccessManager()
        if params is not None:
            url += '?' + '&'.join('{}={}'.format(k, urllib.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems())

        self.url = QUrl(RestRequest.restApiUrl + url)

        # connect asynchronous result, when a request finishes
        self._manager.finished.connect(self._finished)
        self._manager.sslErrors.connect(self._sslError)
        self._parentWindow = parentWindow

        self.done.connect(done, Qt.QueuedConnection)

    # private slot, no need to declare as slot
    @pyqtSlot(QNetworkReply)
    def _finished(self, reply):
        '''
        Handle signal 'finished'.  A network request has finished.
        '''
        try:
            if reply.error() != QNetworkReply.NoError:
                raise Exception(reply.errorString())
            data = six.text_type(reply.readAll())
            data = json.loads(data)
        except Exception as e:
            data = {
                'result': None,
                'error': six.text_type(e)
            }

        self.done.emit(data)

        reply.deleteLater()  # schedule for delete from main event loop

    @pyqtSlot(QNetworkReply, list)
    def _sslError(self, reply, errors):
        settings = QSettings()
        settings.beginGroup('ssl')
        cert = errors[0].certificate()
        digest = six.text_type(cert.digest().toHex())

        approved = settings.value(digest, False).toBool()

        errorString = '<p>The certificate for <b>{}</b> has the following errors:</p><ul>'.format(cert.subjectInfo(QSslCertificate.CommonName))

        for err in errors:
            errorString += '<li>' + err.errorString() + '</li>'

        errorString += '</ul>'

        if approved or QMessageBox.warning(self._parentWindow, 'SSL Warning', errorString, QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            settings.setValue(digest, True)
            reply.ignoreSslErrors()

        settings.endGroup()

    def get(self):
        request = QNetworkRequest(self.url)
        request.setRawHeader('User-Agent', osDetector.getOs() + " - UDS Connector " + VERSION)
        self._manager.get(request)
Пример #32
0
class Nominatim(object):
    """Manage connexion to Nominatim."""

    def __init__(self,
                 url="http://nominatim.openstreetmap.org/search?format=json"):
        """
        Constructor
        @param url:URL of Nominatim
        @type url:str
        """

        self.__url = url
        self.network = QNetworkAccessManager()
        self.data = None
        self.network_reply = None
        self.loop = None

    def query(self, query):
        """
        Perform a nominatim query

        @param query: Query to execute
        @type query: str

        @raise NetWorkErrorException

        @return: the result of the query
        @rtype: str
        """

        url_query = QUrl(self.__url)

        query = QUrl.toPercentEncoding(query)
        url_query.addEncodedQueryItem('q', query)
        url_query.addQueryItem('info', 'QgisQuickOSMPlugin')
        url_query.setPort(80)

        proxy = get_proxy()
        if proxy:
            self.network.setProxy(proxy)

        request = QNetworkRequest(url_query)
        request.setRawHeader("User-Agent", "QuickOSM")
        self.network_reply = self.network.get(request)
        self.loop = QEventLoop()
        self.network.finished.connect(self._end_of_request)
        self.loop.exec_()

        if self.network_reply.error() == QNetworkReply.NoError:
            return json.loads(self.data)
        else:
            raise NetWorkErrorException(suffix="Nominatim API")

    def _end_of_request(self):
        self.data = self.network_reply.readAll().data().decode('utf-8')
        self.loop.quit()

    def get_first_polygon_from_query(self, query):
        """
        Get first OSM_ID of a Nominatim area

        @param query: Query to execute
        @type query: str

        @raise NominatimAreaException:

        @return: First relation's osm_id
        @rtype: str
        """
        data = self.query(query)
        for result in data:
            if result['osm_type'] == "relation":
                return result['osm_id']

        # If no result has been return
        raise NominatimAreaException

    def get_first_point_from_query(self, query):
        """
        Get first longitude, latitude of a Nominatim point

        @param query: Query to execute
        @type query: str

        @raise NominatimAreaException:

        @return: First relation's osm_id
        @rtype: str
        """
        data = self.query(query)
        for result in data:
            if result['osm_type'] == "node":
                return result['lon'], result['lat']

        # If no result has been return
        raise NominatimAreaException
Пример #33
0
class StravaUpload(QObject):

    LOGIN = '******'
    ATHLETES_SHOW = 'http://www.strava.com/api/v2/athletes/{id}'
    UPLOAD = 'http://www.strava.com/api/v2/upload'
    UPLOAD_STATUS = 'http://www.strava.com/api/v2/upload/status/{id}'


    statusMessage = pyqtSignal(str)
    totalProgress = pyqtSignal(int)
    itemProgress = pyqtSignal(int)
    authNeeded = pyqtSignal()
    finished = pyqtSignal()


    def __init__(self, tracks, auth_token=None, device_info=None, parent=None):
        super(StravaUpload, self).__init__(parent)
        self.device_info = device_info
        self.auth_token = auth_token

        self.tracks = tracks[:]
        self.current_track = None
        self.results = []
        self.progress = 0
        self.upload_id = None
        self._aborted = False
        self.reply = None

        self.network_manager = QNetworkAccessManager(self)


    def start(self):

        self._doAuthenticate()

    def cancel(self):
        self._aborted = True
        if self.reply is not None:
            self.reply.abort()


    def authenticate(self, username, password):

        log.debug('Sending auth request')
        req = QNetworkRequest(QUrl(self.LOGIN))
        req.setHeader(QNetworkRequest.ContentTypeHeader,
                "application/x-www-form-urlencoded")

        self.reply = self.network_manager.post(req, urllib.urlencode({
            'email' : username,
            'password' : password,
            }))

        self.reply.finished.connect(self._onAuthenticated)


    def _emitProgress(self, msg, value):
        self.progressString.emit(msg)
        self.progress.emit(value)

    def _doAuthenticate(self):

        self.statusMessage.emit('Authenticating')

        if self.auth_token is None:
            log.debug('Auth needed')
            self.authNeeded.emit()
        else:
            self._uploadNext()






    def _onAuthenticated(self):

        data = self._loadJson(str(self.reply.readAll()))

        self.reply = None


        if data is None:
            log.debug('Auth request failed (response: %s)', data)
            self._doAuthenticate()
            return


        if 'error' in data:
            log.debug('Auth request failed (response: %s)', data['error'])
            self._doAuthenticate()

        elif 'token' in data:
            log.debug('Auth OK')
            self.auth_token = data['token']
            self._uploadNext()


    def _uploadNext(self):

        if self._aborted:
            return

        log.debug('Uploading next')

        self.itemProgress.emit(0)
        self.totalProgress.emit(self.progress)

        if not self.tracks:
            log.debug('Finished')
            self.finished.emit()
            return

        self.current_track = self.tracks.pop(0)

        self.progress += 1

        self._doUpload()


    def _doUpload(self):

        if self.current_track is None or self._aborted:
            return

        track, track_type = self.current_track




        self.statusMessage.emit('Uploading {0}'.format(track['name']))

        log.debug('Sending upload request (%s)', track['name'])

        # data_fields, data = bryton_gpx_to_strava_json(track['gpx'])

        data = tcx.bryton_gpx_to_tcx(track['gpx'], activity_type=track_type, pretty=False, device=self.device_info)


        req = QNetworkRequest(QUrl(self.UPLOAD))
        req.setHeader(QNetworkRequest.ContentTypeHeader,
                "application/json")

        # d2 = json.loads(open('tmp/test.json').read())
        # d2['token'] = self.auth_token
        # self.reply = self.network_manager.post(req, json.dumps(d2))
        self.reply = self.network_manager.post(req, json.dumps({
            'token' : self.auth_token,
            'type' : 'tcx',
            'data' : data,
            'activity_type' : track_type,
            }))

        self.reply.finished.connect(self._onUploaded)

    def _onUploaded(self):

        data = self._loadJson(str(self.reply.readAll()))

        self.reply = None
        if data is None:
            log.debug('Upload failed (response: %s)', data)
            self._uploadFailed('Unknown error')
        elif 'error' in data:
            log.debug('Upload failed (%s)', data['error'])
            self._uploadFailed(data['error'])
        else:
            log.debug('Upload OK (%s)', data['upload_id'])
            self.upload_id = data['upload_id']
            self.statusMessage.emit('Checking upload status')
            QTimer.singleShot(2000, self._checkUpload)


            # self._progress += 1
            # self.tracks.pop(0)
            # self.progress.emit(self._progress)
            # self.upload()


    def _uploadFailed(self, msg):
        self.results.append({
            'status' : 'ERROR',
            'msg' : 'Failed: ' + msg,
        })

        self._uploadNext()

    def _uploadOk(self):
        self.results.append({
            'status' : 'OK',
            'msg': 'Successfully uploaded'
        })

        self._uploadNext()

    def _checkUpload(self):

        if self._aborted:
            return

        log.debug('Sending upload status request (%s)', self.upload_id)
        url = QUrl(self.UPLOAD_STATUS.format(id=self.upload_id))
        url.addQueryItem('token', self.auth_token)

        req = QNetworkRequest(url)

        self.reply = self.network_manager.get(req)

        self.reply.finished.connect(self._onUploadStatus)




    def _onUploadStatus(self):

        data = self._loadJson(str(self.reply.readAll()))

        self.reply = None

        if data is None:
            log.debug('Upload status failed (response: %s)', data)
            self._uploadFailed('Unknown error')
        elif 'upload_error' in data:
            log.debug('Upload status failed (%s)', data['upload_error'])
            self.statusMessage.emit('Upload failed')
            self._uploadFailed(data['upload_error'])
        else:
            self.statusMessage.emit(data['upload_status'])
            log.debug('Upload status %d (%s)', self.upload_id, data['upload_progress'])
            progress = int(data['upload_progress'])
            if progress == 0:
                progress = 10 # Just add a little to the progress so it doesn't look stuck
            self.itemProgress.emit(progress)
            if progress == 100:
                self._uploadOk()
            else:
                QTimer.singleShot(2500, self._checkUpload)




    def _loadJson(self, data):

        try:
            return json.loads(data)
        except ValueError, e:
            return None
Пример #34
0
class LobbyWidget(FormClass, BaseClass):
    planetClicked = QtCore.pyqtSignal(int)
    hovering = QtCore.pyqtSignal()
    creditsUpdated = QtCore.pyqtSignal(int)
    rankUpdated = QtCore.pyqtSignal(int)
    creditsUpdated = QtCore.pyqtSignal(int)
    victoriesUpdated = QtCore.pyqtSignal(int)
    attacksUpdated = QtCore.pyqtSignal()
    depotUpdated = QtCore.pyqtSignal()
    planetUpdated = QtCore.pyqtSignal(int)
    attackProposalUpdated = QtCore.pyqtSignal(int)
    ReinforcementUpdated = QtCore.pyqtSignal(dict)
    planetaryDefenseUpdated = QtCore.pyqtSignal(dict)
    ReinforcementsGroupUpdated = QtCore.pyqtSignal(dict)
    ReinforcementsGroupDeleted = QtCore.pyqtSignal(dict)
    dominationUpdated = QtCore.pyqtSignal(int)
    playersListUpdated = QtCore.pyqtSignal(dict)
    teamUpdated = QtCore.pyqtSignal(dict)
    searchingUpdated = QtCore.pyqtSignal(bool)

    def __init__(self, client, *args, **kwargs):
        logger.debug("Lobby instantiating.")
        BaseClass.__init__(self, *args, **kwargs)

        self.setupUi(self)

        self.client = client
        #self.client.galacticwarTab.setStyleSheet(util.readstylesheet("galacticwar/galacticwar.css"))

        self.COLOR_FACTIONS = {}
        self.mapTransparency = 10
        self.AA = True
        self.rotation = True
        self.stars = 25

        self.GWOptions = GWOptions(self)
        self.GWOptions.loadSettings()

        self.client.galacticwarTab.layout().addWidget(self)

        self.downloader = QNetworkAccessManager(self)
        self.downloader.finished.connect(self.finishRequest)

        self.shaderlist = []
        self.texturelist = {}
        self.shaders = {}

        self.infoPanel = None
        self.OGLdisplay = None

        self.galaxy = Galaxy(self)
        self.channel = None

        self.initDone = False

        self.uid = None
        self.faction = None
        self.name = None
        self.rank = None
        self.credits = 0
        self.victories = 0
        self.enslavedBy = None

        self.attacks = {}

        self.state = ClientState.NONE

        ## Network initialization

        self.socket = QtNetwork.QTcpSocket()
        self.socket.readyRead.connect(self.readFromServer)
        self.socket.disconnected.connect(self.disconnectedFromServer)
        self.socket.error.connect(self.socketError)
        self.blockSize = 0

        self.progress = QtGui.QProgressDialog()
        self.progress.setMinimum(0)
        self.progress.setMaximum(0)

#    def focusEvent(self, event):
#        return BaseClass.focusEvent(self, event)

    def showEvent(self, event):
        if self.state != ClientState.ACCEPTED:
            fa.exe.check("gw")
            if self.doConnect():
                logger.info("connection done")
                self.doLogin()

        else:
            if not self.initDone:
                logger.info("init not done")
                self.doLogin()
            else:
                if self.faction == None:
                    logger.info("not faction")
                    self.doLogin()

        return BaseClass.showEvent(self, event)

    def updateOptions(self):
        ''' settings galactic wars options'''
        self.GWOptions.show()

    def createChannel(self, chat, name):
        self.channel = gwChannel(chat, name, True)

    def finishRequest(self, reply):
        filename = reply.url().toString().rsplit('/', 1)[1]
        root, _ = os.path.splitext(filename)

        toFile = os.path.join(GW_TEXTURE_DIR, filename)
        writeFile = QtCore.QFile(toFile)
        if (writeFile.open(QtCore.QIODevice.WriteOnly)):
            writeFile.write(reply.readAll())
            writeFile.close()
        else:
            logger.warn("%s is not writeable in in %s. Skipping." %
                        (filename, GW_TEXTURE_DIR))

        if root in self.texturelist:
            del self.texturelist[root]

        if len(self.texturelist) == 0:
            self.setup()
            self.progress.close()

    def doConnect(self):
        logger.debug("Connecting to server")
        if self.client.state == ClientState.ACCEPTED:

            self.progress.setCancelButtonText("Cancel")
            self.progress.setWindowFlags(QtCore.Qt.CustomizeWindowHint
                                         | QtCore.Qt.WindowTitleHint)
            self.progress.setAutoClose(False)
            self.progress.setAutoReset(False)
            self.progress.setModal(1)
            self.progress.setWindowTitle("Galactic War Network...")
            self.progress.setLabelText("Gating in ...")
            self.progress.show()

            #            self.login = self.client.login.strip()
            #            logger.info("Attempting to gate as: " + str(self.client.login))
            self.state = ClientState.NONE

            # Begin connecting.
            self.socket.connectToHost(LOBBY_HOST, LOBBY_PORT)

            while (self.socket.state() !=
                   QtNetwork.QAbstractSocket.ConnectedState
                   ) and self.progress.isVisible():
                QtGui.QApplication.processEvents()

    #        #Perform Version Check first
            if not self.socket.state(
            ) == QtNetwork.QAbstractSocket.ConnectedState:

                self.progress.close()  # in case it was still showing...
                # We either cancelled or had a TCP error, meaning the connection failed..
                if self.progress.wasCanceled():
                    logger.warn("doConnect() aborted by user.")
                else:
                    logger.error("doConnect() failed with clientstate " +
                                 str(self.state) + ", socket errorstring: " +
                                 self.socket.errorString())
                return False
            else:

                return True

    def doLogin(self):
        ''' login in the GW server 
            We are using the main login and session to check legitimity of the client.
        '''

        self.progress.setLabelText("Gating in...")
        self.progress.reset()
        self.progress.show()

        logger.info("Attempting to gate as: " + str(self.client.login))
        self.state = ClientState.NONE

        self.send(
            dict(command="hello",
                 version=util.VERSION_STRING,
                 port=self.client.gamePort,
                 login=self.client.login,
                 session=self.client.session))

        while (not self.state) and self.progress.isVisible():
            QtGui.QApplication.processEvents()

        if self.progress.wasCanceled():
            logger.warn("Gating aborted by user.")
            return False

        self.progress.close()

        if self.state == ClientState.ACCEPTED:
            logger.info("Gating accepted.")
            self.progress.close()
            self.client.actionGalacticWar.triggered.connect(self.updateOptions)
            self.client.actionGalacticWar.setEnabled(True)
            return True
            #self.connected.emit()

        elif self.state == ClientState.REJECTED:
            logger.warning("Gating rejected.")
            return False
        else:
            # A more profound error has occurrect (cancellation or disconnection)
            return False

    def setup(self):
        self.galaxy.computeVoronoi()
        from glDisplay import GLWidget
        from infopanel import InfoPanelWidget
        from newsTicker import NewsTicker
        from reinforcements import PlanetaryWidget
        from reinforcements import ReinforcementWidget

        #items panels
        self.teams = Teams(self)
        self.planetaryItems = PlanetaryWidget(self)
        self.reinforcementItems = ReinforcementWidget(self)
        self.OGLdisplay = GLWidget(self)
        self.newsTicker = NewsTicker(self)
        self.galaxyLayout.addWidget(self.OGLdisplay)
        self.galaxyLayout.addWidget(self.newsTicker)
        self.newsTicker.setMaximumHeight(20)
        self.infoPanel = InfoPanelWidget(self)
        self.info_Panel.layout().addWidget(self.infoPanel)

        self.send(dict(command="init_done", status=True))
        self.infoPanel.setup()

    def get_rank(self, faction, rank):
        return RANKS[faction][rank]

    def handle_welcome(self, message):
        self.state = ClientState.ACCEPTED

    def handle_planetary_defense_info(self, message):
        '''populate planetary defense lists'''
        self.planetaryDefenseUpdated.emit(message)

    def handle_group_reinforcements_info(self, message):
        '''populate current group reinforcements '''
        self.ReinforcementsGroupUpdated.emit(message)

    def handle_group_reinforcements_deleted(self, message):
        self.ReinforcementsGroupDeleted.emit(message)

    def handle_reinforcement_item_info(self, message):
        '''populate reinforcement lists'''
        self.ReinforcementUpdated.emit(message)

    def handle_resource_required(self, message):
        if message["action"] == "shaders":
            self.shaderlist = message["data"]
            self.send(dict(command="request", action="shaders"))
        elif message["action"] == "textures":
            for tex in message["data"]:
                if not tex in self.texturelist:
                    self.texturelist[tex] = message["data"][tex]

    def handle_shader(self, message):
        name = message["name"]
        shader_fragment = message["shader_fragment"]
        shader_vertex = message["shader_vertex"]
        if not name in self.shaders:
            self.shaders[name] = {}
            self.shaders[name]["fragment"] = shader_fragment
            self.shaders[name]["vertex"] = shader_vertex

        if name in self.shaderlist:
            self.shaderlist.remove(name)
        self.check_resources()

        #we have all our shader.

    def get_texture_name(self, tex):
        return os.path.join(GW_TEXTURE_DIR, tex + ".png")

    def download_textures(self):
        self.progress.show()
        self.progress.setLabelText("Downloading resources ...")

        textInCache = []

        for tex in self.texturelist:
            if os.path.exists(self.get_texture_name(tex)):
                if util.md5(
                        self.get_texture_name(tex)) == self.texturelist[tex]:
                    #logger.debug(tex + ".png in cache.")
                    textInCache.append(tex)
                    continue
            #logger.debug("Downloading " + tex + ".png")
            self.downloader.get(
                QNetworkRequest(QtCore.QUrl(TEXTURE_SERVER + tex + ".png")))

        for tex in textInCache:
            del self.texturelist[tex]

        if len(self.texturelist) == 0:
            self.progress.close()
            self.setup()

    def check_resources(self):
        '''checking if we have everything we need'''
        if len(self.shaderlist) == 0 and self.initDone:
            self.download_textures()

    def handle_remove_team(self, message):
        self.teamUpdated.emit(dict(leader=None, members=[]))

    def handle_team(self, message):
        self.teamUpdated.emit(message)

    def handle_request_team(self, message):
        ''' We have a team invitation from someone '''
        who = message["who"]
        uid = message["uid"]

        self.infoPanel.formTeam()
        self.infoPanel.teamwidget.addProposal(who, uid)

    def handle_news_feed(self, message):
        '''Adding news to news feed'''
        if hasattr(self, "newsTicker"):
            if self.newsTicker:
                self.newsTicker.addNews(message["news"])

    def handle_player_info(self, message):
        ''' Update Player stats '''

        self.uid = int(message["uid"])
        self.faction = message["faction"]
        self.name = message["name"]
        self.rank = message["rank"]
        self.credits = message["credits"]
        self.victories = message["victories"]

        logger.debug("Received player info : victories %i, credits %i" %
                     (self.victories, self.credits))

        self.rankUpdated.emit(self.rank)
        self.creditsUpdated.emit(self.credits)
        self.victoriesUpdated.emit(self.victories)

    def handle_game_upgrades(self, message):
        '''writing reinforcement list'''
        upgrades = message["upgrades"]
        fa.gwgametable.writeTable(upgrades, "gwReinforcementList.gw")

        # and we empty the unit reinforcement list
        self.reinforcementItems.reset()

    def handle_domination(self, message):
        master = message["master"]
        self.enslavedBy = master
        self.dominationUpdated.emit(master)

    def handle_attack_result(self, message):
        self.progress.close()
        result = message["result"]
        if result == "won":
            QtGui.QMessageBox.information(self, "War report", "You win !",
                                          QtGui.QMessageBox.Close)

    def handle_attack_proposal(self, message):
        planetuid = message["planetuid"]
        self.attackProposalUpdated.emit(planetuid)

    def handle_attacks_info(self, message):
        if self.OGLdisplay == None:
            return

        attacks = message["attacks"]
        self.attacks = {}

        for playeruid in attacks:
            playeruid_int = int(playeruid)
            if not playeruid_int in self.attacks:
                self.attacks[playeruid_int] = {}

            for planetuid in attacks[playeruid]:
                planetuid_int = int(planetuid)
                self.attacks[playeruid_int][planetuid_int] = attacks[
                    playeruid][planetuid]
        self.attacksUpdated.emit()

    def handle_planet_defense_remove(self, message):
        '''handling removing defenses for a planet'''
        planetuid = message["planetuid"]
        self.galaxy.removeDefenses(planetuid)

    def handle_planet_depot_info(self, message):
        '''handling depots'''
        planetuid = message["planetuid"]
        self.galaxy.updateDepot(planetuid, message)
        self.depotUpdated.emit()

    def handle_planet_defense_info(self, message):
        '''handling defenses for planets'''
        planetuid = message["planetuid"]
        self.galaxy.updateDefenses(planetuid, message)

    def handle_planet_info(self, message):
        uid = message['uid']
        if not uid in self.galaxy.control_points:
            display = message['visible']
            x = message['posx']
            y = message['posy']
            size = message['size']
            textureMd5 = message['md5tex']
            name = message['name']
            desc = message['desc']
            sector = message['sector']
            if display:
                texture = message['texture']
                mapname = message['mapname']
                maxplayer = message['maxplayer']
                if not texture in self.texturelist:
                    self.texturelist[texture] = textureMd5
            else:
                mapname = ""
                texture = 0
                maxplayer = 0

            self.galaxy.addPlanet(uid,
                                  sector,
                                  name,
                                  desc,
                                  x,
                                  y,
                                  size,
                                  maxplayer=maxplayer,
                                  mapname=mapname,
                                  texture=texture,
                                  init=True,
                                  display=display)
            self.galaxy.update(message)

            if not uid in self.galaxy.links:
                self.galaxy.links[uid] = message['links']
        else:
            self.galaxy.update(message)
            self.planetUpdated.emit(message['sector'])

    def handle_logged_in(self, message):

        self.handle_player_info(message)
        if self.faction != None:
            self.client.galacticwarTab.setStyleSheet(
                util.readstylesheet("galacticwar/galacticwar.css").replace(
                    "%FACTION%", FACTIONS[self.faction]))

        self.attacksUpdated.emit()

    def handle_create_account(self, message):
        if message["action"] == 0:

            accountCreator = loginwizards.gwSelectFaction(self)
            accountCreator.exec_()
            if self.faction != None:
                self.send(
                    dict(command="account_creation",
                         action=0,
                         faction=self.faction))
            else:
                self.client.mainTabs.setCurrentIndex(0)
                QtGui.QMessageBox.warning(
                    self, "No faction :(",
                    "You need to pledge allegiance to a faction in order to play Galactic War !"
                )

        elif message["action"] == 1:
            name = message["name"]
            self.faction = message["faction"]

            self.rank = message["rank"]

            question = QtGui.QMessageBox.question(
                self, "Avatar name generation",
                "Your avatar name will be : <br><br>" +
                self.get_rank(self.faction, self.rank) + " " + name +
                ".<br><br>Press Reset to generate another, Ok to accept.",
                QtGui.QMessageBox.Reset, QtGui.QMessageBox.Ok)
            if question == QtGui.QMessageBox.Reset:
                self.send(dict(command="account_creation", action=1))
            else:
                self.name = name
                self.send(dict(command="account_creation", action=2))

    def handle_faction_player_list(self, message):
        '''players online'''
        self.playersListUpdated.emit(message["players"])

    def handle_init_done(self, message):
        if message['status'] == True:
            self.initDone = True
            self.check_resources()

    def handle_social(self, message):
        if "autojoin" in message:
            if message["autojoin"] == 0:
                self.client.autoJoin.emit(["#UEF"])
            elif message["autojoin"] == 1:
                self.client.autoJoin.emit(["#Aeon"])
            elif message["autojoin"] == 2:
                self.client.autoJoin.emit(["#Cybran"])
            elif message["autojoin"] == 3:
                self.client.autoJoin.emit(["#Seraphim"])

    def handle_searching(self, message):
        state = message["state"]
        if state == "on":
            self.searchingUpdated.emit(True)
        else:
            self.searchingUpdated.emit(False)

    def handle_notice(self, message):
        self.client.handle_notice(message)

    def handle_update(self, message):
        update = message["update"]
        if not util.developer():
            logger.warn("Server says that Updating is needed.")
            self.progress.close()
            self.state = ClientState.OUTDATED
            fa.updater.fetchClientUpdate(update)

    def process(self, action, stream):
        if action == "PING":
            self.writeToServer("PONG")
        else:
            self.dispatchJSON(action, stream)

    def dispatchJSON(self, data_string, stream):
        '''
        A fairly pythonic way to process received strings as JSON messages.
        '''
        message = json.loads(data_string)
        cmd = "handle_" + message['command']
        #logger.debug("Incoming JSON Command: " + data_string)
        if hasattr(self, cmd):
            getattr(self, cmd)(message)
        else:
            logger.error("command unknown : %s", cmd)

    def send(self, message):
        data = json.dumps(message)
        logger.info("Outgoing JSON Message: " + data)
        self.writeToServer(data)

    @QtCore.pyqtSlot()
    def readFromServer(self):
        ins = QtCore.QDataStream(self.socket)
        ins.setVersion(QtCore.QDataStream.Qt_4_2)

        while ins.atEnd() == False:
            if self.blockSize == 0:
                if self.socket.bytesAvailable() < 4:
                    return
                self.blockSize = ins.readUInt32()
            if self.socket.bytesAvailable() < self.blockSize:
                return

            action = ins.readQString()
            self.process(action, ins)
            self.blockSize = 0

    @QtCore.pyqtSlot()
    def disconnectedFromServer(self):
        logger.warn("Disconnected from lobby server.")

        if self.state == ClientState.ACCEPTED:
            QtGui.QMessageBox.warning(
                QtGui.QApplication.activeWindow(),
                "Disconnected from Galactic War",
                "The lobby lost the connection to the Galactic War server.<br/><b>You might still be able to chat.<br/>To play, try reconnecting a little later!</b>",
                QtGui.QMessageBox.Close)
            self.initDone = False
            self.client.mainTabs.setCurrentIndex(0)

            self.client.mainTabs.setTabEnabled(
                self.client.mainTabs.indexOf(self.client.galacticwarTab),
                False)
            self.client.mainTabs.setTabText(
                self.client.mainTabs.indexOf(self.client.galacticwarTab),
                "offline")

        self.state = ClientState.DROPPED

    def writeToServer(self, action, *args, **kw):
        '''
        This method is the workhorse of the client, and is used to send messages, queries and commands to the server.
        '''
        logger.debug("Client: " + action)

        block = QtCore.QByteArray()
        out = QtCore.QDataStream(block, QtCore.QIODevice.ReadWrite)
        out.setVersion(QtCore.QDataStream.Qt_4_2)

        out.writeUInt32(0)
        out.writeQString(action)

        for arg in args:
            if type(arg) is IntType:
                out.writeInt(arg)
            elif isinstance(arg, basestring):
                out.writeQString(arg)
            elif type(arg) is FloatType:
                out.writeFloat(arg)
            elif type(arg) is ListType:
                out.writeQVariantList(arg)
            elif type(arg) is DictType:
                out.writeQString(json.dumps(arg))
            elif type(arg) is QtCore.QFile:
                arg.open(QtCore.QIODevice.ReadOnly)
                fileDatas = QtCore.QByteArray(arg.readAll())
                #seems that that logger doesn't work
                #logger.debug("file size ", int(fileDatas.size()))
                out.writeInt(fileDatas.size())
                out.writeRawData(fileDatas)

                # This may take a while. We display the progress bar so the user get a feedback
                self.sendFile = True
                self.progress.setLabelText("Sending file to server")
                self.progress.setCancelButton(None)
                self.progress.setWindowFlags(QtCore.Qt.CustomizeWindowHint
                                             | QtCore.Qt.WindowTitleHint)
                self.progress.setAutoClose(True)
                self.progress.setMinimum(0)
                self.progress.setMaximum(100)
                self.progress.setModal(1)
                self.progress.setWindowTitle("Uploading in progress")

                self.progress.show()
                arg.close()
            else:
                logger.warn("Uninterpreted Data Type: " + str(type(arg)) +
                            " sent as str: " + str(arg))
                out.writeQString(str(arg))

        out.device().seek(0)
        out.writeUInt32(block.size() - 4)
        self.bytesToSend = block.size() - 4

        self.socket.write(block)

    @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
    def socketError(self, error):
        logger.error("TCP Socket Error: " + self.socket.errorString())
        if self.state > ClientState.NONE:  # Positive client states deserve user notification.
            QtGui.QMessageBox.critical(
                None, "TCP Error",
                "A TCP Connection Error has occurred:<br/><br/><b>" +
                self.socket.errorString() + "</b>", QtGui.QMessageBox.Close)
Пример #35
0
class MikiEdit(QTextEdit):

    def __init__(self, parent=None):
        super(MikiEdit, self).__init__(parent)
        self.parent = parent
        self.settings = parent.settings
        self.setFontPointSize(12)
        self.setVisible(False)
        self.ix = open_dir(self.settings.indexdir)

        # Spell checker support
        try:
            import enchant
            enchant.Dict()
            self.speller = enchant.Dict()
        except ImportError:
            print("Spell checking unavailable. Need to install pyenchant.")
            self.speller = None
        except enchant.errors.DictNotFoundError:
            print("Spell checking unavailable. Need to install dictionary (e.g. aspell-en).")
            self.speller = None

        self.imageFilter = ""
        self.documentFilter = ""
        for ext in self.settings.attachmentImage:
            self.imageFilter += " *" + ext
        for ext in self.settings.attachmentDocument:
            self.documentFilter += " *" + ext
        self.imageFilter = "Image (" + self.imageFilter.strip() + ")"
        self.documentFilter = "Document (" + self.documentFilter.strip() + ")"

        self.downloadAs = ""
        self.networkManager = QNetworkAccessManager()
        self.networkManager.finished.connect(self.downloadFinished)


    def updateIndex(self):
        ''' Update whoosh index, which cost much computing resource '''
        page = self.parent.notesTree.currentPage()
        content = self.toPlainText()        
        try:
            #writer = self.ix.writer()
            writer = AsyncWriter(self.ix)
            if METADATA_CHECKER.match(content) and 'meta' in self.settings.extensions:
                no_metadata_content = METADATA_CHECKER.sub("", content, count=1).lstrip()
                self.settings.md.reset().convert(content)
                writer.update_document(
                    path=page, title=parseTitle(content, page), content=no_metadata_content,
                    tags=','.join(self.settings.md.Meta.get('tags', [])).strip())
                writer.commit()
            else:
                writer.update_document(
                    path=page, title=parseTitle(content, page), content=content, tags='')
                writer.commit()
        except:
            print("Whoosh commit failed.")

    def downloadFinished(self, reply):
        if reply.error():
            print("Failed to download")
        else:
            attFile = QFile(self.downloadAs)
            attFile.open(QIODevice.WriteOnly)
            attFile.write(reply.readAll())
            attFile.close()
            print("Succeeded")
        reply.deleteLater()

    def mimeFromText(self, text):
        mime = QMimeData()
        mime.setText(text)
        return mime

    def createMimeDataFromSelection(self):
        """ Reimplement this to prevent copied text taken as hasHtml() """
        plaintext = self.textCursor().selectedText()

        # From QTextCursor doc:
        # if the selection obtained from an editor spans a line break,
        # the text will contain a Unicode U+2029 paragraph separator character
        # instead of a newline \n character
        text = plaintext.replace('\u2029', '\n')
        return self.mimeFromText(text)

    def insertFromMimeData(self, source):
        """ Intended behavior
        If copy/drag something that hasUrls, then check the extension name:
            if image then apply image pattern ![Alt text](/path/to/img.jpg)
                     else apply link  pattern [text](http://example.net)
        If copy/drag something that hasImage, then ask for file name
        If copy/drag something that hasHtml, then html2text
        Else use the default insertFromMimeData implementation
        """

        item = self.parent.notesTree.currentItem()
        attDir = self.parent.notesTree.itemToAttachmentDir(item)
        if not QDir(attDir).exists():
            QDir().mkpath(attDir)

        if source.hasUrls():
            for qurl in source.urls():
                url = qurl.toString()
                filename, extension = os.path.splitext(url)
                filename = os.path.basename(filename)
                newFilePath = os.path.join(attDir, filename + extension).replace(os.sep, '/')
                relativeFilePath = newFilePath.replace(self.settings.notebookPath, "..")
                attachments = self.settings.attachmentImage + self.settings.attachmentDocument

                if QUrl(qurl).isLocalFile():
                    if extension.lower() in attachments:
                        nurl = url.replace("file://", "")
                        QFile.copy(nurl, newFilePath)
                        self.parent.updateAttachmentView()

                        if extension.lower() in self.settings.attachmentImage:
                            text = "![%s](%s)" % (filename, relativeFilePath)
                        elif extension.lower() in self.settings.attachmentDocument:
                            text = "[%s%s](%s)\n" % (filename, extension, relativeFilePath)
                    else:
                        text = "[%s%s](%s)\n" % (filename, extension, url)
                else:
                    if extension.lower() in attachments:
                        self.downloadAs = newFilePath
                        self.networkManager.get(QNetworkRequest(qurl))

                        if extension.lower() in self.settings.attachmentImage:
                            text = "![%s](%s)" % (filename, relativeFilePath)
                        elif extension.lower() in self.settings.attachmentDocument:
                            text = "[%s%s](%s)\n" % (filename, extension, relativeFilePath)
                    else:
                        text = "[%s%s](%s)\n" % (filename, extension, url)

                super(MikiEdit, self).insertFromMimeData(self.mimeFromText(text))
        elif source.hasImage():
            img = source.imageData()
            attDir = self.parent.notesTree.itemToAttachmentDir(item)
            dialog = LineEditDialog(attDir, self)
            if dialog.exec_():
                fileName = dialog.editor.text()
                if not QFileInfo(fileName).suffix():
                    fileName += '.jpg'
                filePath = os.path.join(attDir, fileName).replace(os.sep, '/')
                img.save(filePath)
                relativeFilePath = filePath.replace(self.settings.notebookPath, "..")
                text = "![%s](%s)" % (fileName, relativeFilePath)
                super(MikiEdit, self).insertFromMimeData(self.mimeFromText(text))
        elif source.hasHtml():
            html = source.html()
            if HAS_HTML2TEXT:
                backToMarkdown = html2text.HTML2Text()
                markdown = backToMarkdown.handle(html)
                super(MikiEdit, self).insertFromMimeData(self.mimeFromText(markdown))
            else:
                super(MikiEdit, self).insertFromMimeData(self.mimeFromText(html))
        else:
            super(MikiEdit, self).insertFromMimeData(source)

    def insertAttachment(self, filePath, fileType):
        item = self.parent.notesTree.currentItem()
        attDir = self.parent.notesTree.itemToAttachmentDir(item)
        filename, extension = os.path.splitext(filePath)
        filename = os.path.basename(filename)
        newFilePath = os.path.join(attDir, filename + extension).replace(os.sep, '/')
        relativeFilePath = newFilePath.replace(self.settings.notebookPath, "..")
        if not os.path.exists(attDir):
            os.makedirs(attDir)
        QFile.copy(filePath, newFilePath)
        self.parent.updateAttachmentView()
        if fileType == self.imageFilter:
            text = "![%s](%s)" % (filename, relativeFilePath)
        else:
            text = "[%s%s](%s)\n" % (filename, extension, relativeFilePath)
        self.insertPlainText(text)

    def insertAttachmentWrapper(self):
        (filePath, fileType) = QFileDialog.getOpenFileNameAndFilter(
            self, self.tr('Insert attachment'), '',
            self.imageFilter + ";;" + self.documentFilter)
        if filePath == "":
            return
        self.insertAttachment(filePath, fileType)

    def contextMenuEvent(self, event):

        def correctWord(cursor, word):
            # From QTextCursor doc:
            # if there is a selection, the selection is deleted and replaced
            return lambda: cursor.insertText(word)

        popup_menu = self.createStandardContextMenu()

        # Spellcheck the word under mouse cursor, not self.textCursor
        cursor = self.cursorForPosition(event.pos())
        cursor.select(QTextCursor.WordUnderCursor)

        text = cursor.selectedText()
        if self.speller and text:
            if not self.speller.check(text):
                lastAction = popup_menu.actions()[0]
                for word in self.speller.suggest(text)[:10]:
                    action = QAction(word, popup_menu)
                    action.triggered.connect(correctWord(cursor, word))
                    action.setFont(QFont("sans", weight=QFont.Bold))
                    popup_menu.insertAction(lastAction, action)
                popup_menu.insertSeparator(lastAction)

        popup_menu.exec_(event.globalPos())

    def keyPressEvent(self, event):
        """ for Qt.Key_Tab, expand as 4 spaces
            for other keys, use default implementation
        """
        if event.key() == Qt.Key_Tab:
            self.insertPlainText('    ')
        else:
            QTextEdit.keyPressEvent(self, event)
    '''
    def closeEvent(self, event):
        self.ix.close()
        print('closed idx')
        event.accept()
    '''
    def save(self, item):
        pageName = self.parent.notesTree.itemToPage(item)
        filePath = self.parent.notesTree.itemToFile(item)
        htmlFile = self.parent.notesTree.itemToHtmlFile(item)

        fh = QFile(filePath)
        try:
            if not fh.open(QIODevice.WriteOnly):
                raise IOError(fh.errorString())
        except IOError as e:
            QMessageBox.warning(self, 'Save Error',
                                'Failed to save %s: %s' % (pageName, e))
            raise
        finally:
            if fh is not None:
                savestream = QTextStream(fh)
                savestream << self.toPlainText()
                fh.close()
                self.document().setModified(False)

                # Fork a process to update index, which benefit responsiveness.
                Thread(target=self.updateIndex).start()


    def toHtml(self):
        '''markdown.Markdown.convert v.s. markdown.markdown
            ~~Previously `convert` was used, but it doens't work with fenced_code~~
            fixed that by calling markdown.Markdown.reset before each conversion
        '''
        htmltext = self.toPlainText()
        if 'asciimathml' in self.settings.extensions:
            stuff=JSCRIPT_TPL.format(self.settings.mathjax)
        else:
            stuff=''
        return self.settings.md.reset().convert(htmltext)+stuff
        # md = markdown.Markdown(extensions)
        # return md.convert(htmltext)

    def saveAsHtml(self, htmlFile = None):
        """ Save as Complete (with css and images) or HTML Only
            To be merged with saveNoteAs
        """
        if not htmlFile:
            (htmlFile, htmlType) = QFileDialog.getSaveFileNameAndFilter(
                self, self.tr("Export to HTML"), "", "Complete;;HTML Only")
        if htmlFile == '':
            return
        if not QFileInfo(htmlFile).suffix():
            htmlFile += '.html'

        if htmlType == "Complete":
            self.saveCompleteHtml(htmlFile)
        else:
            self.saveHtmlOnly(htmlFile)

    def saveCompleteHtml(self, htmlFile):
        html = QFile(htmlFile)
        html.open(QIODevice.WriteOnly)
        savestream = QTextStream(html)
        css = QFile(self.settings.cssfile)
        css.open(QIODevice.ReadOnly)
        # Use a html lib may be a better idea?
        savestream << "<html><head><meta charset='utf-8'></head>"
        # Css is inlined.
        savestream << "<style>"
        savestream << QTextStream(css).readAll()
        savestream << "</style>"
        # Note content
        savestream << self.toHtml()
        savestream << "</html>"
        html.close()

    def saveHtmlOnly(self, htmlFile):
        fileDir = os.path.dirname(htmlFile)
        QDir().mkpath(fileDir)

        html = QFile(htmlFile)
        html.open(QIODevice.WriteOnly)
        savestream = QTextStream(html)
        savestream << """
                      <html><head>
                        <meta charset="utf-8">
                        <link rel="stylesheet" href="/css/notebook.css" type="text/css" />
                      </head>
                      """
        # Note content
        savestream << self.toHtml()
        savestream << "</html>"
        html.close()
Пример #36
0
class downloadManager(QtCore.QObject):
    ''' This class allows downloading stuff in the background'''
    def __init__(self, parent=None):
        self.client = parent
        self.nam = QNetworkAccessManager()

        self.nam.finished.connect(self.finishedDownload)

        self.modRequests = {}
        self.mapRequests = {}
        self.mapRequestsItem = []

    def finishedDownload(self, reply):
        ''' finishing downloads '''
        urlstring = reply.url().toString()
        reqlist = []
        if urlstring in self.mapRequests: reqlist = self.mapRequests[urlstring]
        if urlstring in self.modRequests: reqlist = self.modRequests[urlstring]
        if reqlist:
            #save the map from cache
            name = os.path.basename(reply.url().toString())
            pathimg = os.path.join(util.CACHE_DIR, name)
            img = QtCore.QFile(pathimg)
            img.open(QtCore.QIODevice.WriteOnly)
            img.write(reply.readAll())
            img.close()
            if os.path.exists(pathimg):
                #Create alpha-mapped preview image
                try:
                    pass  # the server already sends 100x100 pic
#                    img = QtGui.QImage(pathimg).scaled(100,100)
#                    img.save(pathimg)
                except:
                    pathimg = "games/unknown_map.png"
                    logger.info("Failed to resize " + name)
            else:
                pathimg = "games/unknown_map.png"
                logger.debug("Web Preview failed for: " + name)
            logger.debug("Web Preview used for: " + name)
            for requester in reqlist:
                if requester:
                    if requester in self.mapRequestsItem:
                        requester.setIcon(0, util.icon(pathimg, False))
                        self.mapRequestsItem.remove(requester)
                    else:
                        requester.setIcon(util.icon(pathimg, False))
            if urlstring in self.mapRequests: del self.mapRequests[urlstring]
            if urlstring in self.modRequests: del self.modRequests[urlstring]

    def downloadMap(self, name, requester, item=False):
        '''
        Downloads a preview image from the web for the given map name
        '''
        #This is done so generated previews always have a lower case name. This doesn't solve the underlying problem (case folding Windows vs. Unix vs. FAF)
        name = name.lower()
        if len(name) == 0:
            return

        url = QtCore.QUrl(VAULT_PREVIEW_ROOT + urllib2.quote(name) + ".png")
        if not url.toString() in self.mapRequests:
            logger.debug("Searching map preview for: " + name)
            self.mapRequests[url.toString()] = []
            request = QNetworkRequest(url)
            self.nam.get(request)
            self.mapRequests[url.toString()].append(requester)
        else:
            self.mapRequests[url.toString()].append(requester)
        if item:
            self.mapRequestsItem.append(requester)

    def downloadModPreview(self, strurl, requester):
        url = QtCore.QUrl(strurl)
        if not url.toString() in self.modRequests:
            logger.debug("Searching mod preview for: " +
                         os.path.basename(strurl).rsplit('.', 1)[0])
            self.modRequests[url.toString()] = []
            request = QNetworkRequest(url)
            self.nam.get(request)
        self.modRequests[url.toString()].append(requester)
Пример #37
0
class OnlineUpdater(QWidgetComponentFactory(uiFile=COMPONENT_UI_FILE)):
	"""
	| Defines the :mod:`sibl_gui.components.addons.onlineUpdater.onlineUpdater` Component Interface class.
	| This Component provides online updating capabilities to the Application available through options exposed in
		the :mod:`sibl_gui.components.core.preferencesManager.preferencesManager` Component ui.
	"""

	def __init__(self, parent=None, name=None, *args, **kwargs):
		"""
		Initializes the class.

		:param parent: Object parent.
		:type parent: QObject
		:param name: Component name.
		:type name: unicode
		:param \*args: Arguments.
		:type \*args: \*
		:param \*\*kwargs: Keywords arguments.
		:type \*\*kwargs: \*\*
		"""

		LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))

		super(OnlineUpdater, self).__init__(parent, name, *args, **kwargs)

		# --- Setting class attributes. ---
		self.deactivatable = True

		self.__engine = None
		self.__settings = None
		self.__settingsSection = None

		self.__preferencesManager = None
		self.__templatesOutliner = None
		self.__locationsBrowser = None

		self.__ioDirectory = "remote/"

		self.__repositoryUrl = REPOSITORY_URL
		self.__releasesFileUrl = "sIBL_GUI_Releases.rc"

		self.__networkAccessManager = None
		self.__releasesFileReply = None

		self.__remoteUpdater = None
		self.__reportUpdateStatus = None

	#******************************************************************************************************************
	#***	Attributes properties.
	#******************************************************************************************************************
	@property
	def engine(self):
		"""
		Property for **self.__engine** attribute.

		:return: self.__engine.
		:rtype: QObject
		"""

		return self.__engine

	@engine.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def engine(self, value):
		"""
		Setter for **self.__engine** attribute.

		:param value: Attribute value.
		:type value: QObject
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "engine"))

	@engine.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def engine(self):
		"""
		Deleter for **self.__engine** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "engine"))

	@property
	def settings(self):
		"""
		Property for **self.__settings** attribute.

		:return: self.__settings.
		:rtype: QSettings
		"""

		return self.__settings

	@settings.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def settings(self, value):
		"""
		Setter for **self.__settings** attribute.

		:param value: Attribute value.
		:type value: QSettings
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "settings"))

	@settings.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def settings(self):
		"""
		Deleter for **self.__settings** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "settings"))

	@property
	def settingsSection(self):
		"""
		Property for **self.__settingsSection** attribute.

		:return: self.__settingsSection.
		:rtype: unicode
		"""

		return self.__settingsSection

	@settingsSection.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def settingsSection(self, value):
		"""
		Setter for **self.__settingsSection** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "settingsSection"))

	@settingsSection.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def settingsSection(self):
		"""
		Deleter for **self.__settingsSection** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "settingsSection"))

	@property
	def preferencesManager(self):
		"""
		Property for **self.__preferencesManager** attribute.

		:return: self.__preferencesManager.
		:rtype: QWidget
		"""

		return self.__preferencesManager

	@preferencesManager.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def preferencesManager(self, value):
		"""
		Setter for **self.__preferencesManager** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "preferencesManager"))

	@preferencesManager.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def preferencesManager(self):
		"""
		Deleter for **self.__preferencesManager** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "preferencesManager"))

	@property
	def templatesOutliner(self):
		"""
		Property for **self.__templatesOutliner** attribute.

		:return: self.__templatesOutliner.
		:rtype: QWidget
		"""

		return self.__templatesOutliner

	@templatesOutliner.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def templatesOutliner(self, value):
		"""
		Setter for **self.__templatesOutliner** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "templatesOutliner"))

	@templatesOutliner.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def templatesOutliner(self):
		"""
		Deleter for **self.__templatesOutliner** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "templatesOutliner"))

	@property
	def locationsBrowser(self):
		"""
		Property for **self.__locationsBrowser** attribute.

		:return: self.__locationsBrowser.
		:rtype: QWidget
		"""

		return self.__locationsBrowser

	@locationsBrowser.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def locationsBrowser(self, value):
		"""
		Setter for **self.__locationsBrowser** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "locationsBrowser"))

	@locationsBrowser.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def locationsBrowser(self):
		"""
		Deleter for **self.__locationsBrowser** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "locationsBrowser"))

	@property
	def ioDirectory(self):
		"""
		Property for **self.__ioDirectory** attribute.

		:return: self.__ioDirectory.
		:rtype: unicode
		"""

		return self.__ioDirectory

	@ioDirectory.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def ioDirectory(self, value):
		"""
		Setter for **self.__ioDirectory** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "ioDirectory"))

	@ioDirectory.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def ioDirectory(self):
		"""
		Deleter for **self.__ioDirectory** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "ioDirectory"))

	@property
	def repositoryUrl(self):
		"""
		Property for **self.__repositoryUrl** attribute.

		:return: self.__repositoryUrl.
		:rtype: unicode
		"""

		return self.__repositoryUrl

	@repositoryUrl.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def repositoryUrl(self, value):
		"""
		Setter for **self.__repositoryUrl** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "repositoryUrl"))

	@repositoryUrl.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def repositoryUrl(self):
		"""
		Deleter for **self.__repositoryUrl** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "repositoryUrl"))

	@property
	def releasesFileUrl(self):
		"""
		Property for **self.__releasesFileUrl** attribute.

		:return: self.__releasesFileUrl.
		:rtype: unicode
		"""

		return self.__releasesFileUrl

	@releasesFileUrl.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def releasesFileUrl(self, value):
		"""
		Setter for **self.__releasesFileUrl** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "releasesFileUrl"))

	@releasesFileUrl.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def releasesFileUrl(self):
		"""
		Deleter for **self.__releasesFileUrl** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "releasesFileUrl"))

	@property
	def networkAccessManager(self):
		"""
		Property for **self.__networkAccessManager** attribute.

		:return: self.__networkAccessManager.
		:rtype: QNetworkAccessManager
		"""

		return self.__networkAccessManager

	@networkAccessManager.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def networkAccessManager(self, value):
		"""
		Setter for **self.__networkAccessManager** attribute.

		:param value: Attribute value.
		:type value: QNetworkAccessManager
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "networkAccessManager"))

	@networkAccessManager.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def networkAccessManager(self):
		"""
		Deleter for **self.__networkAccessManager** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "networkAccessManager"))

	@property
	def releaseReply(self):
		"""
		Property for **self.__releasesFileReply** attribute.

		:return: self.__releasesFileReply.
		:rtype: QNetworkReply
		"""

		return self.__releasesFileReply

	@releaseReply.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def releaseReply(self, value):
		"""
		Setter for **self.__releasesFileReply** attribute.

		:param value: Attribute value.
		:type value: QNetworkReply
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "releaseReply"))

	@releaseReply.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def releaseReply(self):
		"""
		Deleter for **self.__releasesFileReply** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "releaseReply"))

	@property
	def remoteUpdater(self):
		"""
		Property for **self.__remoteUpdater** attribute.

		:return: self.__remoteUpdater.
		:rtype: object
		"""

		return self.__remoteUpdater

	@remoteUpdater.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def remoteUpdater(self, value):
		"""
		Setter for **self.__remoteUpdater** attribute.

		:param value: Attribute value.
		:type value: object
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "remoteUpdater"))

	@remoteUpdater.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def remoteUpdater(self):
		"""
		Deleter for **self.__remoteUpdater** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "remoteUpdater"))

	@property
	def reportUpdateStatus(self):
		"""
		Property for **self.__reportUpdateStatus** attribute.

		:return: self.__reportUpdateStatus.
		:rtype: bool
		"""

		return self.__reportUpdateStatus

	@reportUpdateStatus.setter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def reportUpdateStatus(self, value):
		"""
		Setter for **self.__reportUpdateStatus** attribute.

		:param value: Attribute value.
		:type value: bool
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "reportUpdateStatus"))

	@reportUpdateStatus.deleter
	@foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
	def reportUpdateStatus(self):
		"""
		Deleter for **self.__reportUpdateStatus** attribute.
		"""

		raise foundations.exceptions.ProgrammingError(
		"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "reportUpdateStatus"))

	#******************************************************************************************************************
	#***	Class methods.
	#******************************************************************************************************************
	def activate(self, engine):
		"""
		Activates the Component.

		:param engine: Engine to attach the Component to.
		:type engine: QObject
		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Activating '{0}' Component.".format(self.__class__.__name__))

		self.__engine = engine
		self.__settings = self.__engine.settings
		self.__settingsSection = self.name

		self.__preferencesManager = self.__engine.componentsManager["factory.preferencesManager"]
		self.__templatesOutliner = self.__engine.componentsManager["core.templatesOutliner"]
		self.__locationsBrowser = self.__engine.componentsManager["addons.locationsBrowser"]

		self.__ioDirectory = os.path.join(self.__engine.userApplicationDataDirectory,
										Constants.ioDirectory, self.__ioDirectory)
		not foundations.common.pathExists(self.__ioDirectory) and os.makedirs(self.__ioDirectory)

		self.__networkAccessManager = QNetworkAccessManager()

		self.__reportUpdateStatus = True

		self.activated = True
		return True

	def deactivate(self):
		"""
		Deactivates the Component.

		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Deactivating '{0}' Component.".format(self.__class__.__name__))

		self.__engine = None
		self.__settings = None
		self.__settingsSection = None

		self.__preferencesManager = None
		self.__templatesOutliner = None
		self.__locationsBrowser = None

		self.__ioDirectory = os.path.basename(os.path.abspath(self.__ioDirectory))

		self.__networkAccessManager = None

		self.__reportUpdateStatus = None

		self.activated = False
		return True

	def initializeUi(self):
		"""
		Initializes the Component ui.
		
		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Initializing '{0}' Component ui.".format(self.__class__.__name__))

		self.__engine.parameters.deactivateWorkerThreads and \
		LOGGER.info(
		"{0} | 'OnStartup' Online Updater worker thread deactivated by '{1}' command line parameter value!".format(
		self.__class__.__name__, "deactivateWorkerThreads"))

		self.__Check_For_New_Releases_On_Startup_checkBox_setUi()
		self.__Ignore_Non_Existing_Templates_checkBox_setUi()

		# Signals / Slots.
		self.Check_For_New_Releases_pushButton.clicked.connect(self.__Check_For_New_Releases_pushButton__clicked)
		self.Check_For_New_Releases_On_Startup_checkBox.stateChanged.connect(
		self.__Check_For_New_Releases_On_Startup_checkBox__stateChanged)
		self.Ignore_Non_Existing_Templates_checkBox.stateChanged.connect(
		self.__Ignore_Non_Existing_Templates_checkBox__stateChanged)

		self.initializedUi = True
		return True

	def uninitializeUi(self):
		"""
		Uninitializes the Component ui.
		
		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Uninitializing '{0}' Component ui.".format(self.__class__.__name__))

		# Signals / Slots.
		self.Check_For_New_Releases_pushButton.clicked.disconnect(self.__Check_For_New_Releases_pushButton__clicked)
		self.Check_For_New_Releases_On_Startup_checkBox.stateChanged.disconnect(
		self.__Check_For_New_Releases_On_Startup_checkBox__stateChanged)
		self.Ignore_Non_Existing_Templates_checkBox.stateChanged.disconnect(
		self.__Ignore_Non_Existing_Templates_checkBox__stateChanged)

		self.initializedUi = False
		return True

	def onStartup(self):
		"""
		Defines the slot triggered on Framework startup.

		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Calling '{0}' Component Framework 'onStartup' method.".format(self.__class__.__name__))

		self.__reportUpdateStatus = False
		if not self.__engine.parameters.deactivateWorkerThreads and \
		self.Check_For_New_Releases_On_Startup_checkBox.isChecked():
			self.checkForNewReleases()
		return True

	def addWidget(self):
		"""
		Adds the Component Widget to the engine.

		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Adding '{0}' Component Widget.".format(self.__class__.__name__))

		self.__preferencesManager.Others_Preferences_gridLayout.addWidget(self.Online_Updater_groupBox)

	def removeWidget(self):
		"""
		Removes the Component Widget from the engine.

		:return: Method success.
		:rtype: bool
		"""

		LOGGER.debug("> Removing '{0}' Component Widget.".format(self.__class__.__name__))

		self.Online_Updater_groupBox.setParent(None)

	def __Check_For_New_Releases_On_Startup_checkBox_setUi(self):
		"""
		Sets the **Check_For_New_Releases_On_Startup_checkBox** Widget.
		"""

		# Adding settings key if it doesn't exists.
		self.__settings.getKey(self.__settingsSection, "checkForNewReleasesOnStartup").isNull() and \
		self.__settings.setKey(self.__settingsSection, "checkForNewReleasesOnStartup", Qt.Checked)

		checkForNewReleasesOnStartup = self.__settings.getKey(self.__settingsSection, "checkForNewReleasesOnStartup")
		LOGGER.debug("> Setting '{0}' with value '{1}'.".format("Check_For_New_Releases_On_Startup_checkBox",
												foundations.common.getFirstItem(checkForNewReleasesOnStartup.toInt())))
		self.Check_For_New_Releases_On_Startup_checkBox.setCheckState(
		foundations.common.getFirstItem(checkForNewReleasesOnStartup.toInt()))

	def __Check_For_New_Releases_On_Startup_checkBox__stateChanged(self, state):
		"""
		Defines the slot triggered by **Check_For_New_Releases_On_Startup_checkBox** Widget when state changed.

		:param state: Checkbox state.
		:type state: int
		"""

		LOGGER.debug("> Check for new releases on startup state: '{0}'.".format(state))
		self.__settings.setKey(self.__settingsSection, "checkForNewReleasesOnStartup", state)

	def __Ignore_Non_Existing_Templates_checkBox_setUi(self):
		"""
		Sets the **Ignore_Non_Existing_Templates_checkBox** Widget.
		"""

		# Adding settings key if it doesn't exists.
		self.__settings.getKey(self.__settingsSection, "ignoreNonExistingTemplates").isNull() and \
		self.__settings.setKey(self.__settingsSection, "ignoreNonExistingTemplates", Qt.Checked)

		ignoreNonExistingTemplates = self.__settings.getKey(self.__settingsSection, "ignoreNonExistingTemplates")
		LOGGER.debug("> Setting '{0}' with value '{1}'.".format("Ignore_Non_Existing_Templates_checkBox",
													foundations.common.getFirstItem(ignoreNonExistingTemplates.toInt())))
		self.Ignore_Non_Existing_Templates_checkBox.setCheckState(
		foundations.common.getFirstItem(ignoreNonExistingTemplates.toInt()))

	def __Ignore_Non_Existing_Templates_checkBox__stateChanged(self, state):
		"""
		Defines the slot triggered by **Ignore_Non_Existing_Templates_checkBox** Widget when state changed.

		:param state: Checkbox state.
		:type state: int
		"""

		LOGGER.debug("> Ignore non existing Templates state: '{0}'.".format(state))
		self.__settings.setKey(self.__settingsSection, "ignoreNonExistingTemplates", state)

	def __Check_For_New_Releases_pushButton__clicked(self, checked):
		"""
		Defines the slot triggered by **Check_For_New_Releases_pushButton** Widget when clicked.

		:param checked: Checked state.
		:type checked: bool
		"""

		self.checkForNewReleasesUi()

	@foundations.exceptions.handleExceptions(sibl_gui.exceptions.NetworkError)
	def __releasesFileReply__finished(self):
		"""
		Defines the slot triggered by the releases file reply when finished.
		"""

		self.__engine.stopProcessing()

		if not self.__releasesFileReply.error():
			content = []
			while not self.__releasesFileReply.atEnd ():
				content.append(foundations.strings.toString(self.__releasesFileReply.readLine()))

			LOGGER.debug("> Parsing releases file content.")
			sectionsFileParser = SectionsFileParser()
			sectionsFileParser.content = content
			sectionsFileParser.parse()

			releases = {}
			for remoteObject in sectionsFileParser.sections:
				if remoteObject != Constants.applicationName:
					databaseTemplates = \
					sibl_gui.components.core.database.operations.filterTemplates("^{0}$".format(remoteObject), "name")
					databaseTemplate = foundations.common.getFirstItem([foundations.common.getFirstItem(databaseTemplate)
												for databaseTemplate in sorted(((databaseTemplate, databaseTemplate.release)
												for databaseTemplate in databaseTemplates),
												reverse=True,
												key=lambda x:(foundations.strings.getVersionRank(x[1])))])
					if not self.__engine.parameters.databaseReadOnly:
						if databaseTemplate:
							if databaseTemplate.release != sectionsFileParser.getValue("Release", remoteObject):
								releases[remoteObject] = ReleaseObject(name=remoteObject,
																	repositoryVersion=sectionsFileParser.getValue(
																	"Release", remoteObject),
																	localVersion=databaseTemplate.release,
																	type=sectionsFileParser.getValue("Type",
																									remoteObject),
																	url=sectionsFileParser.getValue("Url",
																									remoteObject),
																	comment=sectionsFileParser.getValue("Comment",
																									remoteObject))
						else:
							if not self.Ignore_Non_Existing_Templates_checkBox.isChecked():
								releases[remoteObject] = ReleaseObject(name=remoteObject,
																	repositoryVersion=sectionsFileParser.getValue(
																	"Release", remoteObject),
																	localVersion=None,
																	type=sectionsFileParser.getValue("Type",
																									remoteObject),
																	url=sectionsFileParser.getValue("Url",
																									remoteObject),
																	comment=sectionsFileParser.getValue("Comment",
																									remoteObject))
					else:
						LOGGER.info("{0} | '{1}' repository remote object skipped by '{2}' command line parameter value!".format(
						self.__class__.__name__, remoteObject, "databaseReadOnly"))
				else:
					if Constants.version != sectionsFileParser.getValue("Release", remoteObject):
						releases[remoteObject] = ReleaseObject(name=remoteObject,
															repositoryVersion=sectionsFileParser.getValue("Release",
																										remoteObject),
															localVersion=Constants.version,
															url=sectionsFileParser.getValue("Url", remoteObject),
															type=sectionsFileParser.getValue("Type", remoteObject),
															comment=None)
			if releases:
				LOGGER.debug("> Initializing Remote Updater.")
				self.__remoteUpdater = RemoteUpdater(self, releases, Qt.Window)
				self.__remoteUpdater.show()
			else:
				self.__reportUpdateStatus and self.__engine.notificationsManager.notify(
				"{0} | '{1}' is up to date!".format(self.__class__.__name__, Constants.applicationName))
		else:
			raise sibl_gui.exceptions.NetworkError("{0} | QNetworkAccessManager error code: '{1}'.".format(
			self.__class__.__name__, self.__releasesFileReply.error()))

	def __getReleasesFile(self, url):
		"""
		Gets the releases file.
		"""

		LOGGER.debug("> Downloading '{0}' releases file.".format(url.path()))

		self.__engine.startProcessing("Retrieving Releases File ...")
		self.__releasesFileReply = self.__networkAccessManager.get(QNetworkRequest(url))
		self.__releasesFileReply.finished.connect(self.__releasesFileReply__finished)

	@foundations.exceptions.handleExceptions(umbra.exceptions.notifyExceptionHandler,
											sibl_gui.exceptions.NetworkError,
											Exception)
	def checkForNewReleasesUi(self):
		"""
		Checks for new releases.

		:return: Method success.
		:rtype: bool

		:note: May require user interaction.
		"""

		if not self.__networkAccessManager.networkAccessible():
			raise sibl_gui.exceptions.NetworkError("{0} | Network is not accessible!".format(self.__class__.__name__))

		self.__reportUpdateStatus = True
		if self.checkForNewReleases():
			return True
		else:
			raise Exception("{0} | Exception raised while checking for new releases!".format(self.__class__.__name__))

	@foundations.exceptions.handleExceptions(sibl_gui.exceptions.NetworkError, Exception)
	def checkForNewReleases(self):
		"""
		Checks for new releases.

		:return: Method success.
		:rtype: bool
		"""

		if not self.__networkAccessManager.networkAccessible():
			raise sibl_gui.exceptions.NetworkError("{0} | Network is not accessible!".format(self.__class__.__name__))

		self.__getReleasesFile(QUrl(os.path.join(self.__repositoryUrl, self.__releasesFileUrl)))
		return True
Пример #38
0
class AboutDialog(QDialog):
    """Dialog for showing info about TortoiseHg"""
    def __init__(self, parent=None):
        super(AboutDialog, self).__init__(parent)

        self.setWindowIcon(qtlib.geticon('thg_logo'))
        self.setWindowTitle(_('About'))
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)

        self.vbox = QVBoxLayout()
        self.vbox.setSpacing(8)

        self.logo_lbl = QLabel()
        self.logo_lbl.setMinimumSize(QSize(92, 50))
        self.logo_lbl.setScaledContents(False)
        self.logo_lbl.setAlignment(Qt.AlignCenter)
        thglogofile = paths.get_tortoise_icon('thg_logo_92x50.png')
        self.logo_lbl.setPixmap(QPixmap(thglogofile))
        self.vbox.addWidget(self.logo_lbl)

        self.name_version_libs_lbl = QLabel()
        self.name_version_libs_lbl.setText(' ')
        self.name_version_libs_lbl.setAlignment(Qt.AlignCenter)
        self.name_version_libs_lbl.setTextInteractionFlags(
            Qt.TextSelectableByMouse)
        self.vbox.addWidget(self.name_version_libs_lbl)
        self.getVersionInfo()

        self.copyright_lbl = QLabel()
        self.copyright_lbl.setAlignment(Qt.AlignCenter)
        self.copyright_lbl.setText(
            '\n' + _('Copyright 2008-2012 Steve Borho and others'))
        self.vbox.addWidget(self.copyright_lbl)
        self.courtesy_lbl = QLabel()
        self.courtesy_lbl.setAlignment(Qt.AlignCenter)
        self.courtesy_lbl.setText(
            _('Several icons are courtesy of the TortoiseSVN project') + '\n')
        self.vbox.addWidget(self.courtesy_lbl)

        self.download_url_lbl = QLabel()
        self.download_url_lbl.setAlignment(Qt.AlignCenter)
        self.download_url_lbl.setMouseTracking(True)
        self.download_url_lbl.setAlignment(Qt.AlignCenter)
        self.download_url_lbl.setTextInteractionFlags(
            Qt.LinksAccessibleByMouse)
        self.download_url_lbl.setOpenExternalLinks(True)
        self.download_url_lbl.setText(
            '<a href=%s>%s</a>' %
            ('http://tortoisehg.org', _('You can visit our site here')))
        self.vbox.addWidget(self.download_url_lbl)

        # Let's have some space between the url and the buttons.
        self.blancline_lbl = QLabel()
        self.vbox.addWidget(self.blancline_lbl)

        self.hbox = QHBoxLayout()
        self.license_btn = QPushButton()
        self.license_btn.setText(_('&License'))
        self.license_btn.setAutoDefault(False)
        self.license_btn.clicked.connect(self.showLicense)
        self.hspacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                   QSizePolicy.Minimum)
        self.close_btn = QPushButton()
        self.close_btn.setText(_('&Close'))
        self.close_btn.setDefault(True)
        self.close_btn.clicked.connect(self.close)
        self.hbox.addWidget(self.license_btn)
        self.hbox.addItem(self.hspacer)
        self.hbox.addWidget(self.close_btn)
        self.vbox.addLayout(self.hbox)

        self.setLayout(self.vbox)
        self.layout().setSizeConstraint(QLayout.SetFixedSize)
        self._readsettings()

        # Spawn it later, so that the dialog gets visible quickly.
        QTimer.singleShot(0, self.getUpdateInfo)
        self._newverreply = None

    def getVersionInfo(self):
        def make_version(tuple):
            vers = ".".join([str(x) for x in tuple])
            return vers

        thgv = (_('version %s') % version.version())
        libv = (_('with Mercurial-%s, Python-%s, PyQt-%s, Qt-%s') % \
              (hglib.hgversion, make_version(sys.version_info[0:3]),
              PYQT_VERSION_STR, QT_VERSION_STR))
        par = ('<p style=\" margin-top:0px; margin-bottom:6px;\">'
               '<span style=\"font-size:%spt; font-weight:600;\">'
               '%s</span></p>')
        name = (par % (14, 'TortoiseHg'))
        thgv = (par % (10, thgv))
        nvl = ''.join([name, thgv, libv])
        self.name_version_libs_lbl.setText(nvl)

    @pyqtSlot()
    def getUpdateInfo(self):
        verurl = 'http://tortoisehg.bitbucket.org/curversion.txt'
        # If we use QNetworkAcessManager elsewhere, it should be shared
        # through the application.
        self._netmanager = QNetworkAccessManager(self)
        self._newverreply = self._netmanager.get(QNetworkRequest(QUrl(verurl)))
        self._newverreply.finished.connect(self.uFinished)

    @pyqtSlot()
    def uFinished(self):
        newver = (0, 0, 0)
        try:
            f = self._newverreply.readAll().data().splitlines()
            self._newverreply.close()
            self._newverreply = None
            newver = tuple([int(p) for p in f[0].split('.')])
            upgradeurl = f[1]  # generic download URL
            platform = sys.platform
            if platform == 'win32':
                from win32process import IsWow64Process as IsX64
                platform = IsX64() and 'x64' or 'x86'
            # linux2 for Linux, darwin for OSX
            for line in f[2:]:
                p, _url = line.split(':', 1)
                if platform == p:
                    upgradeurl = _url.strip()
                    break
        except (IndexError, ImportError, ValueError):
            pass
        try:
            thgv = version.version()
            if '+' in thgv:
                thgv = thgv[:thgv.index('+')]
            curver = tuple([int(p) for p in thgv.split('.')])
        except ValueError:
            curver = (0, 0, 0)
        if newver > curver:
            url_lbl = _('A new version of TortoiseHg is ready for download!')
            urldata = ('<a href=%s>%s</a>' % (upgradeurl, url_lbl))
            self.download_url_lbl.setText(urldata)

    def showLicense(self):
        from tortoisehg.hgqt import license
        ld = license.LicenseDialog(self)
        ld.show()

    def closeEvent(self, event):
        if self._newverreply:
            self._newverreply.abort()
        self._writesettings()
        super(AboutDialog, self).closeEvent(event)

    def _readsettings(self):
        s = QSettings()
        self.restoreGeometry(s.value('about/geom').toByteArray())

    def _writesettings(self):
        s = QSettings()
        s.setValue('about/geom', self.saveGeometry())
Пример #39
0
class WebClient(BaseWebClient):
    """A webclient with a qtnetwork backend."""

    proxy_instance = None

    def __init__(self, *args, **kwargs):
        """Initialize this instance."""
        super(WebClient, self).__init__(*args, **kwargs)
        self.nam = QNetworkAccessManager(QCoreApplication.instance())
        self.nam.finished.connect(self._handle_finished)
        self.nam.authenticationRequired.connect(self._handle_authentication)
        self.nam.proxyAuthenticationRequired.connect(self.handle_proxy_auth)
        self.nam.sslErrors.connect(self._handle_ssl_errors)
        self.replies = {}
        self.proxy_retry = False
        self.setup_proxy()

        # Force Qt to load the system certificates
        QSslSocket.setDefaultCaCertificates(QSslSocket.systemCaCertificates())
        # Apply our local certificates as the SSL configuration to be used
        # for all QNetworkRequest calls.
        self.ssl_config = QSslConfiguration.defaultConfiguration()
        ca_certs = self.ssl_config.caCertificates()
        try:
            for path in glob.glob(
                    os.path.join(get_cert_dir(), "UbuntuOne*.pem")):
                with open(path) as f:
                    cert = QSslCertificate(f.read())
                    if cert.isValid():
                        ca_certs.append(cert)
                    else:
                        logger.error("invalid certificate: {}".format(path))
        except (IndexError, IOError) as err:
            raise WebClientError(
                "Unable to configure SSL certificates: {}".format(err))

        self.ssl_config.setCaCertificates(ca_certs)

    def _set_proxy(self, proxy):
        """Set the proxy to be used."""
        QNetworkProxy.setApplicationProxy(proxy)
        self.nam.setProxy(proxy)

    def setup_proxy(self):
        """Setup the proxy settings if needed."""
        # QtNetwork knows how to use the system settings on both Win and Mac
        if sys.platform.startswith("linux"):
            settings = gsettings.get_proxy_settings()
            enabled = len(settings) > 0
            if enabled and WebClient.proxy_instance is None:
                proxy = build_proxy(settings)
                self._set_proxy(proxy)
                WebClient.proxy_instance = proxy
            elif enabled and WebClient.proxy_instance:
                logger.info("Proxy already in use.")
            else:
                logger.info("Proxy is disabled.")
        else:
            if WebClient.proxy_instance is None:
                logger.info("Querying OS for proxy.")
                QNetworkProxyFactory.setUseSystemConfiguration(True)

    def handle_proxy_auth(self, proxy, authenticator):
        """Proxy authentication is required."""
        logger.info("auth_required %r, %r", self.proxy_username,
                    proxy.hostName())
        if (self.proxy_username is not None
                and self.proxy_username != str(authenticator.user())):
            authenticator.setUser(self.proxy_username)
            WebClient.proxy_instance.setUser(self.proxy_username)
        if (self.proxy_password is not None
                and self.proxy_password != str(authenticator.password())):
            authenticator.setPassword(self.proxy_password)
            WebClient.proxy_instance.setPassword(self.proxy_password)

    def _perform_request(self, request, method, post_buffer):
        """Return a deferred that will be fired with a Response object."""
        d = defer.Deferred()
        if method == "GET":
            reply = self.nam.get(request)
        elif method == "HEAD":
            reply = self.nam.head(request)
        else:
            reply = self.nam.sendCustomRequest(request, method, post_buffer)
        self.replies[reply] = d
        return d

    @defer.inlineCallbacks
    def request(self,
                iri,
                method="GET",
                extra_headers=None,
                oauth_credentials=None,
                post_content=None):
        """Return a deferred that will be fired with a Response object."""
        uri = self.iri_to_uri(iri)
        request = QNetworkRequest(QUrl(uri))
        request.setSslConfiguration(self.ssl_config)
        headers = yield self.build_request_headers(uri, method, extra_headers,
                                                   oauth_credentials)

        for key, value in headers.items():
            request.setRawHeader(key, value)

        post_buffer = QBuffer()
        post_buffer.setData(post_content)
        try:
            result = yield self._perform_request(request, method, post_buffer)
        except ProxyUnauthorizedError as e:
            app_proxy = QNetworkProxy.applicationProxy()
            proxy_host = app_proxy.hostName() if app_proxy else "proxy server"
            got_creds = yield self.request_proxy_auth_credentials(
                proxy_host, self.proxy_retry)
            if got_creds:
                self.proxy_retry = True
                result = yield self.request(iri, method, extra_headers,
                                            oauth_credentials, post_content)
            else:
                excp = WebClientError('Proxy creds needed.', e)
                defer.returnValue(excp)
        defer.returnValue(result)

    def _handle_authentication(self, reply, authenticator):
        """The reply needs authentication."""
        if authenticator.user() != self.username:
            authenticator.setUser(self.username)
        if authenticator.password() != self.password:
            authenticator.setPassword(self.password)

    def _handle_finished(self, reply):
        """The reply has finished processing."""
        assert reply in self.replies
        d = self.replies.pop(reply)
        error = reply.error()
        content = reply.readAll()
        if not error:
            headers = HeaderDict()
            for key, value in reply.rawHeaderPairs():
                headers[str(key)].append(str(value))
            response = Response(bytes(content), headers)
            d.callback(response)
        else:
            content = unicode(content)
            error_string = unicode(reply.errorString())
            logger.debug('_handle_finished error (%s,%s).', error,
                         error_string)
            if error == QNetworkReply.AuthenticationRequiredError:
                exception = UnauthorizedError(error_string, content)
            elif error == QNetworkReply.ProxyAuthenticationRequiredError:
                # we are going thru a proxy and we did not auth
                exception = ProxyUnauthorizedError(error_string, content)
            else:
                exception = WebClientError(error_string, content)
            d.errback(exception)

    def _get_certificate_details(self, cert):
        """Return an string with the details of the certificate."""
        detail_titles = {
            QSslCertificate.Organization: 'organization',
            QSslCertificate.CommonName: 'common_name',
            QSslCertificate.LocalityName: 'locality_name',
            QSslCertificate.OrganizationalUnitName: 'unit',
            QSslCertificate.CountryName: 'country_name',
            QSslCertificate.StateOrProvinceName: 'state_name'
        }
        details = {}
        for info, title in detail_titles.items():
            details[title] = str(cert.issuerInfo(info))
        return self.format_ssl_details(details)

    def _get_certificate_host(self, cert):
        """Return the host of the cert."""
        return str(cert.issuerInfo(QSslCertificate.CommonName))

    def _handle_ssl_errors(self, reply, errors):
        """Handle the case in which we got an ssl error."""
        msg = StringIO()
        msg.write('SSL errors found; url: %s\n' %
                  reply.request().url().toString())
        for error in errors:
            msg.write('========Error=============\n%s (%s)\n' %
                      (error.errorString(), error.error()))
            msg.write('--------Cert Details------\n%s\n' %
                      self._get_certificate_details(error.certificate()))
            msg.write('==========================\n')
        logger.error(msg.getvalue())

    def force_use_proxy(self, https_settings):
        """Setup this webclient to use the given proxy settings."""
        settings = {"https": https_settings}
        proxy = build_proxy(settings)
        self._set_proxy(proxy)
        WebClient.proxy_instance = proxy

    def shutdown(self):
        """Shut down all pending requests (if possible)."""
        self.nam.deleteLater()
Пример #40
0
class AboutDialog(QDialog):
    """Dialog for showing info about TortoiseHg"""

    def __init__(self, parent=None):
        super(AboutDialog, self).__init__(parent)

        self.setWindowIcon(qtlib.geticon('thg_logo'))
        self.setWindowTitle(_('About'))
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

        self.vbox = QVBoxLayout()
        self.vbox.setSpacing(8)

        self.logo_lbl = QLabel()
        self.logo_lbl.setMinimumSize(QSize(92, 50))
        self.logo_lbl.setScaledContents(False)
        self.logo_lbl.setAlignment(Qt.AlignCenter)
        thglogofile = paths.get_tortoise_icon('thg_logo_92x50.png')
        self.logo_lbl.setPixmap(QPixmap(thglogofile))
        self.vbox.addWidget(self.logo_lbl)

        self.name_version_libs_lbl = QLabel()
        self.name_version_libs_lbl.setText(' ')
        self.name_version_libs_lbl.setAlignment(Qt.AlignCenter)
        self.name_version_libs_lbl.setTextInteractionFlags(
                Qt.TextSelectableByMouse)
        self.vbox.addWidget(self.name_version_libs_lbl)
        self.getVersionInfo()

        self.copyright_lbl = QLabel()
        self.copyright_lbl.setAlignment(Qt.AlignCenter)
        self.copyright_lbl.setText('\n'
                + _('Copyright 2008-2013 Steve Borho and others'))
        self.vbox.addWidget(self.copyright_lbl)
        self.courtesy_lbl = QLabel()
        self.courtesy_lbl.setAlignment(Qt.AlignCenter)
        self.courtesy_lbl.setText(
              _('Several icons are courtesy of the TortoiseSVN project') + '\n')
        self.vbox.addWidget(self.courtesy_lbl)

        self.download_url_lbl = QLabel()
        self.download_url_lbl.setMouseTracking(True)
        self.download_url_lbl.setAlignment(Qt.AlignCenter)
        self.download_url_lbl.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.download_url_lbl.setOpenExternalLinks(True)
        self.download_url_lbl.setText('<a href=%s>%s</a>' %
                ('http://tortoisehg.org', _('You can visit our site here')))
        self.vbox.addWidget(self.download_url_lbl)

        # Let's have some space between the url and the buttons.
        self.blancline_lbl = QLabel()
        self.vbox.addWidget(self.blancline_lbl)

        self.hbox = QHBoxLayout()
        self.license_btn = QPushButton()
        self.license_btn.setText(_('&License'))
        self.license_btn.setAutoDefault(False)
        self.license_btn.clicked.connect(self.showLicense)
        self.hspacer = QSpacerItem(40, 20,
                QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.close_btn = QPushButton()
        self.close_btn.setText(_('&Close'))
        self.close_btn.setDefault(True)
        self.close_btn.clicked.connect(self.close)
        self.hbox.addWidget(self.license_btn)
        self.hbox.addItem(self.hspacer)
        self.hbox.addWidget(self.close_btn)
        self.vbox.addLayout(self.hbox)

        self.setLayout(self.vbox)
        self.layout().setSizeConstraint(QLayout.SetFixedSize)
        self._readsettings()

        # Spawn it later, so that the dialog gets visible quickly.
        QTimer.singleShot(0, self.getUpdateInfo)
        self._newverreply = None

    def getVersionInfo(self):
        def make_version(tuple):
            vers = ".".join([str(x) for x in tuple])
            return vers
        thgv = (_('version %s') % version.version())
        libv = (_('with Mercurial-%s, Python-%s, PyQt-%s, Qt-%s') % \
              (hglib.hgversion, make_version(sys.version_info[0:3]),
              PYQT_VERSION_STR, QT_VERSION_STR))
        par = ('<p style=\" margin-top:0px; margin-bottom:6px;\">'
                '<span style=\"font-size:%spt; font-weight:600;\">'
                '%s</span></p>')
        name = (par % (14, 'TortoiseHg'))
        thgv = (par % (10, thgv))
        nvl = ''.join([name, thgv, libv])
        self.name_version_libs_lbl.setText(nvl)

    @pyqtSlot()
    def getUpdateInfo(self):
        verurl = 'http://tortoisehg.bitbucket.org/curversion.txt'
        # If we use QNetworkAcessManager elsewhere, it should be shared
        # through the application.
        self._netmanager = QNetworkAccessManager(self)
        self._newverreply = self._netmanager.get(QNetworkRequest(QUrl(verurl)))
        self._newverreply.finished.connect(self.uFinished)

    @pyqtSlot()
    def uFinished(self):
        newver = (0,0,0)
        try:
            f = self._newverreply.readAll().data().splitlines()
            self._newverreply.close()
            self._newverreply = None
            newver = tuple([int(p) for p in f[0].split('.')])
            upgradeurl = f[1] # generic download URL
            platform = sys.platform
            if platform == 'win32':
                from win32process import IsWow64Process as IsX64
                platform = IsX64() and 'x64' or 'x86'
            # linux2 for Linux, darwin for OSX
            for line in f[2:]:
                p, _url = line.split(':', 1)
                if platform == p:
                    upgradeurl = _url.strip()
                    break
        except (IndexError, ImportError, ValueError):
            pass
        try:
            thgv = version.version()
            if '+' in thgv:
                thgv = thgv[:thgv.index('+')]
            curver = tuple([int(p) for p in thgv.split('.')])
        except ValueError:
            curver = (0,0,0)
        if newver > curver:
            url_lbl = _('A new version of TortoiseHg is ready for download!')
            urldata = ('<a href=%s>%s</a>' % (upgradeurl, url_lbl))
            self.download_url_lbl.setText(urldata)

    def showLicense(self):
        from tortoisehg.hgqt import license
        ld = license.LicenseDialog(self)
        ld.show()

    def closeEvent(self, event):
        if self._newverreply:
            self._newverreply.abort()
        self._writesettings()
        super(AboutDialog, self).closeEvent(event)

    def _readsettings(self):
        s = QSettings()
        self.restoreGeometry(s.value('about/geom').toByteArray())

    def _writesettings(self):
        s = QSettings()
        s.setValue('about/geom', self.saveGeometry())
Пример #41
0
class SogisBrowserDock(QDockWidget, Ui_SogisBrowserDock):
    def __init__(self, parent=None):
        """Constructor."""
        QDockWidget.__init__(self, parent)
        self.setupUi(self)
        
        self.SEARCH_URL = "http://www.catais.org/wsgi/search_metadb_sogis.wsgi?query="

        self.toolButtonReset.setIcon(QIcon(':/plugins/sogisbrowser/icons/reset.svg'))

        today = QDateTime.currentDateTime()
        self.dateEdit.setDateTime(today)
        self.dateEdit.setCalendarPopup(True)
        
        self.treeWidget = SogisBrowserTreeWidget()
        self.gridLayout.addWidget(self.treeWidget)
        
#        self.dateEdit.setLocale(QLocale(QLocale.German));  # Qt Designer
        
        font = QFont()
        font.setPointSize(10)
        self.treeWidget.setFont(font)

        self.networkManager = QNetworkAccessManager(self)
        self.connect(self.networkManager, SIGNAL("finished(QNetworkReply*)"), self.handleNetworkData)
        
        QObject.connect(self.toolButtonReset, SIGNAL("clicked()"), self.resetSuggest)

    def initGui(self):
        request = QNetworkRequest(QUrl(self.SEARCH_URL))
        self.networkManager.get(request)
        
    def handleNetworkData(self, networkReply):    
        url = networkReply.url()
        if not networkReply.error():
            displaytext = []
            category = []
            meta_id = []
            
            response = networkReply.readAll()

            try:
                my_response = unicode(response)
                json_response = json.loads(my_response, object_pairs_hook=collections.OrderedDict) 
            except Exception:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                QMessageBox.critical(None, "SO!GIS Browser", "Failed to load json response" + str(traceback.format_exc(exc_traceback)))                                    
                return
                
            print json_response
            
            for result in json_response['results']:
                displaytext.append(result['displaytext'])
                category.append(result['category'])
                meta_id.append(result['meta_id'])
            
            self.showSearchResult(displaytext, category, meta_id)

    def showSearchResult(self, displaytext, category, meta_id):
        if len(displaytext) == 0:
            return False
            
        pal = self.palette()
        color  = pal.color(QPalette.Disabled, QPalette.WindowText)

        self.treeWidget.setUpdatesEnabled(False)
        self.treeWidget.clear()

        for  i in range(len(displaytext)):
            item = QTreeWidgetItem(self.treeWidget)
            item.setText(0, displaytext[i])
            item.setToolTip(0, displaytext[i])
            
            item.setText(1, category[i])
            item.setTextAlignment(1, Qt.AlignRight)            
            item.setTextColor(1, color)
            
            item.setData(2, Qt.UserRole, meta_id[i])

        self.treeWidget.setUpdatesEnabled(True)

    def resetSuggest(self):
        self.treeWidget.clearSelection()
Пример #42
0
class ImageFetcher(QObject):

    fetchComplete = pyqtSignal(QByteArray, int)

    def __init__(self):
        QObject.__init__(self)

        self.settings_folder = ComicTaggerSettings.getSettingsFolder()
        self.db_file = os.path.join(self.settings_folder, "image_url_cache.db")
        self.cache_folder = os.path.join(self.settings_folder, "image_cache")

        if not os.path.exists(self.db_file):
            self.create_image_db()

    def clearCache(self):
        os.unlink(self.db_file)
        if os.path.isdir(self.cache_folder):
            shutil.rmtree(self.cache_folder)

    def fetch(self, url, user_data=None, blocking=False):
        """
		If called with blocking=True, this will block until the image is 
		fetched.
		
		If called with blocking=False, this will run the fetch in the 
		background, and emit a signal when done
		"""

        self.user_data = user_data
        self.fetched_url = url

        # first look in the DB
        image_data = self.get_image_from_cache(url)

        if blocking:
            if image_data is None:
                try:
                    image_data = urllib.urlopen(url).read()
                except Exception as e:
                    print e
                    raise ImageFetcherException("Network Error!")

            # save the image to the cache
            self.add_image_to_cache(self.fetched_url, image_data)
            return image_data

        else:

            # if we found it, just emit the signal asap
            if image_data is not None:
                self.fetchComplete.emit(QByteArray(image_data), self.user_data)
                return

            # didn't find it.  look online
            self.nam = QNetworkAccessManager()
            self.nam.finished.connect(self.finishRequest)
            self.nam.get(QNetworkRequest(QUrl(url)))

            #we'll get called back when done...

    def finishRequest(self, reply):

        # read in the image data
        image_data = reply.readAll()

        # save the image to the cache
        self.add_image_to_cache(self.fetched_url, image_data)

        self.fetchComplete.emit(QByteArray(image_data), self.user_data)

    def create_image_db(self):

        # this will wipe out any existing version
        open(self.db_file, 'w').close()

        # wipe any existing image cache folder too
        if os.path.isdir(self.cache_folder):
            shutil.rmtree(self.cache_folder)
        os.makedirs(self.cache_folder)

        con = lite.connect(self.db_file)

        # create tables
        with con:

            cur = con.cursor()

            cur.execute("CREATE TABLE Images(" + "url TEXT," +
                        "filename TEXT," + "timestamp TEXT," +
                        "PRIMARY KEY (url) )")

    def add_image_to_cache(self, url, image_data):

        con = lite.connect(self.db_file)

        with con:

            cur = con.cursor()

            timestamp = datetime.datetime.now()

            tmp_fd, filename = tempfile.mkstemp(dir=self.cache_folder,
                                                prefix="img")
            f = os.fdopen(tmp_fd, 'w+b')
            f.write(image_data)
            f.close()

            cur.execute("INSERT or REPLACE INTO Images VALUES( ?, ?, ? )",
                        (url, filename, timestamp))

    def get_image_from_cache(self, url):

        con = lite.connect(self.db_file)
        with con:
            cur = con.cursor()

            cur.execute("SELECT filename FROM Images WHERE url=?", [url])
            row = cur.fetchone()

            if row is None:
                return None
            else:
                filename = row[0]
                image_data = None

                try:
                    with open(filename, 'rb') as f:
                        image_data = f.read()
                        f.close()
                except IOError as e:
                    pass

                return image_data
Пример #43
0
class downloadManager(QtCore.QObject):
    ''' This class allows downloading stuff in the background'''
    
    def __init__(self, parent = None):
        self.client = parent
        self.nam = QNetworkAccessManager()
        
        self.nam.finished.connect(self.finishedDownload)

        self.modRequests = {}
        self.mapRequests = {}
        self.mapRequestsItem = []
        
    def finishedDownload(self,reply):
        ''' finishing downloads '''
        urlstring = reply.url().toString()
        reqlist = []
        if urlstring in self.mapRequests: reqlist = self.mapRequests[urlstring]
        if urlstring in self.modRequests: reqlist = self.modRequests[urlstring]
        if reqlist:
            #save the map from cache
            name = os.path.basename(reply.url().toString())
            pathimg = os.path.join(util.CACHE_DIR, name)
            img = QtCore.QFile(pathimg)
            img.open(QtCore.QIODevice.WriteOnly)
            img.write(reply.readAll())
            img.close()
            if os.path.exists(pathimg):
                #Create alpha-mapped preview image
                try:
                    pass # the server already sends 100x100 pic
#                    img = QtGui.QImage(pathimg).scaled(100,100)
#                    img.save(pathimg)
                except:
                    pathimg = "games/unknown_map.png"
                    logger.info("Failed to resize " + name)
            else :
                pathimg = "games/unknown_map.png"
                logger.debug("Web Preview failed for: " + name)
            logger.debug("Web Preview used for: " + name)
            for requester in reqlist:
                if requester:
                    if requester in self.mapRequestsItem:
                        requester.setIcon(0, util.icon(pathimg, False))
                        self.mapRequestsItem.remove(requester)
                    else:
                        requester.setIcon(util.icon(pathimg, False))
            if urlstring in self.mapRequests: del self.mapRequests[urlstring]
            if urlstring in self.modRequests: del self.modRequests[urlstring]
            
    def downloadMap(self, name, requester, item=False):
        '''
        Downloads a preview image from the web for the given map name
        '''
        #This is done so generated previews always have a lower case name. This doesn't solve the underlying problem (case folding Windows vs. Unix vs. FAF)
        name = name.lower()
        if len(name) == 0:
            return
        

        url = QtCore.QUrl(VAULT_PREVIEW_ROOT + urllib2.quote(name) + ".png")
        if not url.toString() in self.mapRequests:
            logger.debug("Searching map preview for: " + name)
            self.mapRequests[url.toString()] = []
            request = QNetworkRequest(url)
            self.nam.get(request)
            self.mapRequests[url.toString()].append(requester)
        else :
            self.mapRequests[url.toString()].append(requester)
        if item:
            self.mapRequestsItem.append(requester)

    def downloadModPreview(self, strurl, requester):
        url = QtCore.QUrl(strurl)
        if not url.toString() in self.modRequests:
            logger.debug("Searching mod preview for: " + os.path.basename(strurl).rsplit('.',1)[0])
            self.modRequests[url.toString()] = []
            request = QNetworkRequest(url)
            self.nam.get(request)
        self.modRequests[url.toString()].append(requester)
Пример #44
0
class MapTileHTTPLoader(QObject):

    tileLoaded = pyqtSignal(int, int, int, QByteArray)

    def __init__(self, cacheSize=1024*1024*100, userAgent='(PyQt) TileMap 1.2', parent=None):
        QObject.__init__(self, parent=parent)
        self._manager = None
        self._cache = None
        self._cacheSize = cacheSize
        self._userAgent = userAgent
        self._tileInDownload = dict()

    @pyqtSlot(int, int, int, str)
    def loadTile(self, x, y, zoom, url):
        if self._manager is None:
            self._manager = QNetworkAccessManager(parent=self)
            self._manager.finished.connect(self.handleNetworkData)
            self._cache = MapTileHTTPCache(maxSize=self._cacheSize, parent=self)

        key = (x, y, zoom)
        url = QUrl(url)
        if url in self._cache:
            # print('from cache')
            data = self._cache[url]
            self.tileLoaded.emit(x, y, zoom, data)
        elif key in self._tileInDownload:
            # Image is already in download... return
            return
        else:
            request = QNetworkRequest(url=url)
            request.setRawHeader('User-Agent', self._userAgent)
            request.setAttribute(QNetworkRequest.User, key)
            self._tileInDownload[key] = self._manager.get(request)

        # print('In download:', len(self._tileInDownload))

    @pyqtSlot(QNetworkReply)
    def handleNetworkData(self, reply):
        tp = reply.request().attribute(QNetworkRequest.User)  # .toPyObject()
        if tp in self._tileInDownload:
            del self._tileInDownload[tp]

        if not reply.error():
            data = reply.readAll()
            self._cache[reply.request().url()] = data
            self.tileLoaded.emit(tp[0], tp[1], tp[2], data)
        reply.close()
        reply.deleteLater()

    @pyqtSlot()
    def abortRequest(self, x, y, zoom):
        p = (x, y, zoom)
        reply = self._tileInDownload[p]
        del self._tileInDownload[p]
        reply.close()
        reply.deleteLater()

    @pyqtSlot()
    def abortAllRequests(self):
        for x, y, zoom in list(self._tileInDownload.keys()):
            self.abortRequest(x, y, zoom)
class GasWmtsLayer(QObject):
    def __init__(self, iface, data, fallback = False):
        QObject.__init__(self)
        
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.fallback = fallback
        
        self.settings = QSettings("CatAIS","GeoAdminSearch")
        
        self.wmtsCapabilitities = self.settings.value("services/wmtscapabilities", "http://api3.geo.admin.ch/rest/services/api/1.0.0/WMTSCapabilities.xml")
        
        self.settings = QSettings("CatAIS","GeoAdminSearch")
        searchLanguage = self.settings.value("options/language", "de")
        self.userName = self.settings.value("options/username", "")
        self.password = self.settings.value("options/password", "")

        self.layerName = data['layer']
        
        url = self.wmtsCapabilitities

        # It does not work:
        # a) when networkAccess is not 'self'
        # b) without lambda
        self.networkAccess = QNetworkAccessManager()         
        self.connect(self.networkAccess, SIGNAL("finished(QNetworkReply*)"), lambda event, data=data: self.receiveWmtsCapabilities(event, data))
        self.networkAccess.get(QNetworkRequest(QUrl(url)))   
        
    def receiveWmtsCapabilities(self, networkReply, data):
        if not networkReply.error():
            response = networkReply.readAll()
            xml = QXmlStreamReader(response)
            while not xml.atEnd():
                token = xml.readNext()
                if token == QXmlStreamReader.StartDocument:
                    continue
                
                if token == QXmlStreamReader.StartElement:
                    if xml.name() == "Layer":
                        
                        identifier = None
                        format = None
                        time = None
                        tileMatrixSet = None

                        xml.readNext()
                        
                        while not (xml.tokenType() == QXmlStreamReader.EndElement and xml.name() == "Layer"):
                            if xml.tokenType() == QXmlStreamReader.StartElement:
                                
                                if xml.name() == "Identifier" and identifier == None:
                                    my_identifier =  xml.readElementText().strip()
                                    if my_identifier == self.layerName:
                                        identifier = my_identifier
                                
                                if xml.name() == "Format" and format == None:
                                     my_format = xml.readElementText().strip()
                                    
                                if xml.name() == "Dimension" and time == None:
                                    while not (xml.tokenType() == QXmlStreamReader.EndElement and xml.name() == "Dimension"):
                                        if xml.tokenType() == QXmlStreamReader.StartElement:
                                            if xml.name() == "Default":
                                                my_time = xml.readElementText().strip()
                                        xml.readNext()
                                     
                                if xml.name() == "TileMatrixSetLink" and tileMatrixSet == None:
                                    while not (xml.tokenType() == QXmlStreamReader.EndElement and xml.name() == "TileMatrixSetLink"):
                                        if xml.tokenType() == QXmlStreamReader.StartElement:
                                            if xml.name() == "TileMatrixSet":
                                                my_tileMatrixSet = xml.readElementText().strip()
                                        xml.readNext()
                                     
                            xml.readNext()
                        
                        if identifier <> None:
                            format = my_format
                            time = my_time
                            tileMatrixSet = my_tileMatrixSet
                            break

        print "end of WMTSCapabilities.xml"
        print identifier

        if not identifier or not format or not time or not tileMatrixSet: 
            if not self.fallback:
                self.iface.messageBar().pushMessage("Warning",  _translate("GeoAdminSearch", "WMTS layer not found. Will try to add it as WMS layer.",  None), level=QgsMessageBar.WARNING, duration=5)                      
                self.emit(SIGNAL("wmtsLayerNotFound(QVariant, QString)"), data, "WMS")
                return
            else:
                self.iface.messageBar().pushMessage("Error",  _translate("GeoAdminSearch", "Not able to add WMS or WMTS layer.",  None), level=QgsMessageBar.CRITICAL, duration=5)                                      
                return

        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            headerFields = self.settings.value("options/headerfields")
            headerValues = self.settings.value("options/headervalues")
            referer =""
            if headerFields and headerValues:
                for i in range(len(headerFields)):
                    if headerFields[i] == "Referer":
                        referer = headerValues[i]
                        
            layerName = data['label'].replace('<b>', '').replace('</b>', '')
            
            if referer == "":
                uri = "crs=EPSG:21781&dpiMode=7&featureCount=10&format="+format+"&layers="+identifier+"&styles=&tileDimensions=Time%3D"+time+"&tileMatrixSet="+tileMatrixSet+"&url=" + self.wmtsCapabilitities
            else:
                uri = "crs=EPSG:21781&dpiMode=7&featureCount=10&format="+format+"&layers="+identifier+"&referer="+referer+"&styles=&tileDimensions=Time%3D"+time+"&tileMatrixSet="+tileMatrixSet+"&url=" + self.wmtsCapabilitities
            wmtsLayer = QgsRasterLayer (uri, layerName, "wms", False)      
            self.emit(SIGNAL("layerCreated(QgsMapLayer)"), wmtsLayer)

        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            print str(traceback.format_exc(exc_traceback))
            
            QApplication.restoreOverrideCursor()            
        QApplication.restoreOverrideCursor()      
Пример #46
0
class StakeholderProtocol(QObject):

    # SIGNAL that is emitted after stakeholders have been read
    readSignal = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after a new stakeholder has been added
    created = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after an existing activity has been updated
    updated = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after an activity has been deleted
    deleted = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after activities have been counted
    counted = pyqtSignal(bool, int, QString)

    def __init__(self, host, user, password):
        QObject.__init__(self)

        # Set the host
        self.host = host
        # Create a base64 encoded credential string from user name and password.
        # This is required for the HTTP basic access authentication, compare
        # also http://en.wikipedia.org/wiki/Basic_access_authentication
        self.userlogin = "******" % (user, password)
        self.login = "******" + QByteArray(self.userlogin).toBase64()

        # Create a new QNetworkAccessManager and connect it to the
        # authenticationRequired signal
        self.manager = QNetworkAccessManager(self)

        # self.connect(self.manager, SIGNAL("authenticationRequired( QNetworkReply*, QAuthenticator* )"), self.slotAuthenticationRequired)

    def read(self, **kwargs):

        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        params = []

        try:
            queryable = kwargs["queryable"]
            params.append({"queryable": queryable})
            queryableList = QString(queryable).split(",")
        except KeyError:
            pass

        for key, value in kwargs.items():
            if QString(key).split("__")[0] in queryableList:
                params.append({key: value})

        url = "%s/stakeholders?" % self.host
        for p in params:
            url = "%s%s=%s&" % (url, p.keys()[0], p.values()[0])

        qUrl = QUrl(url)
        # Create a new request
        request = QNetworkRequest(qUrl)
        request.setRawHeader("Authorization", self.login)
        request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")

        self.manager.get(request)

        return url

    def readRequestFinished(self, reply):
        # Get the HTTP status code from the reply

        self.disconnect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        # Check the status code see also http://en.wikipedia.org/wiki/HTTP_status_code
        # In case of a successful upload we get a 201 status code back and the
        # "stylePosted" signal is emitted with the first parameter set to True.
        # If the query didn't succeed, the status code is 4xx indicating that
        # the host was not found, the authentication failed or a forbidden
        # action in case a style with the same name already exists. It's up to
        # the receiver to handle these status codes.
        self.readSignal.emit(httpStatusCode in (200, 201), httpStatusCode, QString(reply.readAll()))

    def add(self, stakeholder):

        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        url = "%s/stakeholders" % self.host

        qurl = QUrl(url)
        # Create a new request
        request = QNetworkRequest(qurl)
        request.setRawHeader("Authorization", self.login)
        request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")

        wrapperObj = {}

        if len(stakeholder) > 0:
            wrapperObj["stakeholders"] = [s.createDiff(None) for s in stakeholder]
        else:
            wrapperObj["stakeholders"] = [stakeholder.createDiff(None)]

        rawBody = json.dumps(wrapperObj, sort_keys=True, indent=4 * " ")
        self.manager.post(request, rawBody)

        return url, rawBody

    def addRequestFinished(self, reply):

        self.disconnect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        self.created.emit(httpStatusCode in (200, 201), httpStatusCode, QString(reply.readAll()))
Пример #47
0
class MikiEdit(QTextEdit):
    def __init__(self, parent=None):
        super(MikiEdit, self).__init__(parent)
        self.parent = parent
        self.settings = parent.settings
        self.setFontPointSize(12)
        self.setVisible(False)
        self.ix = open_dir(self.settings.indexdir)

        # Spell checker support
        try:
            import enchant
            enchant.Dict()
            self.speller = enchant.Dict()
        except ImportError:
            print("Spell checking unavailable. Need to install pyenchant.")
            self.speller = None
        except enchant.errors.DictNotFoundError:
            print(
                "Spell checking unavailable. Need to install dictionary (e.g. aspell-en)."
            )
            self.speller = None

        self.imageFilter = ""
        self.documentFilter = ""
        for ext in self.settings.attachmentImage:
            self.imageFilter += " *" + ext
        for ext in self.settings.attachmentDocument:
            self.documentFilter += " *" + ext
        self.imageFilter = "Image (" + self.imageFilter.strip() + ")"
        self.documentFilter = "Document (" + self.documentFilter.strip() + ")"

        self.downloadAs = ""
        self.networkManager = QNetworkAccessManager()
        self.networkManager.finished.connect(self.downloadFinished)

    def updateIndex(self):
        ''' Update whoosh index, which cost much computing resource '''
        page = self.parent.notesTree.currentPage()
        content = self.toPlainText()
        try:
            #writer = self.ix.writer()
            writer = AsyncWriter(self.ix)
            if METADATA_CHECKER.match(
                    content) and 'meta' in self.settings.extensions:
                no_metadata_content = METADATA_CHECKER.sub("",
                                                           content,
                                                           count=1).lstrip()
                self.settings.md.reset().convert(content)
                writer.update_document(
                    path=page,
                    title=parseTitle(content, page),
                    content=no_metadata_content,
                    tags=','.join(self.settings.md.Meta.get('tags',
                                                            [])).strip())
                writer.commit()
            else:
                writer.update_document(path=page,
                                       title=parseTitle(content, page),
                                       content=content,
                                       tags='')
                writer.commit()
        except:
            print("Whoosh commit failed.")

    def downloadFinished(self, reply):
        if reply.error():
            print("Failed to download")
        else:
            attFile = QFile(self.downloadAs)
            attFile.open(QIODevice.WriteOnly)
            attFile.write(reply.readAll())
            attFile.close()
            print("Succeeded")
        reply.deleteLater()

    def mimeFromText(self, text):
        mime = QMimeData()
        mime.setText(text)
        return mime

    def createMimeDataFromSelection(self):
        """ Reimplement this to prevent copied text taken as hasHtml() """
        plaintext = self.textCursor().selectedText()

        # From QTextCursor doc:
        # if the selection obtained from an editor spans a line break,
        # the text will contain a Unicode U+2029 paragraph separator character
        # instead of a newline \n character
        text = plaintext.replace('\u2029', '\n')
        return self.mimeFromText(text)

    def insertFromMimeData(self, source):
        """ Intended behavior
        If copy/drag something that hasUrls, then check the extension name:
            if image then apply image pattern ![Alt text](/path/to/img.jpg)
                     else apply link  pattern [text](http://example.net)
        If copy/drag something that hasImage, then ask for file name
        If copy/drag something that hasHtml, then html2text
        Else use the default insertFromMimeData implementation
        """

        item = self.parent.notesTree.currentItem()
        attDir = self.parent.notesTree.itemToAttachmentDir(item)
        if not QDir(attDir).exists():
            QDir().mkpath(attDir)

        if source.hasUrls():
            for qurl in source.urls():
                url = qurl.toString()
                filename, extension = os.path.splitext(url)
                filename = os.path.basename(filename)
                newFilePath = os.path.join(attDir,
                                           filename + extension).replace(
                                               os.sep, '/')
                relativeFilePath = newFilePath.replace(
                    self.settings.notebookPath, "..")
                attachments = self.settings.attachmentImage + self.settings.attachmentDocument

                if QUrl(qurl).isLocalFile():
                    if extension.lower() in attachments:
                        nurl = url.replace("file://", "")
                        QFile.copy(nurl, newFilePath)
                        self.parent.updateAttachmentView()

                        if extension.lower() in self.settings.attachmentImage:
                            text = "![%s](%s)" % (filename, relativeFilePath)
                        elif extension.lower(
                        ) in self.settings.attachmentDocument:
                            text = "[%s%s](%s)\n" % (filename, extension,
                                                     relativeFilePath)
                    else:
                        text = "[%s%s](%s)\n" % (filename, extension, url)
                else:
                    if extension.lower() in attachments:
                        self.downloadAs = newFilePath
                        self.networkManager.get(QNetworkRequest(qurl))

                        if extension.lower() in self.settings.attachmentImage:
                            text = "![%s](%s)" % (filename, relativeFilePath)
                        elif extension.lower(
                        ) in self.settings.attachmentDocument:
                            text = "[%s%s](%s)\n" % (filename, extension,
                                                     relativeFilePath)
                    else:
                        text = "[%s%s](%s)\n" % (filename, extension, url)

                super(MikiEdit,
                      self).insertFromMimeData(self.mimeFromText(text))
        elif source.hasImage():
            img = source.imageData()
            attDir = self.parent.notesTree.itemToAttachmentDir(item)
            dialog = LineEditDialog(attDir, self)
            if dialog.exec_():
                fileName = dialog.editor.text()
                if not QFileInfo(fileName).suffix():
                    fileName += '.jpg'
                filePath = os.path.join(attDir, fileName).replace(os.sep, '/')
                img.save(filePath)
                relativeFilePath = filePath.replace(self.settings.notebookPath,
                                                    "..")
                text = "![%s](%s)" % (fileName, relativeFilePath)
                super(MikiEdit,
                      self).insertFromMimeData(self.mimeFromText(text))
        elif source.hasHtml():
            html = source.html()
            if HAS_HTML2TEXT:
                backToMarkdown = html2text.HTML2Text()
                markdown = backToMarkdown.handle(html)
                super(MikiEdit,
                      self).insertFromMimeData(self.mimeFromText(markdown))
            else:
                super(MikiEdit,
                      self).insertFromMimeData(self.mimeFromText(html))
        else:
            super(MikiEdit, self).insertFromMimeData(source)

    def insertAttachment(self, filePath, fileType):
        item = self.parent.notesTree.currentItem()
        attDir = self.parent.notesTree.itemToAttachmentDir(item)
        filename, extension = os.path.splitext(filePath)
        filename = os.path.basename(filename)
        newFilePath = os.path.join(attDir,
                                   filename + extension).replace(os.sep, '/')
        relativeFilePath = newFilePath.replace(self.settings.notebookPath,
                                               "..")
        if not os.path.exists(attDir):
            os.makedirs(attDir)
        QFile.copy(filePath, newFilePath)
        self.parent.updateAttachmentView()
        if fileType == self.imageFilter:
            text = "![%s](%s)" % (filename, relativeFilePath)
        else:
            text = "[%s%s](%s)\n" % (filename, extension, relativeFilePath)
        self.insertPlainText(text)

    def insertAttachmentWrapper(self):
        (filePath, fileType) = QFileDialog.getOpenFileNameAndFilter(
            self, self.tr('Insert attachment'), '',
            self.imageFilter + ";;" + self.documentFilter)
        if filePath == "":
            return
        self.insertAttachment(filePath, fileType)

    def contextMenuEvent(self, event):
        def correctWord(cursor, word):
            # From QTextCursor doc:
            # if there is a selection, the selection is deleted and replaced
            return lambda: cursor.insertText(word)

        popup_menu = self.createStandardContextMenu()

        # Spellcheck the word under mouse cursor, not self.textCursor
        cursor = self.cursorForPosition(event.pos())
        cursor.select(QTextCursor.WordUnderCursor)

        text = cursor.selectedText()
        if self.speller and text:
            if not self.speller.check(text):
                lastAction = popup_menu.actions()[0]
                for word in self.speller.suggest(text)[:10]:
                    action = QAction(word, popup_menu)
                    action.triggered.connect(correctWord(cursor, word))
                    action.setFont(QFont("sans", weight=QFont.Bold))
                    popup_menu.insertAction(lastAction, action)
                popup_menu.insertSeparator(lastAction)

        popup_menu.exec_(event.globalPos())

    def keyPressEvent(self, event):
        """ for Qt.Key_Tab, expand as 4 spaces
            for other keys, use default implementation
        """
        if event.key() == Qt.Key_Tab:
            self.insertPlainText('    ')
        else:
            QTextEdit.keyPressEvent(self, event)

    '''
    def closeEvent(self, event):
        self.ix.close()
        print('closed idx')
        event.accept()
    '''

    def save(self, item):
        pageName = self.parent.notesTree.itemToPage(item)
        filePath = self.parent.notesTree.itemToFile(item)
        htmlFile = self.parent.notesTree.itemToHtmlFile(item)

        fh = QFile(filePath)
        try:
            if not fh.open(QIODevice.WriteOnly):
                raise IOError(fh.errorString())
        except IOError as e:
            QMessageBox.warning(self, 'Save Error',
                                'Failed to save %s: %s' % (pageName, e))
            raise
        finally:
            if fh is not None:
                savestream = QTextStream(fh)
                savestream << self.toPlainText()
                fh.close()
                self.document().setModified(False)

                # Fork a process to update index, which benefit responsiveness.
                Thread(target=self.updateIndex).start()

    def toHtml(self):
        '''markdown.Markdown.convert v.s. markdown.markdown
            ~~Previously `convert` was used, but it doens't work with fenced_code~~
            fixed that by calling markdown.Markdown.reset before each conversion
        '''
        htmltext = self.toPlainText()
        if 'mdx_asciimathml' in self.settings.extensions:
            stuff = JSCRIPT_TPL.format(self.settings.mathjax)
        else:
            stuff = ''
        return self.settings.md.reset().convert(htmltext) + stuff
        # md = markdown.Markdown(extensions)
        # return md.convert(htmltext)

    def saveAsHtml(self, htmlFile=None):
        """ Save as Complete (with css and images) or HTML Only
            To be merged with saveNoteAs
        """
        if not htmlFile:
            (htmlFile, htmlType) = QFileDialog.getSaveFileNameAndFilter(
                self, self.tr("Export to HTML"), "", "Complete;;HTML Only")
        if htmlFile == '':
            return
        if not QFileInfo(htmlFile).suffix():
            htmlFile += '.html'

        if htmlType == "Complete":
            self.saveCompleteHtml(htmlFile)
        else:
            self.saveHtmlOnly(htmlFile)

    def saveCompleteHtml(self, htmlFile):
        html = QFile(htmlFile)
        html.open(QIODevice.WriteOnly)
        savestream = QTextStream(html)
        css = QFile(self.settings.cssfile)
        css.open(QIODevice.ReadOnly)
        # Use a html lib may be a better idea?
        savestream << "<html><head><meta charset='utf-8'></head>"
        # Css is inlined.
        savestream << "<style>"
        savestream << QTextStream(css).readAll()
        savestream << "</style>"
        # Note content
        savestream << self.toHtml()
        savestream << "</html>"
        html.close()

    def saveHtmlOnly(self, htmlFile):
        fileDir = os.path.dirname(htmlFile)
        QDir().mkpath(fileDir)

        html = QFile(htmlFile)
        html.open(QIODevice.WriteOnly)
        savestream = QTextStream(html)
        savestream << """
                      <html><head>
                        <meta charset="utf-8">
                        <link rel="stylesheet" href="/css/notebook.css" type="text/css" />
                      </head>
                      """
        # Note content
        savestream << self.toHtml()
        savestream << "</html>"
        html.close()
Пример #48
0
class ActivityProtocol(QObject):

    # SIGNAL that is emitted after activities have been read
    readSignal = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after a new activity has been added
    created = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after an existing activity has been updated
    updated = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after an activity has been deleted
    deleted = pyqtSignal(bool, int, QString)

    # SIGNAL that is emitted after activities have been counted
    counted = pyqtSignal(bool, int, QString)

    def __init__(self, host, user, password):
        QObject.__init__(self)

        # Set the host
        self.host = host
        # Create a base64 encoded credential string from user name and password.
        # This is required for the HTTP basic access authentication, compare
        # also http://en.wikipedia.org/wiki/Basic_access_authentication
        self.userlogin = "******" % (user, password)
        self.login = "******" + QByteArray(self.userlogin).toBase64()

        # Create a new QNetworkAccessManager and connect it to the
        # authenticationRequired signal
        self.manager = QNetworkAccessManager(self)
        # self.connect(self.manager, SIGNAL("authenticationRequired( QNetworkReply*, QAuthenticator* )"), self.slotAuthenticationRequired)

    def update(self, rawBody):
        """
        Update an activity using a POST request
        """
        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.updateRequestFinished)

        url = "%s/activities" % self.host
        qurl = QUrl(url)
        self.request = QNetworkRequest(qurl)
        self.request.setRawHeader("Authorization", self.login)
        self.request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")

        self.manager.post(self.request, QString(json.dumps(rawBody)).toUtf8())

        return url

    def updateRequestFinished(self, reply):
        self.disconnect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.updateRequestFinished)

        # Get the HTTP status code from the reply
        self.httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        # httpReasonPhrase = reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute).toString()

        data = reply.readAll()

        self.updated.emit(self.httpStatusCode in (200, 201), self.httpStatusCode, QString(data))

    def read(self, extent):
        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readRequestFinished)

        # Limit the longitude and latitutde maximum boundaries
        xmin = extent.xMinimum() if extent.xMinimum() >= -180 else -180
        ymin = extent.yMinimum() if extent.yMinimum() >= -90 else -90
        xmax = extent.xMaximum() if extent.xMaximum() <= 180 else 180
        ymax = extent.yMaximum() if extent.yMaximum() <= 90 else 90

        url = "%s/activities/json?bbox=%d,%d,%d,%d" % (self.host, xmin, ymin, xmax, ymax)

        qUrl = QUrl(url)
        self.request = QNetworkRequest(qUrl)
        self.request.setRawHeader("Authorization", self.login)

        self.request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")

        self.manager.get(self.request)

        return url

    def readRequestFinished(self, reply):
        # Get the HTTP status code from the reply
        self.httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        # data = str("a")
        data = reply.readAll()

        # Check the status code see also http://en.wikipedia.org/wiki/HTTP_status_code
        # In case of a successful upload we get a 201 status code back and the
        # "stylePosted" signal is emitted with the first parameter set to True.
        # If the query didn't succeed, the status code is 4xx indicating that
        # the host was not found, the authentication failed or a forbidden
        # action in case a style with the same name already exists. It's up to
        # the receiver to handle these status codes.
        self.readSignal.emit(self.httpStatusCode in (200, 201), self.httpStatusCode, QString(data))

    def readById(self, id):
        """

        """
        self.connect(self.manager, SIGNAL("finished( QNetworkReply* )"), self.readByIdRequestFinished)

        # Get the latest version of the activity with this id
        url = "%s/activities/json/%s?geometry=full" % (self.host, id)

        qUrl = QUrl(url)
        self.request = QNetworkRequest(qUrl)
        # self.request.setRawHeader("Authorization", self.login)

        self.manager.get(self.request)

        return url

    def readByIdRequestFinished(self, reply):

        # Get the HTTP status code from the reply
        self.httpStatusCode = int(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute).toString())

        data = reply.readAll()

        self.readSignal.emit(self.httpStatusCode in (200, 201), self.httpStatusCode, QString(data))
Пример #49
0
class ReplaysWidget(BaseClass, FormClass):
    SOCKET = 11002
    HOST = "lobby.faforever.com"

    def __init__(self, client):
        super(BaseClass, self).__init__()

        self.setupUi(self)

        #self.replayVault.setVisible(False)
        self.client = client
        client.replaysTab.layout().addWidget(self)

        client.gameInfo.connect(self.processGameInfo)
        client.replayVault.connect(self.replayVault)

        self.onlineReplays = {}
        self.onlineTree.setItemDelegate(ReplayItemDelegate(self))
        self.replayDownload = QNetworkAccessManager()
        self.replayDownload.finished.connect(self.finishRequest)

        # sending request to replay vault
        self.searchButton.pressed.connect(self.searchVault)
        self.playerName.returnPressed.connect(self.searchVault)
        self.mapName.returnPressed.connect(self.searchVault)

        self.myTree.itemDoubleClicked.connect(self.myTreeDoubleClicked)
        self.myTree.itemPressed.connect(self.myTreePressed)
        self.myTree.header().setResizeMode(0,
                                           QtGui.QHeaderView.ResizeToContents)
        self.myTree.header().setResizeMode(1,
                                           QtGui.QHeaderView.ResizeToContents)
        self.myTree.header().setResizeMode(2, QtGui.QHeaderView.Stretch)
        self.myTree.header().setResizeMode(3,
                                           QtGui.QHeaderView.ResizeToContents)

        self.liveTree.itemDoubleClicked.connect(self.liveTreeDoubleClicked)
        self.liveTree.itemPressed.connect(self.liveTreePressed)
        self.liveTree.header().setResizeMode(
            0, QtGui.QHeaderView.ResizeToContents)
        self.liveTree.header().setResizeMode(1, QtGui.QHeaderView.Stretch)
        self.liveTree.header().setResizeMode(
            2, QtGui.QHeaderView.ResizeToContents)

        self.games = {}

        self.onlineTree.itemDoubleClicked.connect(self.onlineTreeDoubleClicked)
        self.onlineTree.itemPressed.connect(self.onlineTreeClicked)

        # replay vault connection to server
        self.searching = False
        self.blockSize = 0
        self.replayVaultSocket = QtNetwork.QTcpSocket()
        self.replayVaultSocket.error.connect(self.handleServerError)
        self.replayVaultSocket.readyRead.connect(self.readDataFromServer)
        self.replayVaultSocket.disconnected.connect(self.disconnected)
        self.replayVaultSocket.error.connect(self.errored)

        logger.info("Replays Widget instantiated.")

    def searchVault(self):
        ''' search for some replays '''
        self.searching = True
        self.connectToModVault()
        self.send(
            dict(command="search",
                 rating=self.minRating.value(),
                 map=self.mapName.text(),
                 player=self.playerName.text(),
                 mod=self.modList.currentText()))
        self.onlineTree.clear()

    def reloadView(self):
        if self.searching != True:
            self.connectToModVault()
            self.send(dict(command="list"))

    def finishRequest(self, reply):
        faf_replay = QtCore.QFile(
            os.path.join(util.CACHE_DIR, "temp.fafreplay"))
        faf_replay.open(QtCore.QIODevice.WriteOnly | QtCore.QIODevice.Truncate)
        faf_replay.write(reply.readAll())
        faf_replay.flush()
        faf_replay.close()
        fa.exe.replay(os.path.join(util.CACHE_DIR, "temp.fafreplay"))

    def onlineTreeClicked(self, item):
        if QtGui.QApplication.mouseButtons() == QtCore.Qt.RightButton:
            item.pressed(item)
        else:
            if hasattr(item, "moreInfo"):
                if item.moreInfo == False:
                    self.connectToModVault()
                    self.send(dict(command="info_replay", uid=item.uid))
                else:
                    self.replayInfos.clear()
                    self.replayInfos.setHtml(item.replayInfo)

    def onlineTreeDoubleClicked(self, item):
        if hasattr(item, "url"):
            self.replayDownload.get(QNetworkRequest(QtCore.QUrl(item.url)))

    def replayVault(self, message):
        action = message["action"]
        if action == "list_recents":
            self.onlineReplays = {}
            replays = message["replays"]
            for replay in replays:
                uid = replay["id"]

                if uid not in self.onlineReplays:
                    self.onlineReplays[uid] = ReplayItem(uid, self)
                    self.onlineReplays[uid].update(replay, self.client)
                else:
                    self.onlineReplays[uid].update(replay, self.client)

            self.updateOnlineTree()

        elif action == "info_replay":
            uid = message["uid"]
            if uid in self.onlineReplays:
                self.onlineReplays[uid].infoPlayers(message["players"])

        elif action == "search_result":
            self.searching = False
            self.onlineReplays = {}
            replays = message["replays"]
            for replay in replays:
                uid = replay["id"]

                if uid not in self.onlineReplays:
                    self.onlineReplays[uid] = ReplayItem(uid, self)
                    self.onlineReplays[uid].update(replay, self.client)
                else:
                    self.onlineReplays[uid].update(replay, self.client)

            self.updateOnlineTree()

    def focusEvent(self, event):
        self.updatemyTree()
        self.reloadView()
        return BaseClass.focusEvent(self, event)

    def showEvent(self, event):
        self.updatemyTree()
        self.reloadView()
        return BaseClass.showEvent(self, event)

    def updateOnlineTree(self):
        self.replayInfos.clear()
        self.onlineTree.clear()
        buckets = {}
        for uid in self.onlineReplays:
            bucket = buckets.setdefault(self.onlineReplays[uid].startDate, [])
            bucket.append(self.onlineReplays[uid])

        for bucket in buckets.keys():
            bucket_item = QtGui.QTreeWidgetItem()
            self.onlineTree.addTopLevelItem(bucket_item)

            bucket_item.setIcon(0, util.icon("replays/bucket.png"))
            bucket_item.setText(0, "<font color='white'>" + bucket + "</font>")
            bucket_item.setText(
                1, "<font color='white'>" + str(len(buckets[bucket])) +
                " replays</font>")

            for replay in buckets[bucket]:
                bucket_item.addChild(replay)
                replay.setFirstColumnSpanned(True)
                replay.setIcon(0, replay.icon)

            bucket_item.setExpanded(True)

    def updatemyTree(self):
        self.myTree.clear()

        # We put the replays into buckets by day first, then we add them to the treewidget.
        buckets = {}

        # Iterate
        for infile in os.listdir(util.REPLAY_DIR):
            if infile.endswith(".scfareplay"):
                bucket = buckets.setdefault("legacy", [])

                item = QtGui.QTreeWidgetItem()
                item.setText(1, infile)
                item.filename = os.path.join(util.REPLAY_DIR, infile)
                item.setIcon(0, util.icon("replays/replay.png"))
                item.setTextColor(
                    0, QtGui.QColor(client.instance.getColor("default")))

                bucket.append(item)

            elif infile.endswith(".fafreplay"):
                item = QtGui.QTreeWidgetItem()
                try:
                    item.filename = os.path.join(util.REPLAY_DIR, infile)
                    item.info = json.loads(
                        open(item.filename, "rt").readline())

                    # Parse replayinfo into data
                    if item.info.get('complete', False):
                        game_date = time.strftime(
                            "%Y-%m-%d", time.localtime(item.info['game_time']))
                        game_hour = time.strftime(
                            "%H:%M", time.localtime(item.info['game_time']))

                        bucket = buckets.setdefault(game_date, [])

                        icon = fa.maps.preview(item.info['mapname'])
                        if icon:
                            item.setIcon(0, icon)
                        else:
                            self.client.downloader.downloadMap(
                                item.info['mapname'], item, True)
                            item.setIcon(0, util.icon("games/unknown_map.png"))
                        item.setToolTip(
                            0, fa.maps.getDisplayName(item.info['mapname']))
                        item.setText(0, game_hour)
                        item.setTextColor(
                            0,
                            QtGui.QColor(client.instance.getColor("default")))

                        item.setText(1, item.info['title'])
                        item.setToolTip(1, infile)

                        # Hacky way to quickly assemble a list of all the players, but including the observers
                        playerlist = []
                        for _, players in item.info['teams'].items():
                            playerlist.extend(players)
                        item.setText(2, ", ".join(playerlist))
                        item.setToolTip(2, ", ".join(playerlist))

                        # Add additional info
                        item.setText(3, item.info['featured_mod'])
                        item.setTextAlignment(3, QtCore.Qt.AlignCenter)
                        item.setTextColor(
                            1,
                            QtGui.QColor(
                                client.instance.getUserColor(
                                    item.info.get('recorder', ""))))
                    else:
                        bucket = buckets.setdefault("incomplete", [])
                        item.setIcon(0, util.icon("replays/replay.png"))
                        item.setText(1, infile)
                        item.setText(
                            2, "(replay doesn't have complete metadata)")
                        item.setTextColor(1, QtGui.QColor(
                            "yellow"))  #FIXME: Needs to come from theme

                except:
                    bucket = buckets.setdefault("broken", [])
                    item.setIcon(0, util.icon("replays/broken.png"))
                    item.setText(1, infile)
                    item.setTextColor(
                        1,
                        QtGui.QColor("red"))  #FIXME: Needs to come from theme
                    item.setText(2, "(replay parse error)")
                    item.setTextColor(
                        2,
                        QtGui.QColor("gray"))  #FIXME: Needs to come from theme
                    logger.error("Replay parse error for " + infile)

                bucket.append(item)

        # Now, create a top level treewidgetitem for every bucket, and put the bucket's contents into them
        for bucket in buckets.keys():
            bucket_item = QtGui.QTreeWidgetItem()

            if bucket == "broken":
                bucket_item.setTextColor(
                    0, QtGui.QColor("red"))  #FIXME: Needs to come from theme
                bucket_item.setText(1, "(not watchable)")
                bucket_item.setTextColor(
                    1, QtGui.QColor(client.instance.getColor("default")))
            elif bucket == "incomplete":
                bucket_item.setTextColor(
                    0,
                    QtGui.QColor("yellow"))  #FIXME: Needs to come from theme
                bucket_item.setText(1, "(watchable)")
                bucket_item.setTextColor(
                    1, QtGui.QColor(client.instance.getColor("default")))
            elif bucket == "legacy":
                bucket_item.setTextColor(
                    0, QtGui.QColor(client.instance.getColor("default")))
                bucket_item.setTextColor(
                    1, QtGui.QColor(client.instance.getColor("default")))
                bucket_item.setText(1, "(old replay system)")
            else:
                bucket_item.setTextColor(
                    0, QtGui.QColor(client.instance.getColor("player")))

            bucket_item.setIcon(0, util.icon("replays/bucket.png"))
            bucket_item.setText(0, bucket)
            bucket_item.setText(3, str(len(buckets[bucket])) + " replays")
            bucket_item.setTextColor(
                3, QtGui.QColor(client.instance.getColor("default")))

            self.myTree.addTopLevelItem(bucket_item)
            #self.myTree.setFirstItemColumnSpanned(bucket_item, True)

            for replay in buckets[bucket]:
                bucket_item.addChild(replay)

    def displayReplay(self):
        for uid in self.games:
            item = self.games[uid]
            if time.time() - item.info[
                    'game_time'] > LIVEREPLAY_DELAY_TIME and item.isHidden():
                item.setHidden(False)

    @QtCore.pyqtSlot(dict)
    def processGameInfo(self, info):
        if info['state'] == "playing":
            if info['uid'] in self.games:
                # Updating an existing item
                item = self.games[info['uid']]

                item.takeChildren(
                )  #Clear the children of this item before we're updating it
            else:
                # Creating a fresh item
                item = QtGui.QTreeWidgetItem()
                self.games[info['uid']] = item

                self.liveTree.insertTopLevelItem(0, item)

                if time.time() - info["game_time"] < LIVEREPLAY_DELAY_TIME:
                    item.setHidden(True)
                    QtCore.QTimer.singleShot(
                        LIVEREPLAY_DELAY_QTIMER, self.displayReplay
                    )  #The delay is there because we have a delay in the livereplay server

            # For debugging purposes, format our tooltip for the top level items
            # so it contains a human-readable representation of the info dictionary
            item.info = info
            tip = ""
            for key in info.keys():
                tip += "'" + unicode(key) + "' : '" + unicode(
                    info[key]) + "'<br/>"

            item.setToolTip(1, tip)

            icon = fa.maps.preview(info['mapname'])
            item.setToolTip(0, fa.maps.getDisplayName(info['mapname']))
            if not icon:
                self.client.downloader.downloadMap(item.info['mapname'], item,
                                                   True)
                icon = util.icon("games/unknown_map.png")

            item.setText(
                0,
                time.strftime("%H:%M", time.localtime(item.info['game_time'])))
            item.setTextColor(
                0, QtGui.QColor(client.instance.getColor("default")))

            item.setIcon(0, icon)
            item.setText(1, info['title'])
            item.setTextColor(1,
                              QtGui.QColor(client.instance.getColor("player")))

            item.setText(2, info['featured_mod'])
            item.setTextAlignment(2, QtCore.Qt.AlignCenter)

            if not info['teams']:
                item.setDisabled(True)

            # This game is the game the player is currently in
            mygame = False

            # Create player entries for all the live players in a match
            for team in info['teams']:
                if team == "-1":  #skip observers, they don't seem to stream livereplays
                    continue

                for player in info['teams'][team]:
                    playeritem = QtGui.QTreeWidgetItem()
                    playeritem.setText(0, player)

                    url = QtCore.QUrl()
                    url.setScheme("faflive")
                    url.setHost("lobby.faforever.com")
                    url.setPath(
                        str(info["uid"]) + "/" + player + ".SCFAreplay")
                    url.addQueryItem("map", info["mapname"])
                    url.addQueryItem("mod", info["featured_mod"])

                    playeritem.url = url
                    if client.instance.login == player:
                        mygame = True
                        item.setTextColor(
                            1, QtGui.QColor(client.instance.getColor("self")))
                        playeritem.setTextColor(
                            0, QtGui.QColor(client.instance.getColor("self")))
                        playeritem.setToolTip(0, url.toString())
                        playeritem.setIcon(0, util.icon("replays/replay.png"))
                    elif client.instance.isFriend(player):
                        if not mygame:
                            item.setTextColor(
                                1,
                                QtGui.QColor(
                                    client.instance.getColor("friend")))
                        playeritem.setTextColor(
                            0,
                            QtGui.QColor(client.instance.getColor("friend")))
                        playeritem.setToolTip(0, url.toString())
                        playeritem.setIcon(0, util.icon("replays/replay.png"))
                    elif client.instance.isPlayer(player):
                        playeritem.setTextColor(
                            0,
                            QtGui.QColor(client.instance.getColor("player")))
                        playeritem.setToolTip(0, url.toString())
                        playeritem.setIcon(0, util.icon("replays/replay.png"))
                    else:
                        playeritem.setTextColor(
                            0,
                            QtGui.QColor(client.instance.getColor("default")))
                        playeritem.setDisabled(True)

                    item.addChild(playeritem)
                    self.liveTree.setFirstItemColumnSpanned(playeritem, True)
        elif info['state'] == "closed":
            if info['uid'] in self.games:
                self.liveTree.takeTopLevelItem(
                    self.liveTree.indexOfTopLevelItem(self.games[info['uid']]))

    @QtCore.pyqtSlot(QtGui.QTreeWidgetItem)
    def liveTreePressed(self, item):
        if QtGui.QApplication.mouseButtons() != QtCore.Qt.RightButton:
            return

        if self.liveTree.indexOfTopLevelItem(item) != -1:
            item.setExpanded(True)
            return

        menu = QtGui.QMenu(self.liveTree)

        # Actions for Games and Replays
        actionReplay = QtGui.QAction("Replay in FA", menu)
        actionLink = QtGui.QAction("Copy Link", menu)

        # Adding to menu
        menu.addAction(actionReplay)
        menu.addAction(actionLink)

        # Triggers
        actionReplay.triggered.connect(
            lambda: self.liveTreeDoubleClicked(item, 0))
        actionLink.triggered.connect(
            lambda: QtGui.QApplication.clipboard().setText(item.toolTip(0)))

        # Adding to menu
        menu.addAction(actionReplay)
        menu.addAction(actionLink)

        #Finally: Show the popup
        menu.popup(QtGui.QCursor.pos())

    @QtCore.pyqtSlot(QtGui.QListWidgetItem)
    def myTreePressed(self, item):
        if QtGui.QApplication.mouseButtons() != QtCore.Qt.RightButton:
            return

        if item.isDisabled():
            return

        if self.myTree.indexOfTopLevelItem(item) != -1:
            return

        menu = QtGui.QMenu(self.myTree)

        # Actions for Games and Replays
        actionReplay = QtGui.QAction("Replay", menu)
        actionExplorer = QtGui.QAction("Show in Explorer", menu)

        # Adding to menu
        menu.addAction(actionReplay)
        menu.addAction(actionExplorer)

        # Triggers
        actionReplay.triggered.connect(
            lambda: self.myTreeDoubleClicked(item, 0))
        actionExplorer.triggered.connect(
            lambda: util.showInExplorer(item.filename))

        # Adding to menu
        menu.addAction(actionReplay)
        menu.addAction(actionExplorer)

        #Finally: Show the popup
        menu.popup(QtGui.QCursor.pos())

    @QtCore.pyqtSlot(QtGui.QTreeWidgetItem, int)
    def myTreeDoubleClicked(self, item, column):
        if item.isDisabled():
            return

        if self.myTree.indexOfTopLevelItem(item) == -1:
            fa.exe.replay(item.filename)

    @QtCore.pyqtSlot(QtGui.QTreeWidgetItem, int)
    def liveTreeDoubleClicked(self, item, column):
        '''
        This slot launches a live replay from eligible items in liveTree
        '''
        if item.isDisabled():
            return

        if self.liveTree.indexOfTopLevelItem(item) == -1:
            # Notify other modules that we're watching a replay
            self.client.viewingReplay.emit(item.url)
            fa.exe.replay(item.url)

    def connectToModVault(self):
        ''' connect to the replay vault server'''

        if self.replayVaultSocket.state(
        ) != QtNetwork.QAbstractSocket.ConnectedState and self.replayVaultSocket.state(
        ) != QtNetwork.QAbstractSocket.ConnectingState:
            self.replayVaultSocket.connectToHost(self.HOST, self.SOCKET)

    def send(self, message):
        data = json.dumps(message)
        logger.debug("Outgoing JSON Message: " + data)
        self.writeToServer(data)

    @QtCore.pyqtSlot()
    def readDataFromServer(self):
        ins = QtCore.QDataStream(self.replayVaultSocket)
        ins.setVersion(QtCore.QDataStream.Qt_4_2)

        while ins.atEnd() == False:
            if self.blockSize == 0:
                if self.replayVaultSocket.bytesAvailable() < 4:
                    return
                self.blockSize = ins.readUInt32()
            if self.replayVaultSocket.bytesAvailable() < self.blockSize:
                return

            action = ins.readQString()
            self.process(action, ins)
            self.blockSize = 0

    def process(self, action, stream):
        logger.debug("Replay Vault Server: " + action)
        self.receiveJSON(action, stream)

    def receiveJSON(self, data_string, stream):
        '''
        A fairly pythonic way to process received strings as JSON messages.
        '''
        message = json.loads(data_string)
        cmd = "handle_" + message['command']
        if hasattr(self.client, cmd):
            getattr(self.client, cmd)(message)

        self.replayVaultSocket.disconnectFromHost()

    def writeToServer(self, action, *args, **kw):
        logger.debug(
            ("writeToServer(" + action + ", [" + ', '.join(args) + "])"))

        block = QtCore.QByteArray()
        out = QtCore.QDataStream(block, QtCore.QIODevice.ReadWrite)
        out.setVersion(QtCore.QDataStream.Qt_4_2)
        out.writeUInt32(0)
        out.writeQString(action)

        for arg in args:
            if type(arg) is IntType:
                out.writeInt(arg)
            elif isinstance(arg, basestring):
                out.writeQString(arg)
            elif type(arg) is FloatType:
                out.writeFloat(arg)
            elif type(arg) is ListType:
                out.writeQVariantList(arg)
            else:
                logger.warn("Uninterpreted Data Type: " + str(type(arg)) +
                            " of value: " + str(arg))
                out.writeQString(str(arg))

        out.device().seek(0)
        out.writeUInt32(block.size() - 4)

        self.bytesToSend = block.size() - 4
        self.replayVaultSocket.write(block)

    def handleServerError(self, socketError):
        if socketError == QtNetwork.QAbstractSocket.RemoteHostClosedError:
            logger.info(
                "Replay Server down: The server is down for maintenance, please try later."
            )

        elif socketError == QtNetwork.QAbstractSocket.HostNotFoundError:
            logger.info(
                "Connection to Host lost. Please check the host name and port settings."
            )

        elif socketError == QtNetwork.QAbstractSocket.ConnectionRefusedError:
            logger.info("The connection was refused by the peer.")
        else:
            logger.info("The following error occurred: %s." %
                        self.replayVaultSocket.errorString())

    @QtCore.pyqtSlot()
    def disconnected(self):
        logger.debug("Disconnected from server")

    @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
    def errored(self, error):
        logger.error("TCP Error " + self.replayVaultSocket.errorString())
Пример #50
0
class ComicVineTalker(QObject):

    logo_url = "http://static.comicvine.com/bundles/comicvinesite/images/logo.png"
    api_key = ""

    @staticmethod
    def getRateLimitMessage():
        if ComicVineTalker.api_key == "":
            return "Comic Vine rate limit exceeded.  You should configue your own Comic Vine API key."
        else:
            return "Comic Vine rate limit exceeded.  Please wait a bit."

    def __init__(self):
        QObject.__init__(self)

        self.api_base_url = "http://comicvine.gamespot.com/api"
        self.wait_for_rate_limit = False

        # key that is registered to comictagger
        default_api_key = '27431e6787042105bd3e47e169a624521f89f3a4'

        if ComicVineTalker.api_key == "":
            self.api_key = default_api_key
        else:
            self.api_key = ComicVineTalker.api_key

        self.cv_headers = {'User-Agent': 'ComicTagger ' + str(ctversion.version) + ' [' + ctversion.fork + ' / ' + ctversion.fork_tag + ']'}
        self.log_func = None

    def setLogFunc(self, log_func):
        self.log_func = log_func

    def writeLog(self, text):
        if self.log_func is None:
            # sys.stdout.write(text.encode(errors='replace'))
            # sys.stdout.flush()
            print >> sys.stderr, text
        else:
            self.log_func(text)

    def parseDateStr(self, date_str):
        day = None
        month = None
        year = None
        if date_str is not None:
            parts = date_str.split('-')
            year = parts[0]
            if len(parts) > 1:
                month = parts[1]
                if len(parts) > 2:
                    day = parts[2]
        return day, month, year

    def testKey(self, key):

        test_url = self.api_base_url + "/issue/1/?api_key=" + \
            key + "&format=json&field_list=name"
        r = requests.get(test_url, headers=self.cv_headers)

        cv_response = r.json()

        # Bogus request, but if the key is wrong, you get error 100: "Invalid
        # API Key"
        return cv_response['status_code'] != 100

    """
    Get the contect from the CV server.  If we're in "wait mode" and status code is a rate limit error
    sleep for a bit and retry.
    """

    def getCVContent(self, url):
        total_time_waited = 0
        limit_wait_time = 1
        counter = 0
        wait_times = [1, 2, 3, 4]
        while True:
            cv_response = self.getUrlContent(url)
            if self.wait_for_rate_limit and cv_response[
                    'status_code'] == ComicVineTalkerException.RateLimit:
                self.writeLog(
                    "Rate limit encountered.  Waiting for {0} minutes\n".format(limit_wait_time))
                time.sleep(limit_wait_time * 60)
                total_time_waited += limit_wait_time
                limit_wait_time = wait_times[counter]
                if counter < 3:
                    counter += 1
                # don't wait much more than 20 minutes
                if total_time_waited < 20:
                    continue
            if cv_response['status_code'] != 1:
                self.writeLog(
                    "Comic Vine query failed with error #{0}:  [{1}]. \n".format(
                        cv_response['status_code'],
                        cv_response['error']))
                raise ComicVineTalkerException(
                    cv_response['status_code'], cv_response['error'])
            else:
                # it's all good
                break
        return cv_response

    def getUrlContent(self, url):
        # connect to server:
        #  if there is a 500 error, try a few more times before giving up
        #  any other error, just bail
        # print "ATB---", url
        for tries in range(3):
            try:
                r = requests.get(url, headers=self.cv_headers)
                return r.json()
            except Exception as e:
                ecode = type(e).__name__
                if ecode == 500:
                    self.writeLog("Try #{0}: ".format(tries + 1))
                    time.sleep(1)
                self.writeLog(str(e) + "\n")

                if ecode != 500:
                    break

            except Exception as e:
                self.writeLog(str(e) + "\n")
                raise ComicVineTalkerException(
                    ComicVineTalkerException.Network, "Network Error!")

        raise ComicVineTalkerException(
            ComicVineTalkerException.Unknown, "Error on Comic Vine server")

    def searchForSeries(self, series_name, callback=None, refresh_cache=False):

        # remove cruft from the search string
        series_name = utils.removearticles(series_name).lower().strip()

        # before we search online, look in our cache, since we might have
        # done this same search recently
        cvc = ComicVineCacher()
        if not refresh_cache:
            cached_search_results = cvc.get_search_results(series_name)

            if len(cached_search_results) > 0:
                return cached_search_results

        original_series_name = series_name

        # We need to make the series name into an "AND"ed query list
        query_word_list = series_name.split()
        and_list = ['AND'] * (len(query_word_list) - 1)
        and_list.append('')
        # zipper up the two lists
        query_list = zip(query_word_list, and_list)
        # flatten the list
        query_list = [item for sublist in query_list for item in sublist]
        # convert back to a string
        query_string = " ".join(query_list).strip()
        # print "Query string = ", query_string

        query_string = urllib.quote_plus(query_string.encode("utf-8"))

        search_url = self.api_base_url + "/search/?api_key=" + self.api_key + "&format=json&resources=volume&query=" + \
            query_string + \
            "&field_list=name,id,start_year,publisher,image,description,count_of_issues"
        cv_response = self.getCVContent(search_url + "&page=1")

        search_results = list()

        # see http://api.comicvine.com/documentation/#handling_responses

        limit = cv_response['limit']
        current_result_count = cv_response['number_of_page_results']
        total_result_count = cv_response['number_of_total_results']

        if callback is None:
            self.writeLog(
                "Found {0} of {1} results\n".format(
                    cv_response['number_of_page_results'],
                    cv_response['number_of_total_results']))
        search_results.extend(cv_response['results'])
        page = 1

        if callback is not None:
            callback(current_result_count, total_result_count)

        # see if we need to keep asking for more pages...
        while (current_result_count < total_result_count):
            if callback is None:
                self.writeLog(
                    "getting another page of results {0} of {1}...\n".format(
                        current_result_count,
                        total_result_count))
            page += 1

            cv_response = self.getCVContent(search_url + "&page=" + str(page))

            search_results.extend(cv_response['results'])
            current_result_count += cv_response['number_of_page_results']

            if callback is not None:
                callback(current_result_count, total_result_count)

        # for record in search_results:
            #print(u"{0}: {1} ({2})".format(record['id'], record['name'] , record['start_year']))
            # print(record)
            #record['count_of_issues'] = record['count_of_isssues']
        #print(u"{0}: {1} ({2})".format(search_results['results'][0]['id'], search_results['results'][0]['name'] , search_results['results'][0]['start_year']))

        # cache these search results
        cvc.add_search_results(original_series_name, search_results)

        return search_results

    def fetchVolumeData(self, series_id):

        # before we search online, look in our cache, since we might already
        # have this info
        cvc = ComicVineCacher()
        cached_volume_result = cvc.get_volume_info(series_id)

        if cached_volume_result is not None:
            return cached_volume_result

        volume_url = self.api_base_url + "/volume/" + CVTypeID.Volume + "-" + \
            str(series_id) + "/?api_key=" + self.api_key + \
            "&field_list=name,id,start_year,publisher,count_of_issues&format=json"

        cv_response = self.getCVContent(volume_url)

        volume_results = cv_response['results']

        cvc.add_volume_info(volume_results)

        return volume_results

    def fetchIssuesByVolume(self, series_id):

        # before we search online, look in our cache, since we might already
        # have this info
        cvc = ComicVineCacher()
        cached_volume_issues_result = cvc.get_volume_issues_info(series_id)

        if cached_volume_issues_result is not None:
            return cached_volume_issues_result

        #---------------------------------
        issues_url = self.api_base_url + "/issues/" + "?api_key=" + self.api_key + "&filter=volume:" + \
            str(series_id) + \
            "&field_list=id,volume,issue_number,name,image,cover_date,site_detail_url,description&format=json"
        cv_response = self.getCVContent(issues_url)

        #------------------------------------

        limit = cv_response['limit']
        current_result_count = cv_response['number_of_page_results']
        total_result_count = cv_response['number_of_total_results']
        # print "ATB total_result_count", total_result_count

        #print("ATB Found {0} of {1} results".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
        volume_issues_result = cv_response['results']
        page = 1
        offset = 0

        # see if we need to keep asking for more pages...
        while (current_result_count < total_result_count):
            #print("ATB getting another page of issue results {0} of {1}...".format(current_result_count, total_result_count))
            page += 1
            offset += cv_response['number_of_page_results']

            # print issues_url+ "&offset="+str(offset)
            cv_response = self.getCVContent(
                issues_url + "&offset=" + str(offset))

            volume_issues_result.extend(cv_response['results'])
            current_result_count += cv_response['number_of_page_results']

        self.repairUrls(volume_issues_result)

        cvc.add_volume_issues_info(series_id, volume_issues_result)

        return volume_issues_result

    def fetchIssuesByVolumeIssueNumAndYear(
            self, volume_id_list, issue_number, year):
        volume_filter = "volume:"
        for vid in volume_id_list:
            volume_filter += str(vid) + "|"

        year_filter = ""
        if year is not None and str(year).isdigit():
            year_filter = ",cover_date:{0}-1-1|{1}-1-1".format(
                year, int(year) + 1)

        issue_number = urllib.quote_plus(unicode(issue_number).encode("utf-8"))

        filter = "&filter=" + volume_filter + \
            year_filter + ",issue_number:" + issue_number

        issues_url = self.api_base_url + "/issues/" + "?api_key=" + self.api_key + filter + \
            "&field_list=id,volume,issue_number,name,image,cover_date,site_detail_url,description&format=json"

        cv_response = self.getCVContent(issues_url)

        #------------------------------------

        limit = cv_response['limit']
        current_result_count = cv_response['number_of_page_results']
        total_result_count = cv_response['number_of_total_results']
        # print "ATB total_result_count", total_result_count

        #print("ATB Found {0} of {1} results\n".format(cv_response['number_of_page_results'], cv_response['number_of_total_results']))
        filtered_issues_result = cv_response['results']
        page = 1
        offset = 0

        # see if we need to keep asking for more pages...
        while (current_result_count < total_result_count):
            #print("ATB getting another page of issue results {0} of {1}...\n".format(current_result_count, total_result_count))
            page += 1
            offset += cv_response['number_of_page_results']

            # print issues_url+ "&offset="+str(offset)
            cv_response = self.getCVContent(
                issues_url + "&offset=" + str(offset))

            filtered_issues_result.extend(cv_response['results'])
            current_result_count += cv_response['number_of_page_results']

        self.repairUrls(filtered_issues_result)

        return filtered_issues_result

    def fetchIssueData(self, series_id, issue_number, settings):

        volume_results = self.fetchVolumeData(series_id)
        issues_list_results = self.fetchIssuesByVolume(series_id)

        found = False
        for record in issues_list_results:
            if IssueString(issue_number).asString() is None:
                issue_number = 1
            if IssueString(record['issue_number']).asString().lower() == IssueString(
                    issue_number).asString().lower():
                found = True
                break

        if (found):
            issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + \
                str(record['id']) + "/?api_key=" + \
                self.api_key + "&format=json"

            cv_response = self.getCVContent(issue_url)
            issue_results = cv_response['results']

        else:
            return None

        # Now, map the Comic Vine data to generic metadata
        return self.mapCVDataToMetadata(
            volume_results, issue_results, settings)

    def fetchIssueDataByIssueID(self, issue_id, settings):

        issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + \
            str(issue_id) + "/?api_key=" + self.api_key + "&format=json"
        cv_response = self.getCVContent(issue_url)

        issue_results = cv_response['results']

        volume_results = self.fetchVolumeData(issue_results['volume']['id'])

        # Now, map the Comic Vine data to generic metadata
        md = self.mapCVDataToMetadata(volume_results, issue_results, settings)
        md.isEmpty = False
        return md

    def mapCVDataToMetadata(self, volume_results, issue_results, settings):

        # Now, map the Comic Vine data to generic metadata
        metadata = GenericMetadata()

        metadata.series = issue_results['volume']['name']

        num_s = IssueString(issue_results['issue_number']).asString()
        metadata.issue = num_s
        metadata.title = issue_results['name']

        metadata.publisher = volume_results['publisher']['name']
        metadata.day, metadata.month, metadata.year = self.parseDateStr(
            issue_results['cover_date'])

        #metadata.issueCount = volume_results['count_of_issues']
        metadata.comments = self.cleanup_html(
            issue_results['description'], settings.remove_html_tables)
        if settings.use_series_start_as_volume:
            metadata.volume = volume_results['start_year']

        metadata.notes = "Tagged with the {0} fork of ComicTagger {1} using info from Comic Vine on {2}.  [Issue ID {3}]".format(
            ctversion.fork,
            ctversion.version,
            datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            issue_results['id'])
        #metadata.notes  += issue_results['site_detail_url']

        metadata.webLink = issue_results['site_detail_url']

        person_credits = issue_results['person_credits']
        for person in person_credits:
            if 'role' in person:
                roles = person['role'].split(',')
                for role in roles:
                    # can we determine 'primary' from CV??
                    metadata.addCredit(
                        person['name'], role.title().strip(), False)

        character_credits = issue_results['character_credits']
        character_list = list()
        for character in character_credits:
            character_list.append(character['name'])
        metadata.characters = utils.listToString(character_list)

        team_credits = issue_results['team_credits']
        team_list = list()
        for team in team_credits:
            team_list.append(team['name'])
        metadata.teams = utils.listToString(team_list)

        location_credits = issue_results['location_credits']
        location_list = list()
        for location in location_credits:
            location_list.append(location['name'])
        metadata.locations = utils.listToString(location_list)

        story_arc_credits = issue_results['story_arc_credits']
        arc_list = []
        for arc in story_arc_credits:
            arc_list.append(arc['name'])
        if len(arc_list) > 0:
            metadata.storyArc = utils.listToString(arc_list)

        return metadata

    def cleanup_html(self, string, remove_html_tables):
        """
        converter = html2text.HTML2Text()
        #converter.emphasis_mark = '*'
        #converter.ignore_links = True
        converter.body_width = 0

        print(html2text.html2text(string))
        return string
        #return converter.handle(string)
        """

        if string is None:
            return ""
        # find any tables
        soup = BeautifulSoup(string, "html.parser")
        tables = soup.findAll('table')

        # remove all newlines first
        string = string.replace("\n", "")

        # put in our own
        string = string.replace("<br>", "\n")
        string = string.replace("</p>", "\n\n")
        string = string.replace("<h4>", "*")
        string = string.replace("</h4>", "*\n")

        # remove the tables
        p = re.compile(r'<table[^<]*?>.*?<\/table>')
        if remove_html_tables:
            string = p.sub('', string)
            string = string.replace("*List of covers and their creators:*", "")
        else:
            string = p.sub('{}', string)

        # now strip all other tags
        p = re.compile(r'<[^<]*?>')
        newstring = p.sub('', string)

        newstring = newstring.replace('&nbsp;', ' ')
        newstring = newstring.replace('&amp;', '&')

        newstring = newstring.strip()

        if not remove_html_tables:
            # now rebuild the tables into text from BSoup
            try:
                table_strings = []
                for table in tables:
                    rows = []
                    hdrs = []
                    col_widths = []
                    for hdr in table.findAll('th'):
                        item = hdr.string.strip()
                        hdrs.append(item)
                        col_widths.append(len(item))
                    rows.append(hdrs)

                    for row in table.findAll('tr'):
                        cols = []
                        col = row.findAll('td')
                        i = 0
                        for c in col:
                            item = c.string.strip()
                            cols.append(item)
                            if len(item) > col_widths[i]:
                                col_widths[i] = len(item)
                            i += 1
                        if len(cols) != 0:
                            rows.append(cols)
                    # now we have the data, make it into text
                    fmtstr = ""
                    for w in col_widths:
                        fmtstr += " {{:{}}}|".format(w + 1)
                    width = sum(col_widths) + len(col_widths) * 2
                    print "width=", width
                    table_text = ""
                    counter = 0
                    for row in rows:
                        table_text += fmtstr.format(*row) + "\n"
                        if counter == 0 and len(hdrs) != 0:
                            table_text += "-" * width + "\n"
                        counter += 1

                    table_strings.append(table_text)

                newstring = newstring.format(*table_strings)
            except:
                # we caught an error rebuilding the table.
                # just bail and remove the formatting
                print("table parse error")
                newstring.replace("{}", "")

        return newstring

    def fetchIssueDate(self, issue_id):
        details = self.fetchIssueSelectDetails(issue_id)
        day, month, year = self.parseDateStr(details['cover_date'])
        return month, year

    def fetchIssueCoverURLs(self, issue_id):
        details = self.fetchIssueSelectDetails(issue_id)
        return details['image_url'], details['thumb_image_url']

    def fetchIssuePageURL(self, issue_id):
        details = self.fetchIssueSelectDetails(issue_id)
        return details['site_detail_url']

    def fetchIssueSelectDetails(self, issue_id):

        #cached_image_url,cached_thumb_url,cached_month,cached_year = self.fetchCachedIssueSelectDetails(issue_id)
        cached_details = self.fetchCachedIssueSelectDetails(issue_id)
        if cached_details['image_url'] is not None:
            return cached_details

        issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + \
            str(issue_id) + "/?api_key=" + self.api_key + \
            "&format=json&field_list=image,cover_date,site_detail_url"

        details = dict()
        details['image_url'] = None
        details['thumb_image_url'] = None
        details['cover_date'] = None
        details['site_detail_url'] = None

        cv_response = self.getCVContent(issue_url)

        details['image_url'] = cv_response['results']['image']['super_url']
        details['thumb_image_url'] = cv_response[
            'results']['image']['thumb_url']
        details['cover_date'] = cv_response['results']['cover_date']
        details['site_detail_url'] = cv_response['results']['site_detail_url']

        if details['image_url'] is not None:
            self.cacheIssueSelectDetails(issue_id,
                                         details['image_url'],
                                         details['thumb_image_url'],
                                         details['cover_date'],
                                         details['site_detail_url'])
        # print(details['site_detail_url'])
        return details

    def fetchCachedIssueSelectDetails(self, issue_id):

        # before we search online, look in our cache, since we might already
        # have this info
        cvc = ComicVineCacher()
        return cvc.get_issue_select_details(issue_id)

    def cacheIssueSelectDetails(
            self, issue_id, image_url, thumb_url, cover_date, page_url):
        cvc = ComicVineCacher()
        cvc.add_issue_select_details(
            issue_id, image_url, thumb_url, cover_date, page_url)

    def fetchAlternateCoverURLs(self, issue_id, issue_page_url):
        url_list = self.fetchCachedAlternateCoverURLs(issue_id)
        if url_list is not None:
            return url_list

        # scrape the CV issue page URL to get the alternate cover URLs
        resp = urllib2.urlopen(issue_page_url)
        content = resp.read()
        alt_cover_url_list = self.parseOutAltCoverUrls(content)

        # cache this alt cover URL list
        self.cacheAlternateCoverURLs(issue_id, alt_cover_url_list)

        return alt_cover_url_list

    def parseOutAltCoverUrls(self, page_html):
        soup = BeautifulSoup(page_html, "html.parser")

        alt_cover_url_list = []

        # Using knowledge of the layout of the Comic Vine issue page here:
        # look for the divs that are in the classes 'content-pod' and
        # 'alt-cover'
        div_list = soup.find_all('div')
        covers_found = 0
        for d in div_list:
            if 'class' in d:
                c = d['class']
                if 'imgboxart' in c and 'issue-cover' in c:
                    covers_found += 1
                    if covers_found != 1:
                        alt_cover_url_list.append(d.img['src'])

        return alt_cover_url_list

    def fetchCachedAlternateCoverURLs(self, issue_id):

        # before we search online, look in our cache, since we might already
        # have this info
        cvc = ComicVineCacher()
        url_list = cvc.get_alt_covers(issue_id)
        if url_list is not None:
            return url_list
        else:
            return None

    def cacheAlternateCoverURLs(self, issue_id, url_list):
        cvc = ComicVineCacher()
        cvc.add_alt_covers(issue_id, url_list)

    #-------------------------------------------------------------------------
    urlFetchComplete = pyqtSignal(str, str, int)

    def asyncFetchIssueCoverURLs(self, issue_id):

        self.issue_id = issue_id
        details = self.fetchCachedIssueSelectDetails(issue_id)
        if details['image_url'] is not None:
            self.urlFetchComplete.emit(
                details['image_url'],
                details['thumb_image_url'],
                self.issue_id)
            return

        issue_url = self.api_base_url + "/issue/" + CVTypeID.Issue + "-" + \
            str(issue_id) + "/?api_key=" + self.api_key + \
            "&format=json&field_list=image,cover_date,site_detail_url"
        self.nam = QNetworkAccessManager()
        self.nam.finished.connect(self.asyncFetchIssueCoverURLComplete)
        self.nam.get(QNetworkRequest(QUrl(issue_url)))

    def asyncFetchIssueCoverURLComplete(self, reply):

        # read in the response
        data = reply.readAll()

        try:
            cv_response = json.loads(str(data))
        except:
            print >> sys.stderr, "Comic Vine query failed to get JSON data"
            print >> sys.stderr, str(data)
            return

        if cv_response['status_code'] != 1:
            print >> sys.stderr, "Comic Vine query failed with error:  [{0}]. ".format(
                cv_response['error'])
            return

        image_url = cv_response['results']['image']['super_url']
        thumb_url = cv_response['results']['image']['thumb_url']
        cover_date = cv_response['results']['cover_date']
        page_url = cv_response['results']['site_detail_url']

        self.cacheIssueSelectDetails(
            self.issue_id, image_url, thumb_url, cover_date, page_url)

        self.urlFetchComplete.emit(image_url, thumb_url, self.issue_id)

    altUrlListFetchComplete = pyqtSignal(list, int)

    def asyncFetchAlternateCoverURLs(self, issue_id, issue_page_url):
        # This async version requires the issue page url to be provided!
        self.issue_id = issue_id
        url_list = self.fetchCachedAlternateCoverURLs(issue_id)
        if url_list is not None:
            self.altUrlListFetchComplete.emit(url_list, int(self.issue_id))
            return

        self.nam = QNetworkAccessManager()
        self.nam.finished.connect(self.asyncFetchAlternateCoverURLsComplete)
        self.nam.get(QNetworkRequest(QUrl(str(issue_page_url))))

    def asyncFetchAlternateCoverURLsComplete(self, reply):
        # read in the response
        html = str(reply.readAll())
        alt_cover_url_list = self.parseOutAltCoverUrls(html)

        # cache this alt cover URL list
        self.cacheAlternateCoverURLs(self.issue_id, alt_cover_url_list)

        self.altUrlListFetchComplete.emit(
            alt_cover_url_list, int(self.issue_id))

    def repairUrls(self, issue_list):
        # make sure there are URLs for the image fields
        for issue in issue_list:
            if issue['image'] is None:
                issue['image'] = dict()
                issue['image']['super_url'] = ComicVineTalker.logo_url
                issue['image']['thumb_url'] = ComicVineTalker.logo_url
Пример #51
0
class ConnexionOAPI(object):
    """
    Manage connexion to the overpass API
    """
    def __init__(self, url="http://overpass-api.de/api/", output=None):
        """
        Constructor

        @param url:URL of OverPass
        @type url:str

        @param output:Output desired (XML or JSON)
        @type output:str
        """

        if not url:
            url = "http://overpass-api.de/api/"

        self.__url = url
        self.data = None

        if output not in (None, "json", "xml"):
            raise OutPutFormatException

        self.__output = output
        self.network = QNetworkAccessManager()
        self.network_reply = None
        self.loop = None

    def query(self, query):
        """
        Make a query to the overpass

        @param query:Query to execute
        @type query:str

        @raise OverpassBadRequestException,NetWorkErrorException,
        OverpassTimeoutException

        @return: the result of the query
        @rtype: str
        """

        url_query = QUrl(self.__url + 'interpreter')

        # The output format can be forced (JSON or XML)
        if self.__output:
            query = re.sub(r'output="[a-z]*"',
                           'output="' + self.__output + '"', query)
            query = re.sub(r'\[out:[a-z]*', '[out:' + self.__output, query)

        # noinspection PyCallByClass
        encoded_query = QUrl.toPercentEncoding(query)
        url_query.addEncodedQueryItem('data', encoded_query)
        url_query.addQueryItem('info', 'QgisQuickOSMPlugin')
        url_query.setPort(80)

        proxy = get_proxy()
        if proxy:
            self.network.setProxy(proxy)

        request = QNetworkRequest(url_query)
        request.setRawHeader("User-Agent", "QuickOSM")
        self.network_reply = self.network.get(request)
        self.loop = QEventLoop()
        self.network.finished.connect(self._end_of_request)
        self.loop.exec_()

        if self.network_reply.error() == QNetworkReply.NoError:
            timeout = '<remark> runtime error: Query timed out in "[a-z]+" ' \
                      'at line [\d]+ after ([\d]+) seconds. </remark>'
            if re.search(timeout, self.data):
                raise OverpassTimeoutException
            else:
                return self.data

        elif self.network_reply.error() == QNetworkReply.UnknownContentError:
            raise OverpassBadRequestException
        else:
            raise NetWorkErrorException(suffix="Overpass API")

    def _end_of_request(self):
        self.data = self.network_reply.readAll()
        self.loop.quit()

    def get_file_from_query(self, query):
        """
        Make a query to the overpass and put the result in a temp file

        @param query:Query to execute
        @type query:str

        @return: temporary file path
        @rtype: str
        """
        query = self.query(query)
        tf = tempfile.NamedTemporaryFile(delete=False, suffix=".osm")
        tf.write(query)
        name_file = tf.name
        tf.flush()
        tf.close()
        return name_file

    def get_timestamp(self):
        """
        Get the timestamp of the OSM data on the server

        @return: Timestamp
        @rtype: str
        """
        url_query = self.__url + 'timestamp'
        try:
            return urllib2.urlopen(url=url_query).read()
        except urllib2.HTTPError as e:
            if e.code == 400:
                raise OverpassBadRequestException

    def is_valid(self):
        """
        Try if the url is valid, NOT TESTED YET
        """
        url_query = self.__url + 'interpreter'
        try:
            urllib2.urlopen(url=url_query)
            return True
        except urllib2.HTTPError:
            return False
Пример #52
0
class RestRequest(QObject):

    restApiUrl = ''  #

    done = pyqtSignal(dict, name='done')

    def __init__(self, url, parentWindow, done, params=None):  # parent not used
        super(RestRequest, self).__init__()
        # private
        self._manager = QNetworkAccessManager()
        if params is not None:
            url += '?' + '&'.join('{}={}'.format(k, urllib.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems())

        self.url = QUrl(RestRequest.restApiUrl + url)

        # connect asynchronous result, when a request finishes
        self._manager.finished.connect(self._finished)
        self._manager.sslErrors.connect(self._sslError)
        self._parentWindow = parentWindow

        self.done.connect(done, Qt.QueuedConnection)

    # private slot, no need to declare as slot
    @pyqtSlot(QNetworkReply)
    def _finished(self, reply):
        '''
        Handle signal 'finished'.  A network request has finished.
        '''
        try:
            if reply.error() != QNetworkReply.NoError:
                raise Exception(reply.errorString())
            data = six.text_type(reply.readAll())
            data = json.loads(data)
        except Exception as e:
            data = {
                'result': None,
                'error': six.text_type(e)
            }

        self.done.emit(data)

        reply.deleteLater()  # schedule for delete from main event loop

    @pyqtSlot(QNetworkReply, list)
    def _sslError(self, reply, errors):
        settings = QSettings()
        settings.beginGroup('ssl')
        cert = errors[0].certificate()
        digest = six.text_type(cert.digest().toHex())

        approved = settings.value(digest, False).toBool()

        errorString = '<p>The certificate for <b>{}</b> has the following errors:</p><ul>'.format(cert.subjectInfo(QSslCertificate.CommonName))

        for err in errors:
            errorString += '<li>' + err.errorString() + '</li>'

        errorString += '</ul>'

        if approved or QMessageBox.warning(self._parentWindow, 'SSL Warning', errorString, QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            settings.setValue(digest, True)
            reply.ignoreSslErrors()

        settings.endGroup()

    def get(self):
        request = QNetworkRequest(self.url)
        request.setRawHeader('User-Agent', osDetector.getOs() + " - UDS Connector " + VERSION)
        self._manager.get(request)
Пример #53
0
class CartoDBApi(QObject):
    fetchContent = pyqtSignal(object)
    progress = pyqtSignal(int, int)
    error = pyqtSignal(object)

    def __init__(self,
                 cartodbUser,
                 apiKey,
                 multiuser=False,
                 hostname='cartonico.datapy.info'):
        QObject.__init__(self)
        self.multiuser = multiuser
        self.apiKey = apiKey
        self.cartodbUser = cartodbUser
        self.hostname = hostname
        self.apiUrl = "https://{}.{}/api/v1/".format(cartodbUser, hostname)
        self.returnDict = True

        self.manager = QNetworkAccessManager()
        self.manager.finished.connect(self.returnFetchContent)

    def _getRequest(self, url):
        request = QNetworkRequest(url)
        request.setRawHeader("Content-Type", "application/json")
        request.setRawHeader('User-Agent', 'QGISCartoDB 0.2.x')
        return request

    def _createMultipart(self, data={}, files={}):
        multiPart = QHttpMultiPart(QHttpMultiPart.FormDataType)
        for key, value in data.items():
            textPart = QHttpPart()
            textPart.setHeader(QNetworkRequest.ContentDispositionHeader,
                               "form-data; name=\"%s\"" % key)
            textPart.setBody(value)
            multiPart.append(textPart)

        for key, file in files.items():
            filePart = QHttpPart()
            # filePart.setHeader(QNetworkRequest::ContentTypeHeader, ...);
            fileName = QFileInfo(file.fileName()).fileName()
            filePart.setHeader(
                QNetworkRequest.ContentDispositionHeader,
                "form-data; name=\"%s\"; filename=\"%s\"" % (key, fileName))
            filePart.setBodyDevice(file)
            multiPart.append(filePart)
        return multiPart

    def getUserDetails(self, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(
            self.apiUrl +
            "users/{}/?api_key={}".format(self.cartodbUser, self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def getUserTables(self,
                      page=1,
                      per_page=20,
                      shared='yes',
                      returnDict=True):
        self.returnDict = returnDict
        payload = {
            'tag_name': '',
            'q': '',
            'page': page,
            'type': '',
            'exclude_shared': 'false',
            'per_page': per_page,
            'tags': '',
            'shared': shared,
            'locked': 'false',
            'only_liked': 'false',
            'order': 'name',
            'types': 'table'
        }
        url = QUrl(
            self.apiUrl +
            "viz?api_key={}&{}".format(self.apiKey, urllib.urlencode(payload)))
        request = self._getRequest(url)

        reply = self.manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def getDataFromTable(self, sql, returnDict=True):
        self.returnDict = returnDict
        apiUrl = 'http://{}.{}/api/v2/sql?api_key={}&format=GeoJSON&q={}'.format(
            self.cartodbUser, self.hostname, self.apiKey, sql)
        url = QUrl(apiUrl)
        request = self._getRequest(url)

        reply = self.manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def download(self, sql):
        apiUrl = 'http://{}.{}/api/v2/sql?api_key={}&format=spatialite&q={}'.format(
            self.cartodbUser, self.hostname, self.apiKey, sql)
        url = QUrl(apiUrl)
        request = self._getRequest(url)

        def finished(reply):
            tempdir = tempfile.tempdir
            if tempdir is None:
                tempdir = tempfile.mkdtemp()

            tf = tempfile.NamedTemporaryFile(delete=False)
            sqlite = QFile(tf.name)
            tf.close()
            if (sqlite.open(QIODevice.WriteOnly)):
                sqlite.write(reply.readAll())
                sqlite.close()
                self.fetchContent.emit(tf.name)
            else:
                self.error.emit('Error saving downloaded file')

        manager = QNetworkAccessManager()
        manager.finished.connect(finished)

        reply = manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def upload(self, filePath, returnDict=True):
        self.returnDict = returnDict
        file = QFile(filePath)
        file.open(QFile.ReadOnly)
        url = QUrl(self.apiUrl + "imports/?api_key={}".format(self.apiKey))
        files = {'file': file}
        multipart = self._createMultipart(files=files)
        request = QNetworkRequest(url)
        request.setHeader(
            QNetworkRequest.ContentTypeHeader,
            'multipart/form-data; boundary=%s' % multipart.boundary())
        request.setRawHeader('User-Agent', 'QGISCartoDB 0.2.x')
        reply = self.manager.post(request, multipart)
        loop = QEventLoop()
        reply.uploadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def checkUploadStatus(self, id, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(self.apiUrl +
                   "imports/{}/?api_key={}".format(id, self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def createVizFromTable(self, table, name, description='', returnDict=True):
        self.returnDict = returnDict
        payload = {
            'type': 'derived',
            'name': name,
            'title': name,
            'description': description,
            'tags': ['QGISCartoDB'],
            "tables": [table]
        }
        url = QUrl(self.apiUrl + "viz/?api_key={}".format(self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.post(request, json.dumps(payload))
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def updateViz(self, viz, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(self.apiUrl +
                   "viz/{}?api_key={}".format(viz['id'], self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.put(request, json.dumps(viz))
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def addLayerToMap(self, mapId, layer, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(self.apiUrl +
                   "maps/{}/layers?api_key={}".format(mapId, self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.post(request, json.dumps(layer))
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def updateLayerInMap(self, mapId, layer, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(self.apiUrl + "maps/{}/layers/{}?api_key={}".format(
            mapId, layer['id'], self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.put(request, json.dumps(layer))
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def getLayersMap(self, mapId, returnDict=True):
        self.returnDict = returnDict
        url = QUrl(self.apiUrl +
                   "maps/{}/layers?api_key={}".format(mapId, self.apiKey))
        request = self._getRequest(url)

        reply = self.manager.get(request)
        loop = QEventLoop()
        reply.downloadProgress.connect(self.progressCB)
        reply.error.connect(self._error)
        reply.finished.connect(loop.exit)
        loop.exec_()

    def progressCB(self, breceived, btotal):
        self.progress.emit(breceived, btotal)

    def returnFetchContent(self, reply):
        response = str(reply.readAll())
        # qDebug('Response:' + response)
        # qDebug('Error: ' + str(reply.error()))
        # qDebug('Status: ' + str(reply.rawHeader('Location')))

        if reply.rawHeader('Location') == 'http://cartodb.com/noneuser.html' or \
           reply.rawHeader('Location') == 'http://carto.com/noneuser.html':
            response = '{"error": "User not found"}'
        elif reply.error() == QNetworkReply.AuthenticationRequiredError:
            response = '{"error": "Confirm user credentials"}'

        if self.returnDict:
            try:
                self.fetchContent.emit(json.loads(response))
            except ValueError as e:
                qDebug('Error loading json. {}'.format(response))
                response = '{"error": "Error loading JSON data"}'
                self.fetchContent.emit(json.loads(response))
        else:
            self.fetchContent.emit(response)

    def _error(self, error):
        qDebug('Error: ' + str(error))
        self.error.emit(error)
Пример #54
0
class tutorialsWidget(FormClass, BaseClass):
    def __init__(self, client, *args, **kwargs):
        BaseClass.__init__(self, *args, **kwargs)        
        
        self.setupUi(self)

        self.client = client
        self.client.tutorialsTab.layout().addWidget(self)    
        
        self.sections = {}
        self.tutorials = {}

        self.client.tutorialsInfo.connect(self.processTutorialInfo)
        
        logger.info("Tutorials instantiated.")
        
        
    def finishReplay(self, reply):
        if reply.error() != QNetworkReply.NoError:
            QtGui.QMessageBox.warning(self, "Network Error", reply.errorString())
        else:
            filename = os.path.join(util.CACHE_DIR, str("tutorial.fafreplay"))
            replay  = QtCore.QFile(filename)
            replay.open(QtCore.QIODevice.WriteOnly | QtCore.QIODevice.Text)
            replay.write(reply.readAll())
            replay.close()
    
            fa.replay(filename, True)
    
    def tutorialClicked(self, item):

        self.nam = QNetworkAccessManager()
        self.nam.finished.connect(self.finishReplay)
        self.nam.get(QNetworkRequest(QtCore.QUrl(item.url)))            

    
    def processTutorialInfo(self, message):
        '''
        Two type here : section or tutorials.
        Sections are defining the differents type of tutorials
        '''
        
        logger.debug("Processing TutorialInfo")
        
        if "section" in message :
            section = message["section"]
            desc = message["description"]

            area = util.loadUi("tutorials/tutorialarea.ui")
            tabIndex = self.addTab(area, section)      
            self.setTabToolTip(tabIndex, desc)

            # Set up the List that contains the tutorial items
            area.listWidget.setItemDelegate(TutorialItemDelegate(self))
            area.listWidget.itemDoubleClicked.connect(self.tutorialClicked)
            
            self.sections[section] = area.listWidget
            
        elif "tutorial" in message :
            tutorial = message["tutorial"]
            section = message["tutorial_section"]
            
            if section in self.sections :
                self.tutorials[tutorial] = TutorialItem(tutorial)
                self.tutorials[tutorial].update(message, self.client)
                
                self.sections[section].addItem(self.tutorials[tutorial]) 
Пример #55
0
class OnlineUpdater(QWidgetComponentFactory(uiFile=COMPONENT_UI_FILE)):
    """
	| Defines the :mod:`sibl_gui.components.addons.onlineUpdater.onlineUpdater` Component Interface class.
	| This Component provides online updating capabilities to the Application available through options exposed in
		the :mod:`sibl_gui.components.core.preferencesManager.preferencesManager` Component ui.
	"""
    def __init__(self, parent=None, name=None, *args, **kwargs):
        """
		Initializes the class.

		:param parent: Object parent.
		:type parent: QObject
		:param name: Component name.
		:type name: unicode
		:param \*args: Arguments.
		:type \*args: \*
		:param \*\*kwargs: Keywords arguments.
		:type \*\*kwargs: \*\*
		"""

        LOGGER.debug("> Initializing '{0}()' class.".format(
            self.__class__.__name__))

        super(OnlineUpdater, self).__init__(parent, name, *args, **kwargs)

        # --- Setting class attributes. ---
        self.deactivatable = True

        self.__engine = None
        self.__settings = None
        self.__settingsSection = None

        self.__preferencesManager = None
        self.__templatesOutliner = None
        self.__locationsBrowser = None

        self.__ioDirectory = "remote/"

        self.__repositoryUrl = REPOSITORY_URL
        self.__releasesFileUrl = "sIBL_GUI_Releases.rc"

        self.__networkAccessManager = None
        self.__releasesFileReply = None

        self.__remoteUpdater = None
        self.__reportUpdateStatus = None

    #******************************************************************************************************************
    #***	Attributes properties.
    #******************************************************************************************************************
    @property
    def engine(self):
        """
		Property for **self.__engine** attribute.

		:return: self.__engine.
		:rtype: QObject
		"""

        return self.__engine

    @engine.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def engine(self, value):
        """
		Setter for **self.__engine** attribute.

		:param value: Attribute value.
		:type value: QObject
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "engine"))

    @engine.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def engine(self):
        """
		Deleter for **self.__engine** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "engine"))

    @property
    def settings(self):
        """
		Property for **self.__settings** attribute.

		:return: self.__settings.
		:rtype: QSettings
		"""

        return self.__settings

    @settings.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def settings(self, value):
        """
		Setter for **self.__settings** attribute.

		:param value: Attribute value.
		:type value: QSettings
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "settings"))

    @settings.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def settings(self):
        """
		Deleter for **self.__settings** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "settings"))

    @property
    def settingsSection(self):
        """
		Property for **self.__settingsSection** attribute.

		:return: self.__settingsSection.
		:rtype: unicode
		"""

        return self.__settingsSection

    @settingsSection.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def settingsSection(self, value):
        """
		Setter for **self.__settingsSection** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "settingsSection"))

    @settingsSection.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def settingsSection(self):
        """
		Deleter for **self.__settingsSection** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "settingsSection"))

    @property
    def preferencesManager(self):
        """
		Property for **self.__preferencesManager** attribute.

		:return: self.__preferencesManager.
		:rtype: QWidget
		"""

        return self.__preferencesManager

    @preferencesManager.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def preferencesManager(self, value):
        """
		Setter for **self.__preferencesManager** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "preferencesManager"))

    @preferencesManager.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def preferencesManager(self):
        """
		Deleter for **self.__preferencesManager** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "preferencesManager"))

    @property
    def templatesOutliner(self):
        """
		Property for **self.__templatesOutliner** attribute.

		:return: self.__templatesOutliner.
		:rtype: QWidget
		"""

        return self.__templatesOutliner

    @templatesOutliner.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def templatesOutliner(self, value):
        """
		Setter for **self.__templatesOutliner** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "templatesOutliner"))

    @templatesOutliner.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def templatesOutliner(self):
        """
		Deleter for **self.__templatesOutliner** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "templatesOutliner"))

    @property
    def locationsBrowser(self):
        """
		Property for **self.__locationsBrowser** attribute.

		:return: self.__locationsBrowser.
		:rtype: QWidget
		"""

        return self.__locationsBrowser

    @locationsBrowser.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def locationsBrowser(self, value):
        """
		Setter for **self.__locationsBrowser** attribute.

		:param value: Attribute value.
		:type value: QWidget
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "locationsBrowser"))

    @locationsBrowser.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def locationsBrowser(self):
        """
		Deleter for **self.__locationsBrowser** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "locationsBrowser"))

    @property
    def ioDirectory(self):
        """
		Property for **self.__ioDirectory** attribute.

		:return: self.__ioDirectory.
		:rtype: unicode
		"""

        return self.__ioDirectory

    @ioDirectory.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def ioDirectory(self, value):
        """
		Setter for **self.__ioDirectory** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "ioDirectory"))

    @ioDirectory.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def ioDirectory(self):
        """
		Deleter for **self.__ioDirectory** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "ioDirectory"))

    @property
    def repositoryUrl(self):
        """
		Property for **self.__repositoryUrl** attribute.

		:return: self.__repositoryUrl.
		:rtype: unicode
		"""

        return self.__repositoryUrl

    @repositoryUrl.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def repositoryUrl(self, value):
        """
		Setter for **self.__repositoryUrl** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "repositoryUrl"))

    @repositoryUrl.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def repositoryUrl(self):
        """
		Deleter for **self.__repositoryUrl** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "repositoryUrl"))

    @property
    def releasesFileUrl(self):
        """
		Property for **self.__releasesFileUrl** attribute.

		:return: self.__releasesFileUrl.
		:rtype: unicode
		"""

        return self.__releasesFileUrl

    @releasesFileUrl.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def releasesFileUrl(self, value):
        """
		Setter for **self.__releasesFileUrl** attribute.

		:param value: Attribute value.
		:type value: unicode
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "releasesFileUrl"))

    @releasesFileUrl.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def releasesFileUrl(self):
        """
		Deleter for **self.__releasesFileUrl** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "releasesFileUrl"))

    @property
    def networkAccessManager(self):
        """
		Property for **self.__networkAccessManager** attribute.

		:return: self.__networkAccessManager.
		:rtype: QNetworkAccessManager
		"""

        return self.__networkAccessManager

    @networkAccessManager.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def networkAccessManager(self, value):
        """
		Setter for **self.__networkAccessManager** attribute.

		:param value: Attribute value.
		:type value: QNetworkAccessManager
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "networkAccessManager"))

    @networkAccessManager.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def networkAccessManager(self):
        """
		Deleter for **self.__networkAccessManager** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "networkAccessManager"))

    @property
    def releaseReply(self):
        """
		Property for **self.__releasesFileReply** attribute.

		:return: self.__releasesFileReply.
		:rtype: QNetworkReply
		"""

        return self.__releasesFileReply

    @releaseReply.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def releaseReply(self, value):
        """
		Setter for **self.__releasesFileReply** attribute.

		:param value: Attribute value.
		:type value: QNetworkReply
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "releaseReply"))

    @releaseReply.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def releaseReply(self):
        """
		Deleter for **self.__releasesFileReply** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "releaseReply"))

    @property
    def remoteUpdater(self):
        """
		Property for **self.__remoteUpdater** attribute.

		:return: self.__remoteUpdater.
		:rtype: object
		"""

        return self.__remoteUpdater

    @remoteUpdater.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def remoteUpdater(self, value):
        """
		Setter for **self.__remoteUpdater** attribute.

		:param value: Attribute value.
		:type value: object
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "remoteUpdater"))

    @remoteUpdater.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def remoteUpdater(self):
        """
		Deleter for **self.__remoteUpdater** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "remoteUpdater"))

    @property
    def reportUpdateStatus(self):
        """
		Property for **self.__reportUpdateStatus** attribute.

		:return: self.__reportUpdateStatus.
		:rtype: bool
		"""

        return self.__reportUpdateStatus

    @reportUpdateStatus.setter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def reportUpdateStatus(self, value):
        """
		Setter for **self.__reportUpdateStatus** attribute.

		:param value: Attribute value.
		:type value: bool
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is read only!".format(
                self.__class__.__name__, "reportUpdateStatus"))

    @reportUpdateStatus.deleter
    @foundations.exceptions.handleExceptions(
        foundations.exceptions.ProgrammingError)
    def reportUpdateStatus(self):
        """
		Deleter for **self.__reportUpdateStatus** attribute.
		"""

        raise foundations.exceptions.ProgrammingError(
            "{0} | '{1}' attribute is not deletable!".format(
                self.__class__.__name__, "reportUpdateStatus"))

    #******************************************************************************************************************
    #***	Class methods.
    #******************************************************************************************************************
    def activate(self, engine):
        """
		Activates the Component.

		:param engine: Engine to attach the Component to.
		:type engine: QObject
		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Activating '{0}' Component.".format(
            self.__class__.__name__))

        self.__engine = engine
        self.__settings = self.__engine.settings
        self.__settingsSection = self.name

        self.__preferencesManager = self.__engine.componentsManager[
            "factory.preferencesManager"]
        self.__templatesOutliner = self.__engine.componentsManager[
            "core.templatesOutliner"]
        self.__locationsBrowser = self.__engine.componentsManager[
            "addons.locationsBrowser"]

        self.__ioDirectory = os.path.join(
            self.__engine.userApplicationDataDirectory, Constants.ioDirectory,
            self.__ioDirectory)
        not foundations.common.pathExists(self.__ioDirectory) and os.makedirs(
            self.__ioDirectory)

        self.__networkAccessManager = QNetworkAccessManager()

        self.__reportUpdateStatus = True

        self.activated = True
        return True

    def deactivate(self):
        """
		Deactivates the Component.

		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Deactivating '{0}' Component.".format(
            self.__class__.__name__))

        self.__engine = None
        self.__settings = None
        self.__settingsSection = None

        self.__preferencesManager = None
        self.__templatesOutliner = None
        self.__locationsBrowser = None

        self.__ioDirectory = os.path.basename(
            os.path.abspath(self.__ioDirectory))

        self.__networkAccessManager = None

        self.__reportUpdateStatus = None

        self.activated = False
        return True

    def initializeUi(self):
        """
		Initializes the Component ui.
		
		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Initializing '{0}' Component ui.".format(
            self.__class__.__name__))

        self.__engine.parameters.deactivateWorkerThreads and \
        LOGGER.info(
        "{0} | 'OnStartup' Online Updater worker thread deactivated by '{1}' command line parameter value!".format(
        self.__class__.__name__, "deactivateWorkerThreads"))

        self.__Check_For_New_Releases_On_Startup_checkBox_setUi()
        self.__Ignore_Non_Existing_Templates_checkBox_setUi()

        # Signals / Slots.
        self.Check_For_New_Releases_pushButton.clicked.connect(
            self.__Check_For_New_Releases_pushButton__clicked)
        self.Check_For_New_Releases_On_Startup_checkBox.stateChanged.connect(
            self.__Check_For_New_Releases_On_Startup_checkBox__stateChanged)
        self.Ignore_Non_Existing_Templates_checkBox.stateChanged.connect(
            self.__Ignore_Non_Existing_Templates_checkBox__stateChanged)

        self.initializedUi = True
        return True

    def uninitializeUi(self):
        """
		Uninitializes the Component ui.
		
		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Uninitializing '{0}' Component ui.".format(
            self.__class__.__name__))

        # Signals / Slots.
        self.Check_For_New_Releases_pushButton.clicked.disconnect(
            self.__Check_For_New_Releases_pushButton__clicked)
        self.Check_For_New_Releases_On_Startup_checkBox.stateChanged.disconnect(
            self.__Check_For_New_Releases_On_Startup_checkBox__stateChanged)
        self.Ignore_Non_Existing_Templates_checkBox.stateChanged.disconnect(
            self.__Ignore_Non_Existing_Templates_checkBox__stateChanged)

        self.initializedUi = False
        return True

    def onStartup(self):
        """
		Defines the slot triggered on Framework startup.

		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug(
            "> Calling '{0}' Component Framework 'onStartup' method.".format(
                self.__class__.__name__))

        self.__reportUpdateStatus = False
        if not self.__engine.parameters.deactivateWorkerThreads and \
        self.Check_For_New_Releases_On_Startup_checkBox.isChecked():
            self.checkForNewReleases()
        return True

    def addWidget(self):
        """
		Adds the Component Widget to the engine.

		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Adding '{0}' Component Widget.".format(
            self.__class__.__name__))

        self.__preferencesManager.Others_Preferences_gridLayout.addWidget(
            self.Online_Updater_groupBox)

    def removeWidget(self):
        """
		Removes the Component Widget from the engine.

		:return: Method success.
		:rtype: bool
		"""

        LOGGER.debug("> Removing '{0}' Component Widget.".format(
            self.__class__.__name__))

        self.Online_Updater_groupBox.setParent(None)

    def __Check_For_New_Releases_On_Startup_checkBox_setUi(self):
        """
		Sets the **Check_For_New_Releases_On_Startup_checkBox** Widget.
		"""

        # Adding settings key if it doesn't exists.
        self.__settings.getKey(self.__settingsSection, "checkForNewReleasesOnStartup").isNull() and \
        self.__settings.setKey(self.__settingsSection, "checkForNewReleasesOnStartup", Qt.Checked)

        checkForNewReleasesOnStartup = self.__settings.getKey(
            self.__settingsSection, "checkForNewReleasesOnStartup")
        LOGGER.debug("> Setting '{0}' with value '{1}'.".format(
            "Check_For_New_Releases_On_Startup_checkBox",
            foundations.common.getFirstItem(
                checkForNewReleasesOnStartup.toInt())))
        self.Check_For_New_Releases_On_Startup_checkBox.setCheckState(
            foundations.common.getFirstItem(
                checkForNewReleasesOnStartup.toInt()))

    def __Check_For_New_Releases_On_Startup_checkBox__stateChanged(
            self, state):
        """
		Defines the slot triggered by **Check_For_New_Releases_On_Startup_checkBox** Widget when state changed.

		:param state: Checkbox state.
		:type state: int
		"""

        LOGGER.debug(
            "> Check for new releases on startup state: '{0}'.".format(state))
        self.__settings.setKey(self.__settingsSection,
                               "checkForNewReleasesOnStartup", state)

    def __Ignore_Non_Existing_Templates_checkBox_setUi(self):
        """
		Sets the **Ignore_Non_Existing_Templates_checkBox** Widget.
		"""

        # Adding settings key if it doesn't exists.
        self.__settings.getKey(self.__settingsSection, "ignoreNonExistingTemplates").isNull() and \
        self.__settings.setKey(self.__settingsSection, "ignoreNonExistingTemplates", Qt.Checked)

        ignoreNonExistingTemplates = self.__settings.getKey(
            self.__settingsSection, "ignoreNonExistingTemplates")
        LOGGER.debug("> Setting '{0}' with value '{1}'.".format(
            "Ignore_Non_Existing_Templates_checkBox",
            foundations.common.getFirstItem(
                ignoreNonExistingTemplates.toInt())))
        self.Ignore_Non_Existing_Templates_checkBox.setCheckState(
            foundations.common.getFirstItem(
                ignoreNonExistingTemplates.toInt()))

    def __Ignore_Non_Existing_Templates_checkBox__stateChanged(self, state):
        """
		Defines the slot triggered by **Ignore_Non_Existing_Templates_checkBox** Widget when state changed.

		:param state: Checkbox state.
		:type state: int
		"""

        LOGGER.debug(
            "> Ignore non existing Templates state: '{0}'.".format(state))
        self.__settings.setKey(self.__settingsSection,
                               "ignoreNonExistingTemplates", state)

    def __Check_For_New_Releases_pushButton__clicked(self, checked):
        """
		Defines the slot triggered by **Check_For_New_Releases_pushButton** Widget when clicked.

		:param checked: Checked state.
		:type checked: bool
		"""

        self.checkForNewReleasesUi()

    @foundations.exceptions.handleExceptions(sibl_gui.exceptions.NetworkError)
    def __releasesFileReply__finished(self):
        """
		Defines the slot triggered by the releases file reply when finished.
		"""

        self.__engine.stopProcessing()

        if not self.__releasesFileReply.error():
            content = []
            while not self.__releasesFileReply.atEnd():
                content.append(
                    foundations.strings.toString(
                        self.__releasesFileReply.readLine()))

            LOGGER.debug("> Parsing releases file content.")
            sectionsFileParser = SectionsFileParser()
            sectionsFileParser.content = content
            sectionsFileParser.parse()

            releases = {}
            for remoteObject in sectionsFileParser.sections:
                if remoteObject != Constants.applicationName:
                    databaseTemplates = \
                    sibl_gui.components.core.database.operations.filterTemplates("^{0}$".format(remoteObject), "name")
                    databaseTemplate = foundations.common.getFirstItem([
                        foundations.common.getFirstItem(databaseTemplate)
                        for databaseTemplate in
                        sorted(((databaseTemplate, databaseTemplate.release)
                                for databaseTemplate in databaseTemplates),
                               reverse=True,
                               key=lambda x:
                               (foundations.strings.getVersionRank(x[1])))
                    ])
                    if not self.__engine.parameters.databaseReadOnly:
                        if databaseTemplate:
                            if databaseTemplate.release != sectionsFileParser.getValue(
                                    "Release", remoteObject):
                                releases[remoteObject] = ReleaseObject(
                                    name=remoteObject,
                                    repositoryVersion=sectionsFileParser.
                                    getValue("Release", remoteObject),
                                    localVersion=databaseTemplate.release,
                                    type=sectionsFileParser.getValue(
                                        "Type", remoteObject),
                                    url=sectionsFileParser.getValue(
                                        "Url", remoteObject),
                                    comment=sectionsFileParser.getValue(
                                        "Comment", remoteObject))
                        else:
                            if not self.Ignore_Non_Existing_Templates_checkBox.isChecked(
                            ):
                                releases[remoteObject] = ReleaseObject(
                                    name=remoteObject,
                                    repositoryVersion=sectionsFileParser.
                                    getValue("Release", remoteObject),
                                    localVersion=None,
                                    type=sectionsFileParser.getValue(
                                        "Type", remoteObject),
                                    url=sectionsFileParser.getValue(
                                        "Url", remoteObject),
                                    comment=sectionsFileParser.getValue(
                                        "Comment", remoteObject))
                    else:
                        LOGGER.info(
                            "{0} | '{1}' repository remote object skipped by '{2}' command line parameter value!"
                            .format(self.__class__.__name__, remoteObject,
                                    "databaseReadOnly"))
                else:
                    if Constants.version != sectionsFileParser.getValue(
                            "Release", remoteObject):
                        releases[remoteObject] = ReleaseObject(
                            name=remoteObject,
                            repositoryVersion=sectionsFileParser.getValue(
                                "Release", remoteObject),
                            localVersion=Constants.version,
                            url=sectionsFileParser.getValue(
                                "Url", remoteObject),
                            type=sectionsFileParser.getValue(
                                "Type", remoteObject),
                            comment=None)
            if releases:
                LOGGER.debug("> Initializing Remote Updater.")
                self.__remoteUpdater = RemoteUpdater(self, releases, Qt.Window)
                self.__remoteUpdater.show()
            else:
                self.__reportUpdateStatus and self.__engine.notificationsManager.notify(
                    "{0} | '{1}' is up to date!".format(
                        self.__class__.__name__, Constants.applicationName))
        else:
            raise sibl_gui.exceptions.NetworkError(
                "{0} | QNetworkAccessManager error code: '{1}'.".format(
                    self.__class__.__name__, self.__releasesFileReply.error()))

    def __getReleasesFile(self, url):
        """
		Gets the releases file.
		"""

        LOGGER.debug("> Downloading '{0}' releases file.".format(url.path()))

        self.__engine.startProcessing("Retrieving Releases File ...")
        self.__releasesFileReply = self.__networkAccessManager.get(
            QNetworkRequest(url))
        self.__releasesFileReply.finished.connect(
            self.__releasesFileReply__finished)

    @foundations.exceptions.handleExceptions(
        umbra.exceptions.notifyExceptionHandler,
        sibl_gui.exceptions.NetworkError, Exception)
    def checkForNewReleasesUi(self):
        """
		Checks for new releases.

		:return: Method success.
		:rtype: bool

		:note: May require user interaction.
		"""

        if not self.__networkAccessManager.networkAccessible():
            raise sibl_gui.exceptions.NetworkError(
                "{0} | Network is not accessible!".format(
                    self.__class__.__name__))

        self.__reportUpdateStatus = True
        if self.checkForNewReleases():
            return True
        else:
            raise Exception(
                "{0} | Exception raised while checking for new releases!".
                format(self.__class__.__name__))

    @foundations.exceptions.handleExceptions(sibl_gui.exceptions.NetworkError,
                                             Exception)
    def checkForNewReleases(self):
        """
		Checks for new releases.

		:return: Method success.
		:rtype: bool
		"""

        if not self.__networkAccessManager.networkAccessible():
            raise sibl_gui.exceptions.NetworkError(
                "{0} | Network is not accessible!".format(
                    self.__class__.__name__))

        self.__getReleasesFile(
            QUrl(os.path.join(self.__repositoryUrl, self.__releasesFileUrl)))
        return True