Пример #1
0
class Scene(QtGui.QGraphicsScene):
    def __init__(self):
        super(QtGui.QGraphicsScene, self).__init__()
        self.view = QtGui.QGraphicsView(self)

        self.webview = QGraphicsWebView()
        self.webview.setFlags(QtGui.QGraphicsItem.ItemClipsToShape)
        self.webview.setCacheMode(QtGui.QGraphicsItem.NoCache)
        self.addItem(self.webview)

        self.webview.loadFinished.connect(self.svgLoaded)

    def svgLoaded(self):
        frame = self.webview.page().mainFrame()
        fsize = frame.contentsSize()
        self.webview.resize(QtCore.QSizeF(fsize))
        self.view.resize(fsize.width() + 10, fsize.height() + 10)
        self.webview.page().mainFrame().evaluateJavaScript(getJsScript('circle-test.js')) 
class ARPAP_SpatialReportDialogChart(QtGui.QDialog, FORM_CLASS):

    webview = None
    chartTypes = dict()
    algorithm = None
    reslayer = list()
    modelCategory = None
    modelValue = None
    validation = None
    chartGenerated = False
    mapChartType = {'bar':bar,'pie':pie}
    
    def __init__(self, parent=None):
        super(ARPAP_SpatialReportDialogChart, self).__init__(parent)
        self.parent = parent
        self.algorithm = parent.algorithm
        self.reslayer = parent.reslayer
        self.validation = ValidationInputdata(self,self.tr)
        self.setupUi(self)
        self.manageGui()
    
    
        
        
    def manageGui(self):
        self.chartGeneratorButton.setIcon(QtGui.QIcon(':/plugins/ARPAP_SpatialReport/icons/histogram.png'))
        self.statisticsGeneratorButton.setIcon(QtGui.QIcon(':/plugins/ARPAP_SpatialReport/icons/mActionOpenTable.png'))
        self.savePngFile.setIcon(QtGui.QIcon(':/plugins/ARPAP_SpatialReport/icons/mActionFileSave.png'))
        self.saveCSVFile.setIcon(QtGui.QIcon(':/plugins/ARPAP_SpatialReport/icons/mActionFileSave.png'))
        QObject.connect(self.chartGeneratorButton, SIGNAL('clicked()'),self.generateChart)
        QObject.connect(self.statisticsGeneratorButton, SIGNAL('clicked()'),self.generateStatistics)
        QObject.connect(self.savePngFile, SIGNAL('clicked()'),self.savepng)
        QObject.connect(self.saveCSVFile, SIGNAL('clicked()'),self.saveCSV)
        self.populateChartTypesCombo()
        self.populateCombosField()
        #manage resizeEvent QWebview
        def onResizeWebview(e):
            if self.chartGenerated:
                self.generateChart()
        self.graphicsView.resizeEvent = onResizeWebview 
        
    def populateChartTypesCombo(self):
        self.chartTypes = {
                           'bar':self.tr('Bar (occurrences)'),
                           'pie':self.tr('Pie (distribution)'),
                           }
        for type in self.chartTypes.keys():
            self.selectChartType.addItem(self.chartTypes[type],type)
            
    def getChartType(self):
        return self.selectChartType.itemData(self.selectChartType.currentIndex())
    
    def getSelectedListViewItem(self,listViewName):
        
        model_index = getattr(self,listViewName.lower()+'FieldListView').currentIndex()
        if model_index.row() != -1:
            return getattr(self,'model'+listViewName.capitalize()).itemFromIndex(model_index)

    def populateCombosField(self):
        layer = self.reslayer[0]
        #populate category listview
        self.modelCategory = QtGui.QStandardItemModel(self.categoryFieldListView)
        self.modelValue = QtGui.QStandardItemModel(self.valueFieldListView) 
        self.categoryFieldListView.setModel(self.modelCategory)
        self.valueFieldListView.setModel(self.modelValue)
        for field in layer.pendingFields():
            itemCategory = QtGui.QStandardItem(self.parent.formatFieldToString(field))
            itemCategory.setData(field)
            itemValue = QtGui.QStandardItem(self.parent.formatFieldToString(field))
            itemValue.setData(field)
            self.modelCategory.appendRow(itemCategory)
            self.modelValue.appendRow(itemValue)

    def _purificateValues(self,value):
        if type(value) == QDate:
            value = value.toString()
        elif type(value) == QPyNullVariant:
            value = None
        return value

    def generateChart(self):
        scene = QtGui.QGraphicsScene()
        self.graphicsView.setScene(scene)
        
        #select data adn chart type
        chartType = self.getChartType()
        if self.validation.validateChart(chartType):
            chart = self.mapChartType[chartType]()
            
             
            self.webview = QGraphicsWebView()
            self.webview.resize(self.graphicsView.width()-20,self.graphicsView.height()-20)
            path = os.path.dirname(__file__)+'/js/'
            chartData = getattr(self,chartType + 'ChartData' )()
            chart.setData(chartData)
            self.webview.setHtml(chart.getHTML(),baseUrl=QUrl().fromLocalFile(path))
            self.webview.setFlags(QtGui.QGraphicsItem.ItemClipsToShape)
            self.webview.setCacheMode(QtGui.QGraphicsItem.NoCache)
            frame = self.webview.page().mainFrame()
            frame.setScrollBarPolicy(Qt.Vertical,Qt.ScrollBarAlwaysOff)
            frame.setScrollBarPolicy(Qt.Horizontal,Qt.ScrollBarAlwaysOff)        
            scene.addItem(self.webview)
            self.graphicsView.show()
            self.savePngFile.setEnabled(True)
            self.chartGenerated = True
        else:
            self.showValidateErrors()
        
    def barChartData(self):
        categoryItem = self.getSelectedListViewItem('category')
        layer = self.reslayer[0]
        features = layer.getFeatures()
        occourences = dict()
        for f in features:
            value = self._purificateValues(f.attribute(categoryItem.data().name()))
            if value not in occourences:
                occourences[value] = 0
            occourences[value] += 1 
            
        chartData = {'values':[{'label':k,'value':occourences[k]} for k in occourences.keys()]}    
        return [chartData]
    
    def pieChartData(self):
        categoryItem = self.getSelectedListViewItem('category')
        valueItem = self.getSelectedListViewItem('value')
        layer = self.reslayer[0]
        features = layer.getFeatures()
        occourences = dict()
        totValue = 0
        for f in features:
            key = f.attribute(categoryItem.data().name())
            if not key:
                key = self.tr('Unknown')
            value = self._purificateValues(f.attribute(valueItem.data().name()))
            if key not in occourences:
                occourences[key] = 0
            if not value:
                value = 0
            occourences[key] += value
            totValue += value
            
        chartData = [{'key':k,'y':float(float(occourences[k])/float(totValue))} for k in occourences.keys()] 
        return chartData
    
    def generateStatistics(self):
        categoryItem = self.getSelectedListViewItem('category')
        valueItem = self.getSelectedListViewItem('value')
        layer = self.reslayer[0]
        features = layer.getFeatures()
        occourences = dict()
        for f in features:
            key = self._purificateValues(f.attribute(categoryItem.data().name()))
            if not key:
                key = self.tr('Unknown')
            value = self._purificateValues(f.attribute(valueItem.data().name()))
            if key not in occourences:
                occourences[key] = list()
            if not value:
                value = 0
            occourences[key].append(value)
        # statistics calcs
        self.statistics = dict()
        model = QtGui.QStandardItemModel(self.statisticsTableView)
        self.statisticsTableView.setModel(model)
        c = 0
        self.headersFieldsTableMethods = {
                                     self.tr('Sum'):sum,
                                     self.tr('Min'):min,
                                     self.tr('Max'):max,
                                     self.tr('Median'):numpy.median,
                                     self.tr('Mean'):numpy.mean,
                                     self.tr('Standard deviation'):numpy.std
                                     }
        print occourences
        for columnName in self.headersFieldsTableMethods:
            model.setHorizontalHeaderItem(self.headersFieldsTableMethods.keys().index(columnName),QtGui.QStandardItem(columnName))
        for key in occourences:
            if key not in self.statistics:
                self.statistics[key] = dict()
            rowToAppend = list()
            for func in self.headersFieldsTableMethods:
                self.statistics[key][func] = str(self.headersFieldsTableMethods[func](occourences[key]))
                rowToAppend.append(QtGui.QStandardItem(self.statistics[key][func]))
            model.appendRow(rowToAppend)
            model.setVerticalHeaderItem(c,QtGui.QStandardItem(str(key)))
            c += 1
        self.saveCSVFile.setEnabled(True)
    
    def sum(self,data):
        return sum(data)
    def min(self,data):
        return min(data)
    def max(self,data):
        return max(data)
        
    def savepng(self):
        dialog = QtGui.QFileDialog()                                              
        dialog.setAcceptMode(1)
        dialog.setDefaultSuffix("png")
        dialog.setNameFilters(["PNG files (*.png)", "All files (*)"])
        if dialog.exec_() == 0:                                            
            return
        pathFileToSave = dialog.selectedFiles()[0]
        p = QtGui.QPixmap.grabWidget(self.graphicsView)
        res = p.save(pathFileToSave)
        
    def saveCSV(self):
        dialog = QtGui.QFileDialog()                                              
        dialog.setAcceptMode(1)
        dialog.setDefaultSuffix("csv")
        dialog.setNameFilters(["CSV files (*.csv)", "All files (*)"])
        if dialog.exec_() == 0:                                             
            return
        pathFileToSave = dialog.selectedFiles()[0]
        fileCSV = open(pathFileToSave, 'wb')
        compilatorCSV = csv.writer( fileCSV, delimiter=';' )
        header = ['']
        header.extend(self.headersFieldsTableMethods.keys())
        compilatorCSV.writerow(header)
        for i in self.statistics:   
            row = [i]
            dataRow = [x.encode('utf-8') for x in self.statistics[i].values()]   
            row.extend(dataRow)                     
            compilatorCSV.writerow(row)
        fileCSV.close()
        
    def showValidateErrors(self):
        QtGui.QMessageBox.warning( self, self.tr("ARPA Spatial Report"), self.tr( "Validation error:\n" ) + ';\n'.join(self.validation.getErrors()) )

        
        

        
    
    
   
        
            
    
        

        
Пример #3
0
class Lectern(QMainWindow):

    def __init__(self, parent=None):
        super(Lectern, self).__init__(parent)
        self.anchor = None
        
        self.initMainMenu()
        self.initToolbar()

        splitter = QSplitter()
        self.tocView = QTreeView()
        self.tocView.clicked.connect(self.navTo)
        self.tocModel = TableOfContents()
        self.tocModel.isEmpty.connect(self.handleTOCLoad)
        self.tocView.setModel(self.tocModel)
        self.tocView.expandAll()
        self.tocView.hide()
        splitter.addWidget(self.tocView)

        self.webView = QGraphicsWebView()
        frame = self.webView.page().mainFrame()
        scene = QGraphicsScene()
        scene.addItem(self.webView)
        self.graphicsView = GraphicsView(scene)
        self.graphicsView.setFrameShape(QFrame.NoFrame)
        glWidget = QGLWidget(self)
        self.graphicsView.setViewport(glWidget)

        self.webView.loadFinished.connect(self.handleLoad)

        splitter.addWidget(self.graphicsView)
        self.setCentralWidget(splitter)

        self.ebook_info = {}
        self.setWindowTitle('Lectern')

        try:
            self.ebook_info = self.openBook(QApplication.arguments()[1])
        except IndexError:
            pass
            
    def initMainMenu(self):
        menuBar = self.menuBar()
        menuBar.setNativeMenuBar(True)
        
        # TODO: add CROSS-PLATFORM shortcut keys. (e.g. For Quit, use ⌘Q on Mac OS X, ALT-F4 elsewhere)
        fileMenu = QMenu('File', menuBar)
        navMenu = QMenu('Navigate', menuBar)
        
        # File Menu
        openAction = QAction('Open', fileMenu)
        openAction.triggered.connect(self.chooseEbook)
        fileMenu.addAction(openAction)
        
        quitAction = QAction('Quit', fileMenu)
        quitAction.triggered.connect(self.closeEvent)
        fileMenu.addAction(quitAction)
        
        # Nav Menu
        prevChatperAction = QAction('Previous Chapter', navMenu)
        prevChatperAction.triggered.connect(self.prevChapter)
        navMenu.addAction(prevChatperAction)
        
        nextChatperAction = QAction('Next Chapter', navMenu)
        nextChatperAction.triggered.connect(self.nextChapter)
        navMenu.addAction(nextChatperAction)
        
        menuBar.addMenu(fileMenu)
        menuBar.addMenu(navMenu)
    
    def initToolbar(self):
        toolBar = QToolBar(self)

        chooseAction = QAction(self.style().standardIcon(
            QStyle.SP_DialogOpenButton), 'Open', toolBar)
        chooseAction.triggered.connect(self.chooseEbook)
        toolBar.addAction(chooseAction)

        self.prevAction = QAction(self.style().standardIcon(
            QStyle.SP_ArrowBack), 'Go back', toolBar)
        self.prevAction.setEnabled(False)
        self.prevAction.triggered.connect(self.prevChapter)
        toolBar.addAction(self.prevAction)

        self.nextAction = QAction(self.style().standardIcon(
            QStyle.SP_ArrowForward), 'Go forward', toolBar)
        self.nextAction.setEnabled(False)
        self.nextAction.triggered.connect(self.nextChapter)
        toolBar.addAction(self.nextAction)

        self.addToolBar(toolBar)

    def chooseEbook(self):
        path = QFileDialog.getOpenFileName(self, 'Open eBook', QDesktopServices.storageLocation(
            QDesktopServices.DocumentsLocation),'EPUBs (*.epub)')

        if not isfile(path):
            return

        if self.ebook_info is not None and 'temp_path' in self.ebook_info:
            if exists(self.ebook_info['temp_path']):
                rmtree(self.ebook_info['temp_path'])

        path = QDir.toNativeSeparators(path)
        self.ebook_info = self.openBook(path)

    def openBook(self, path):
        ebook_info = {}
        path = realpath(path)
        if not isfile(path):
            QMessageBox.critical(self, 'File not found', 'File not found')

        mimetype, _ = guess_type(path)
        if mimetype != 'application/epub+zip':
            QMessageBox.critical(self, 'Not an EPUB', 'Not an EPUB')
            return None

        ebook = ZipFile(path)

        names = ebook.namelist()

        if not 'META-INF/container.xml' in names:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'container.xml not '\
                    'found')
            return None

        container_tree = etree.parse(ebook.open('META-INF/container.xml'))
        rootfile = container_tree.xpath("//*[local-name() = 'rootfile']")
        if len(rootfile) == 0:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'root not found in '\
                    'manifest')
            return None

        content_opf = rootfile[0].get('full-path')
        if content_opf is None:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'content.opf not found')
            return None

        ebook_info['opf_root'] = posixpath.dirname(content_opf)

        tree = etree.parse(ebook.open(content_opf))
        manifest = tree.xpath("*[local-name() = 'manifest']")
        if len(manifest) == 0:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'Manifest not found')
            return None
        manifest = manifest[0]

        items = {}
        for item in manifest:
            item_id = item.get('id')
            if item_id is None:
                ebook.close()
                QMessageBox.critical(self, 'Invalid EPUB', 'Item has no id')
                return None

            href = item.get('href')
            if href is None:
                ebook.close()
                QMessageBox.critical(self, 'Invalid EPUB', 'Item has no href')
                return None

            items[item_id] = href

        spine = tree.xpath("*[local-name() = 'spine']")
        if len(spine) == 0:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'Spine not found')
            return None
        spine = spine[0]

        ebook_info['chapters'] = []
        for itemref in spine:
            idref = itemref.get('idref')
            if not idref in items:
                ebook.close()
                QMessageBox.critical(self, 'Invalid EPUB', 'Item in spine '\
                        'not found in manifest')
                return None
            ebook_info['chapters'].append(items[idref])

        if len(ebook_info['chapters']) == 0:
            ebook.close()
            QMessageBox.critical(self, 'Invalid EPUB', 'Content not found')
            return None

        # Table of contents
        toc = tree.find("//*[@href='toc.ncx']")
        if toc is not None:
            toc_path = posixpath.join(ebook_info['opf_root'], 'toc.ncx')
            if toc_path in names:
                toc_tree = etree.parse(ebook.open(toc_path))
                navMap = toc_tree.xpath("//*[local-name() = 'navMap']")
                if len(navMap) > 0:
                    self.tocModel.importNavMap(navMap[0])

        temp = QDir.toNativeSeparators(QDesktopServices.storageLocation(
            QDesktopServices.TempLocation))

        # In case we have two copies of Lectern opening the same book.
        filename = '{0}-{1}'.format(splitext(basename(path))[0], uuid4())
        ebook_info['temp_path'] = join(temp, filename)
        if exists(ebook_info['temp_path']):
            rmtree(ebook_info['temp_path'])

        ebook.extractall(ebook_info['temp_path'])
        ebook.close()
        ebook_info['index'] = 0
        url = join(ebook_info['temp_path'], ebook_info['opf_root'],
                ebook_info['chapters'][0])
        self.webView.setUrl(QUrl(url))
        if len(ebook_info['chapters']) > 1:
            self.nextAction.setEnabled(True)
        return ebook_info

    def prevChapter(self):
        index = self.ebook_info['index']
        chapters = self.ebook_info['chapters']
        if index > 0:
            index -= 1
            if index == 0:
                self.prevAction.setEnabled(False)
            url = join(self.ebook_info['temp_path'],
                    self.ebook_info['opf_root'], chapters[index])
            self.webView.setUrl(QUrl(url))
            self.ebook_info['index'] = index
            self.nextAction.setEnabled(True)

    def nextChapter(self):
        index = self.ebook_info['index']
        chapters = self.ebook_info['chapters']
        if index < len(chapters) - 1:
            index += 1
            if index == len(chapters) - 1:
                self.nextAction.setEnabled(False)
            url = join(self.ebook_info['temp_path'],
                    self.ebook_info['opf_root'], chapters[index])
            self.webView.setUrl(QUrl(url))
            self.ebook_info['index'] = index
            self.prevAction.setEnabled(True)

    def closeBook(self):
        if self.ebook_info is not None and 'temp_path' in self.ebook_info:
            if exists(self.ebook_info['temp_path']):
                rmtree(self.ebook_info['temp_path'])
        self.ebook_info = None

        self.tocView.hide()
        self.prevAction.setEnabled(False)
        self.nextAction.setEnabled(False)

    def closeEvent(self, event = 0):
        if(event == 0):
            event = PyQt4.QtGui.QCloseEvent()

        self.closeBook()
        super(Lectern, self).closeEvent(event)

        # Suppress "cannot make invalid context current" warnings
        sys.exit(0)

    def navTo(self, index):
        navPoint = index.internalPointer()
        href = posixpath.join(self.ebook_info['temp_path'],
                self.ebook_info['opf_root'], navPoint.src)

        try:
            path, anchor = href.split('#')
            if path == self.webView.url().path():
                self.webView.page().mainFrame().scrollToAnchor(anchor)
                return
            else:
                self.anchor = anchor
        except ValueError:
            pass
        url = QUrl.fromEncoded(href)
        self.webView.setUrl(url)

    def handleLoad(self, ok):
        if self.anchor is not None:
            self.webView.page().mainFrame().addToJavaScriptWindowObject("app", self);
            self.webView.page().mainFrame().scrollToAnchor(self.anchor)

    def handleTOCLoad(self, isEmpty):
        if isEmpty:
            self.tocView.hide()
        else:
            self.tocView.show()