class Window(QtGui.QMainWindow): def __init__(self, simulator, parent=None): super(Window, self).__init__(parent) self.simulator = simulator self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.canvas.paintEvent = self.on_canvas_paint_event self.ui.canvas.resizeEvent = self.on_canvas_resize_event self.timer = QtCore.QTimer(self) self.timer.timeout.connect(self.on_timeout) self.timer.start(FRAME_TIME_MS) self.set_simulator_bounds() def on_canvas_paint_event(self, event): painter = QtGui.QPainter(self.ui.canvas) pixel_scale = self.ui.canvas.height() / VIEW_HEIGHT pen = QtGui.QPen(QtGui.QColor(0, 0, 0), 2, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) brush = QtGui.QBrush(QtGui.QColor(0xE0, 0xF0, 0xFF)) painter.setPen(pen) painter.setBrush(brush) painter.setRenderHint(QtGui.QPainter.Antialiasing) for circle in self.simulator.circles: x = circle.position.x * pixel_scale + self.ui.canvas.width() / 2 y = circle.position.y * pixel_scale + self.ui.canvas.height() / 2 radius = circle.radius * pixel_scale painter.drawEllipse(QtCore.QPoint(x, y), radius, radius) for polygon in self.simulator.polygons: brush = QtGui.QBrush(QtGui.QColor(0xE0, 0xF0, 0xFF)) painter.setBrush(brush) points = [] for point in polygon.transformed_points(): x = point.x * pixel_scale + self.ui.canvas.width() / 2 y = point.y * pixel_scale + self.ui.canvas.height() / 2 points.append(QtCore.QPoint(x, y)) painter.drawPolygon(points) def on_canvas_resize_event(self, event): self.set_simulator_bounds() def set_simulator_bounds(self): unit_scale = VIEW_HEIGHT / self.ui.canvas.height() min_x = -self.ui.canvas.width() * unit_scale / 2 + 1 min_y = -VIEW_HEIGHT / 2 + 1 max_x = -min_x max_y = -min_y self.simulator.set_bounds(min_x, min_y, max_x, max_y) def on_timeout(self): self.simulator.advance(FRAME_TIME_MS / 1000.0) self.update()
class Main(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.createUI() self.createAndConnectModel() self.createAndConnectDelegate() self.populateSetTypeMenu() self.delegate.mainWindowInitialized() self.raise_() def createUI(self): self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.unsorted_files_view.horizontalHeader().setResizeMode(QtGui.QHeaderView.Custom) self.ui.unsorted_files_view.setSortingEnabled(True) self.ui.unsorted_files_view.sortByColumn(1, QtCore.Qt.AscendingOrder) def createAndConnectModel(self): self.model = UnsortedFilesModel(self) self.ui.unsorted_files_view.setModel(self.model) def createAndConnectDelegate(self): self.delegate = UnsortedFilesDelegate(self.model, self.ui.unsorted_files_view) self.ui.actionAdd.triggered.connect(self.delegate.actionFileAdd) self.ui.actionEdit.triggered.connect(self.delegate.actionEdit) self.ui.actionSortSelected.triggered.connect(self.delegate.actionSortSelected) self.ui.unsorted_files_view.doubleClicked.connect(self.delegate.rowDoubleClicked) def populateSetTypeMenu(self): file_type_manager = libentr.FileTypeManager() file_type_manager.register_default_types() for ftype in file_type_manager.list_of_types(): set_type_action = self.ui.menuSet_Type.addAction(ftype) set_type_action.triggered.connect(ScopeCapturer(self.delegate.actionSetType, ftype)) def resizeEvent(self, resizeEvent): self.ui.unsorted_files_view.setColumnWidth(0,500) self.ui.unsorted_files_view.setColumnWidth(1,400) self.ui.unsorted_files_view.setColumnWidth(2,250) self.ui.unsorted_files_view.setColumnWidth(3,250) self.ui.unsorted_files_view.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.Interactive) self.ui.unsorted_files_view.horizontalHeader().setResizeMode(1, QtGui.QHeaderView.Interactive) self.ui.unsorted_files_view.horizontalHeader().setResizeMode(2, QtGui.QHeaderView.Interactive) self.ui.unsorted_files_view.horizontalHeader().setResizeMode(3, QtGui.QHeaderView.Interactive)
class MainPseWindow(QMainWindow): ''' @if English Main application window. @endif @if Slovak Hlavne okno aplikacie. Ovladacie klavesy a skratky editora diagramov. ESC - Cancel action DEL - Delete selected component or net C - Copy component M - Move N - Add net R - Rotate right L - Rotate left CTRL+1 Start simulatora / generatora CTRL+2 Stop simulatora CTRL+3 Stop simulatora a reset komponentov @endif ''' def __init__(self, fileName='', parent=None): super(MainPseWindow, self).__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) layout = QHBoxLayout() # horizontal box layout self.view = MyQGraphicsView(self) self.diagram = Diagram(self) # Diagram is QGraphicsScene self.view.setScene(self.diagram) # set scene to the view self.view.setSceneRect(QRectF(-2000, -2000, 4000, 4000)) self.view.centerOn(QPointF(0, 0)) # pociatocna poloha # vyvolanie mouseMoveEvent pri kazdom pohybe mysi self.view.setMouseTracking(True) # self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) layout.addWidget(self.view) self.widget = QWidget() self.widget.setLayout(layout) self.widget.setContextMenuPolicy(Qt.CustomContextMenu) self.setCentralWidget(self.widget) self.widget.customContextMenuRequested.connect(self.createContextMenu) self.fileName = fileName # inicializacia diagramu pri zadanom mene diagramu if self.fileName == '': self.setWindowTitle('Untitled.pse') else: self.diagram.diagramLoad(self.fileName) self.setWindowTitle(self.fileName) self.setWindowIcon(QIcon('./icons/ikona_pse_128x128.png')) self.simEngine = None self.recentFileActs = [] self.init_recent_files() self.setStatusBar(QStatusBar(self)) self.lib_win = None # Liblary window def createContextMenu(self): '''create and show context menu for component''' menu = QMenu(self) menu.addAction(self.ui.ActionEditComponent) menu.addSeparator() menu.addAction(self.ui.ActionRotateLeftComponent) menu.addAction(self.ui.ActionRotateRightComponent) menu.addSeparator() menu.addAction(self.ui.ActionFlipHorizontalComponent) menu.addAction(self.ui.ActionFlipVerticalComponent) menu.exec_(QCursor.pos()) def _setGridAction(self, action): '''set diagram grid according to action data''' grid_type = action.data() self.diagram.setGrid(grid_type) # hide def _snapGrid(self, checked): '''set/unset snapping on the grid, according action button''' self.diagram.snapOnGrid = checked def saveDiagram(self): '''! @if English @endif @if Slovak Uloženie diagramu. V prípade nezadaného mena vyvolá štandardný dialóg pre zadanie mena a cesty a uloženie diagramu do súboru. @endif ''' self.diagram.mode = MODE.MOVE # Reset vsetkych komponentov, zmazanie poli v hodnotach parametrov (ukladali by sa do suboru) for comp in self.diagram.componentList: comp.sim(SIM_RESET, 0, 0, 0) if self.fileName == '': data = QFileDialog.getSaveFileName(self, 'Save', '..', filter='*.pse') self.fileName = data[0] # kontrola na nezadane meno suboru if self.fileName != '': if self.fileName.endswith('.pse') is False: self.fileName = self.fileName + '.pse' self.diagram.diagramSave(self.fileName) self.setWindowTitle(self.fileName) def saveAsDiagram(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE # Reset vsetkych komponentov, zmazanie poli v hodnotach parametrov (ukladali by sa do suboru) for comp in self.diagram.componentList: comp.sim(SIM_RESET, 0, 0, 0) data = QFileDialog.getSaveFileName(self, 'Save As', '..', filter='*.pse') self.fileName = data[0] if self.fileName != '': self.fileName = self.fileName.replace('.txt', '.pse') if self.fileName.endswith('.pse') is False: self.fileName = self.fileName + '.pse' self.diagram.diagramSave(self.fileName) self.setWindowTitle(self.fileName) def openDiagramDialog(self): self.diagram.mode = MODE.MOVE filename = QFileDialog.getOpenFileName(self, 'Open', '..', filter='*.txt *.pse') if isinstance(filename, tuple): filename = filename[0] # cut the filter if filename: self.loadDiagram(filename) def loadDiagram(self, filename): if self.fileName != '': self.diagram.deleteAll() self.fileName = filename self.diagram.diagramLoad(filename) self.setWindowTitle(filename) self.add_to_recent(filename) def exportImage(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE fileName = QFileDialog.getSaveFileName(self, 'Save image', '..', filter='*.png') fn = fileName[0] if fn is not None: if not fn.endswith('.png'): fn = fn + '.png' if six.PY2: geometry = self.view.viewport().geometry() rect = self.view.mapToScene(geometry).boundingRect() pixMap = QPixmap.grabWidget(self.view, x=0, y=0, width=rect.width(), height=rect.height()) else: pixMap = self.view.grab() pixMap.save(fn) def simStart(self): '''! @if English @endif @if Slovak Spustenie simulacie. Funkcia vytvori objekt simulatora a spusti simulaciu. Na zaciatku simulacie su reinicializovane zoznamy prepojeni a komponentov. V pripade prebiehajucej simulacie sa simulacia restartuje. @todo simulacia viacerych diagramov spojenie zoznamov komponentov a prepojeni @endif ''' self.diagram.mode = MODE.SIMULATION if self.simEngine: self.simEngine.stopSimulation() self.simEngine = SimulatorEngine(self.diagram) self.simEngine.startSimulation() return self.simEngine def simStop(self): '''! @if English @endif @if Slovak @endif ''' if self.simEngine is not None: self.simEngine.stopSimulation() time.sleep(0.3) # cakanie na bezpecne ukoncenie threadu self.simEngine = None self.diagram.mode = MODE.MOVE def simReset(self): """! @if English @endif @if Slovak Zastavenie prebiehajucej simulacie a reset vsetkych komponentov. @endif """ self.diagram.mode = MODE.MOVE # 1. zastavenie simulacie if self.simEngine is not None: self.simEngine.stopSimulation() time.sleep(0.3) # cakanie na bezpecne ukoncenie threadu self.simEngine = None # 2. reset vsetkych komponentov, prip. re-inicializacia terminalov for comp in self.diagram.componentList: comp.sim(SIM_RESET, 0, 0, 0) def newDiagramWindow(self): '''! @if English @endif @if Slovak Funkcia otvorí nové okno pre diagram. @endif ''' self.diagram.mode = MODE.MOVE self.newWindow = MainPseWindow('') self.newWindow.setGeometry(120, 120, 800, 500) self.newWindow.show() def newDiagram(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE # @todo - v pripade existujuceho diagramu dialog o ulozeni diagramu ... # ukoncenie simulacie self.simReset() # zmazanie vsetkych komponentov self.diagram.deleteAll() self.fileName = '' self.setWindowTitle('Untitled.pse') def rotateLeft(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.rotateComponentLeft() self.diagram.mode = MODE.MOVE def rotateRight(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.rotateComponentRight() self.diagram.mode = MODE.MOVE def flipHorizontal(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE self.diagram.flipComponentHorizontal() def flipVertical(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE self.diagram.flipComponentVertical() def delComponent(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE for item in self.diagram.selectedItems(): self.diagram.deleteComponent(item) self.diagram.update() def move(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE print('mode move') def frontComponent(self): '''! @if English @endif @if Slovak @endif ''' pass def backComponent(self): '''! @if English @endif @if Slovak @endif ''' pass def addNet(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.ADD_NEW_NET def delNet(self): '''! @if English @endif @if Slovak @endif ''' for net in self.diagram.netList: if net.isActive is True: self.diagram.deleteNet(net) def selNet(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.SELECT_NET def addVertex(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.INSERT_VERTEX def delVertex(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.DELETE_VERTEX def moveVertex(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.MOVE def addConnection(self): '''! @if English @endif @if Slovak @endif ''' self.diagram.mode = MODE.ADD_JUNCTION def about(self): '''show about dialog''' s = "The <b>pse</b> is simple python simulator and block editor<br>" \ "<br>Project of Research Centre University of Zilina<br>" \ "Zilina, Slovak Republic<br>" \ "<b>E-mail</b> [email protected]<br>" \ "<b>Version</b> 151214_0.11<br>" QMessageBox.about(self, "About pse", s) def editComponentProperties(self): '''Open Component Properties dialog on active component''' comp = self.diagram.activeComponent if not isinstance(comp, Component): LOG.debug('Cannot edit: %s' % comp) return if comp: # vypocet polohy okna pre editovanie vlastnosti komponentu # okno sa nachadza v blizkosti polohy komponentu winPos = self.view.mapFromScene( QPoint(comp.position.x(), comp.position.y())) + self.pos() w = CompProperties(comp, winPos, self) w.show() self.diagram.mode = MODE.MOVE def closeEvent(self, event): '''! @if English @endif @if Slovak Ukoncenie aplikacie. Pri ukonceni aplikacie sa zastavi prebiehajuca simulacia. @todo - kontrola na neulozeny subor @endif ''' reply = QMessageBox.question(self, 'Message', "Are you sure to quit?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: # ukoncenie simulacie self.simReset() # zmazanie vsetkych komponentov a ukoncenie refresovacieho threadu self.diagram.deleteAll() self.diagram.stopRefresh() if self.lib_win: self.lib_win.close() # close liblary event.accept() else: event.ignore() def keyPressEvent(self, event): key = event.key() if key == Qt.Key_Escape: print('>>> Key event - ESC - Cancel action') self.diagram.cancelAction() elif key == Qt.Key_C: print('>>> Key event - C - Copy action') self.diagram.copyComponent() elif key == Qt.Key_M: print('>>> Key event - M - Move ') self.move() elif key == Qt.Key_N: print('>>> Key event - N - Add net ') self.addNet() elif key == Qt.Key_R: print('>>> Key event - R - Rotate right') self.diagram.rotateComponentRight() elif key == Qt.Key_L: print('>>> Key event - L - Rotate left') self.diagram.rotateComponentLeft() elif key == Qt.Key_Q: print('>>> Key event - Q - Component list dump') for comp in self.diagram.componentList: print(comp) elif key == Qt.Key_W: print('>>> Key event - W - Net list dump') for net in self.diagram.netList: print(net) elif key == Qt.Key_Delete: print('>>> Key event - DEL - Delete') for item in self.diagram.selectedItems(): if isinstance(item, Component): self.diagram.deleteComponent(item) elif isinstance(item, Net): self.diagram.deleteNet(item) self.diagram.update() def init_recent_files(self): '''inicialization of File->Recent''' for _ in range(MAX_RECENT): act = QAction(self, visible=False, triggered=self.__openRecentFile) self.ui.recent.addAction(act) self.recentFileActs.append(act) self._updateRecentFileActions() def _updateRecentFileActions(self): ''' ''' settings = QSettings("PSE", 'data') recent = settings.value("recent", defaultValue=[]) numRecentFiles = min(len(recent), MAX_RECENT) for i in range(numRecentFiles): path = recent[i] filename = os.path.basename(path) text = "&%d %s" % (i + 1, filename) act = self.recentFileActs[i] act.setText(text) act.setData(path) act.setVisible(True) act.setStatusTip('%s' % path) icon = QIcon('./icons/ikona_pse_128x128.png') act.setIcon(icon) def add_to_recent(self, filename): '''remember current file to the recent files ''' settings = QSettings("PSE", 'data') recent = settings.value("recent", defaultValue=[]) try: recent.remove(filename) except ValueError: pass recent.insert(0, filename) settings.setValue('recent', recent) settings.sync() self._updateRecentFileActions() def __openRecentFile(self): '''open choosed diagram from recent files''' action = self.sender() filename = str(action.data()) self.loadDiagram(filename) def show_libwindow(self): '''Show liblary window''' if not self.lib_win: self.lib_win = Library() self.lib_win.setGeometry(20, 20, 400, 500) self.lib_win.show()
return else: if ui.tran_data_file_text.text() == new_dir: return else: ui.tran_data_file_text.setText(new_dir) ui.textBrowser.append("发射文件路径 has been changed to: " + new_dir) set_tran_data_file(ui) if __name__ == '__main__': app = QApplication(sys.argv) MainWindow = QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() dispaly_all(ui) ui.tran_address_text.editingFinished.connect(partial(set_tran_address, ui)) ui.rece_address_text.editingFinished.connect(partial(set_rece_address, ui)) ui.GNUradio_file_text.editingFinished.connect( partial(set_GNUradio_file, ui)) ui.data_file_text.editingFinished.connect(partial(set_data_file, ui)) ui.tran_data_file_text.editingFinished.connect( partial(set_tran_data_file, ui)) ui.tran_model_box.currentIndexChanged.connect(partial(set_tran_model, ui)) ui.tran_kind_box.currentIndexChanged.connect(partial(set_tran_kind, ui)) ui.rece_kind_box.currentIndexChanged.connect(partial(set_rece_kind, ui)) ui.f_tran_ad_btn.clicked.connect(partial(find_tran_address, ui)) ui.f_rece_ad_btn.clicked.connect(partial(find_rece_address, ui)) ui.only_tran_btn.clicked.connect(partial(start_only_tran, ui))
class Main(QMainWindow): def __init__(self): QMainWindow.__init__(self) # This is always the same self.ui = Ui_MainWindow() self.ui.setupUi(self) def add_file(self): """Add files or directories to the list of files/directories""" file_dialog = QFileDialog(self) if file_dialog.exec_(): filenames = file_dialog.selectedFiles() self.ui.listWidget.addItems(filenames) self.ui.encryptButton.setEnabled(True) def remove_file(self): """Removes selected files (addresses) from the list""" listWidget = self.ui.listWidget selected = listWidget.selectedItems() for item in selected: row = listWidget.row(item) listWidget.takeItem(row) del item if listWidget.count() == 0: # if list is empty, remove and encrypt buttons disabled self.ui.removeButton.setEnabled(False) self.ui.encryptButton.setEnabled(False) def selection_changed(self): """ Triggered when there is a change in selection in the list Item selected/deselected in the list. """ listWidget = self.ui.listWidget if listWidget.count() > 0: self.ui.removeButton.setEnabled(True) else: self.ui.removeButton.setEnabled(False) def encrypt(self): """Implementation of UI's "Encrypt" button function""" listWidget = self.ui.listWidget # open a dialog to choose/create file that will be our encrypted file filter = 'Encrypted (*.encrypted)' save_file = QFileDialog.getSaveFileName(self, 'Save encrypted file', filter=filter)[0] tempfile = save_file + ".tmp" if save_file: # Making a tar archive from all files in the list and save tar as # chosen by user in file dialog with tarfile.open(tempfile, "w") as tar: for i in range(listWidget.count()): item = listWidget.item(i).text() tar.add(item, split(item)[1]) # Getting password(key) for encryption pass_dialog = PasswordDlg(self) if pass_dialog.exec_(): password = pass_dialog.password() cipher = MyCipher(str(password), save_file) if cipher.encrypt(): self.message_box("Successful Encryption!") os.remove(tempfile) def browse(self): self.encrypted_file = QFileDialog.getOpenFileName()[0] self.ui.lineEdit.setText(self.encrypted_file) def text_changed(self): if self.ui.lineEdit.text(): self.ui.decryptButton.setEnabled(True) else: self.ui.decryptButton.setEnabled(False) def decrypt(self): """Implementation of UI's "Decrypt" button function""" pass_dialog = PasswordDlg(self) infile = self.ui.lineEdit.text() if not os.path.isfile(infile): self.message_box("File not found!") return if pass_dialog.exec_(): password = pass_dialog.password() cipher = MyCipher(password, infile) outfile = cipher.decrypt() if outfile: dir, fname = split(outfile) prefix = fname.rsplit('.tar', 1)[0]+' ' outdir = tempfile.mkdtemp(prefix=prefix, dir=dir) with tarfile.open(outfile, 'r') as tar: tar.extractall(outdir) os.remove(outfile) self.message_box("Successful Decryption!") def message_box(self, text, type=BOXTYPE.SUCCESS): msgBox = QMessageBox() msgBox.setText(text) if type == BOXTYPE.SUCCESS: pixmap = QtGui.QPixmap(":/icon/image/check.png") elif type == BOXTYPE.ERROR: pixmap = QtGui.QPixmap(":/icon/image/delete.png") msgBox.setIconPixmap(pixmap) msgBox.exec_()
class Window(QtGui.QMainWindow): def __init__(self, parent=None): super(Window, self).__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.canvas.paintEvent = self.on_canvas_paint_event self.ui.canvas.mouseReleaseEvent = self.on_canvas_mouse_release_event self.ui.canvas.mouseMoveEvent = self.on_canvas_mouse_move_event self.ui.scrollArea.resizeEvent = self.on_scroll_area_resize_event self.ui.actionZoomIn.triggered.connect(self.on_action_zoom_in) self.ui.actionZoomOut.triggered.connect(self.on_action_zoom_out) self.ui.actionPoints.triggered.connect(self.on_action_points) self.ui.actionPointPoint.triggered.connect(self.on_action_point_point) self.ui.actionLineLine.triggered.connect(self.on_action_line_line) self.ui.actionLinePoint.triggered.connect(self.on_action_line_point) self.ui.actionPointPointLine.triggered.connect( self.on_action_point_point_line) self.ui.actionLinePointLine.triggered.connect( self.on_action_line_point_line) self.ui.actionValleyFold.triggered.connect(self.on_action_valley_fold) self.ui.actionExecuteFold.triggered.connect( self.on_action_execute_fold) self.ui.canvas.setMouseTracking(True) self.zoom = 1 points = [ geo.Point(0, 0), geo.Point(0, 1), geo.Point(1, 1), geo.Point(1, 0) ] polygon = geo.Polygon(points) self.sheet = paper.Sheet(polygon) self.highlight = None self.selected = [] self.lines = [] self.intersections = [] self.fold = None self.update_actions() def canvas_size(self): return min(self.ui.scrollArea.width(), self.ui.scrollArea.height()) * self.zoom def point_to_window(self, point): size = self.canvas_size() return QtCore.QPoint(MARGIN + point.x * (size - 2 * MARGIN), MARGIN + point.y * (size - 2 * MARGIN)) def window_to_point(self, point): size = self.canvas_size() return geo.Point((point.x() - MARGIN) / (size - 2 * MARGIN), (point.y() - MARGIN) / (size - 2 * MARGIN)) def selection_threshold(self): return SELECTION_THRESHOLD / self.canvas_size() def find_point_near(self, mouse_point): threshold = self.selection_threshold() for point in self.sheet.points: distance2 = (mouse_point - point).magnitude2() if distance2 <= threshold * threshold: return point for point in self.intersections: distance2 = (mouse_point - point).magnitude2() if distance2 <= threshold * threshold: return point return None def find_line_near(self, mouse_point): found_line = None threshold = self.selection_threshold() for segment in self.sheet.segments: line = geoutil.line.from_segment(segment) if geoutil.line.distance_to_point( line, mouse_point ) <= threshold and geoutil.segment.is_point_within( segment, mouse_point): found_line = line break if not found_line: for line in self.lines: if geoutil.line.distance_to_point(line, mouse_point) <= threshold: found_line = line break return found_line def on_canvas_paint_event(self, event): painter = QtGui.QPainter(self.ui.canvas) painter.setRenderHint(QtGui.QPainter.Antialiasing) def draw_segment(segment): draw_points = [ self.point_to_window(point) for point in segment.points() ] painter.drawLine(*draw_points) def draw_point(point): painter.drawEllipse(self.point_to_window(point), POINT_SIZE, POINT_SIZE) def draw_line(line): min = self.window_to_point(QtCore.QPoint(0, 0)) max = self.window_to_point( QtCore.QPoint(self.ui.canvas.width(), self.ui.canvas.height())) if abs(line.normal.x) > abs(line.normal.y): minline = geoutil.line.from_point_normal(min, geo.Vector(0, 1)) maxline = geoutil.line.from_point_normal( max, geo.Vector(0, -1)) else: minline = geoutil.line.from_point_normal(min, geo.Vector(1, 0)) maxline = geoutil.line.from_point_normal( max, geo.Vector(-1, 0)) minpoint = geoutil.line.intersect(line, minline) maxpoint = geoutil.line.intersect(line, maxline) points = [minpoint, maxpoint] draw_points = [self.point_to_window(point) for point in points] painter.drawLine(*draw_points) def draw_polygon(polygon): draw_points = [ self.point_to_window(point) for point in polygon.points ] painter.drawPolygon(draw_points) pen = QtGui.QPen(EDGE_COLOR, LINE_WIDTH, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) for layer in self.sheet.layers: for facet in layer.facets: brush = QtGui.QBrush(PAPER_COLORS[facet.parity]) painter.setBrush(brush) draw_polygon(facet.polygon) highlight = self.highlight if highlight: if highlight in self.selected or self.num_selected( type(highlight)) == 2: highlight = None pen = QtGui.QPen(LINE_COLOR, LINE_WIDTH, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) for line in self.lines: draw_line(line) pen = QtGui.QPen(FOLD_COLOR, FOLD_WIDTH, Qt.DashLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) if self.fold: draw_line(self.fold) line = geoutil.line.perpendicular(self.fold, geo.Point(0.5, 0.5)) point = self.point_to_window( geoutil.line.intersect(line, self.fold)) vec = QtCore.QPoint(self.fold.normal.x * 20, self.fold.normal.y * 20) p = geoutil.vector.perpendicular(self.fold.normal) perp_vec = QtCore.QPoint(p.x * 5, p.y * 5) norm_vec = QtCore.QPoint(self.fold.normal.x * 5, self.fold.normal.y * 5) pen = QtGui.QPen(QtGui.QColor(0, 0, 0), 2, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) painter.drawLine(point - vec, point + vec) painter.drawLine(point + vec, point + vec - norm_vec - perp_vec) painter.drawLine(point + vec, point + vec - norm_vec + perp_vec) idx = 0 for selected in self.selected: if not isinstance(selected, geo.Line): continue pen = QtGui.QPen(SELECTED_LINE_COLORS[idx], LINE_WIDTH_SELECTED, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) draw_line(selected) idx += 1 idx = 0 painter.setPen(Qt.NoPen) for selected in self.selected: if not isinstance(selected, geo.Point): continue brush = QtGui.QBrush(SELECTED_POINT_COLORS[idx]) painter.setBrush(brush) draw_point(selected) idx += 1 if highlight: if isinstance(highlight, geo.Line): pen = QtGui.QPen(HIGHLIGHT_COLOR, LINE_WIDTH_SELECTED, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin) painter.setPen(pen) draw_line(highlight) elif isinstance(highlight, geo.Point): brush = QtGui.QBrush(HIGHLIGHT_COLOR) painter.setBrush(brush) painter.setPen(Qt.NoPen) draw_point(highlight) def num_selected(self, type): count = 0 for selected in self.selected: if isinstance(selected, type): count += 1 return count def on_canvas_mouse_release_event(self, event): mouse_point = self.window_to_point(event.pos()) found = False if self.fold: line = geoutil.line.perpendicular(self.fold, geo.Point(0.5, 0.5)) point = geoutil.line.intersect(line, self.fold) threshold = self.selection_threshold() if (mouse_point - point).magnitude2() < threshold * threshold: self.fold = geo.Line(-self.fold.normal, -self.fold.offset) found = True if not found: if self.highlight: if self.highlight in self.selected: self.selected.remove(self.highlight) else: if self.num_selected(type(self.highlight)) < 2: self.selected.append(self.highlight) self.highlight = None else: self.selected.clear() self.ui.canvas.update() self.update_actions() def on_canvas_mouse_move_event(self, event): mouse_point = self.window_to_point(event.pos()) highlight = self.find_point_near(mouse_point) if not highlight: highlight = self.find_line_near(mouse_point) if highlight != self.highlight: self.highlight = highlight self.ui.canvas.update() def on_scroll_area_resize_event(self, event): self.resize_canvas() def resize_canvas(self): size = self.canvas_size() hmax = self.ui.scrollArea.horizontalScrollBar().maximum() hvalue = self.ui.scrollArea.horizontalScrollBar().value() vmax = self.ui.scrollArea.verticalScrollBar().maximum() vvalue = self.ui.scrollArea.verticalScrollBar().value() x = hvalue / hmax if hmax else 0.5 y = vvalue / vmax if vmax else 0.5 self.ui.canvas.setMinimumSize(QtCore.QSize(size, size)) self.ui.canvas.setMaximumSize(QtCore.QSize(size, size)) hmax = self.ui.scrollArea.horizontalScrollBar().maximum() vmax = self.ui.scrollArea.verticalScrollBar().maximum() self.ui.scrollArea.horizontalScrollBar().setValue(x * hmax) self.ui.scrollArea.verticalScrollBar().setValue(y * vmax) def update_actions(self): self.ui.actionPoints.setEnabled( self.num_selected(geo.Point) == 2 and self.num_selected(geo.Line) == 0) self.ui.actionPointPoint.setEnabled( self.num_selected(geo.Point) == 2 and self.num_selected(geo.Line) == 0) self.ui.actionLineLine.setEnabled( self.num_selected(geo.Point) == 0 and self.num_selected(geo.Line) == 2) self.ui.actionLinePoint.setEnabled( self.num_selected(geo.Point) == 1 and self.num_selected(geo.Line) == 1) self.ui.actionPointPointLine.setEnabled( self.num_selected(geo.Point) == 2 and self.num_selected(geo.Line) == 1) self.ui.actionLinePointLine.setEnabled( self.num_selected(geo.Point) == 1 and self.num_selected(geo.Line) == 2) self.ui.actionValleyFold.setEnabled( self.num_selected(geo.Point) == 0 and self.num_selected(geo.Line) == 1 and not self.fold) self.ui.actionExecuteFold.setEnabled(self.fold is not None) def add_lines(self, lines): for line in lines: for segment in self.sheet.segments: point = geoutil.segment.intersect_line(segment, line) if point: self.intersections.append(point) for other_line in self.lines: point = geoutil.line.intersect(line, other_line) if point: self.intersections.append(point) self.lines.extend(lines) self.update_actions() self.ui.canvas.update() def add_line(self, line): self.add_lines([line]) def on_action_zoom_in(self): self.zoom *= ZOOM_INCREMENT self.resize_canvas() def on_action_zoom_out(self): self.zoom /= ZOOM_INCREMENT self.resize_canvas() def on_action_points(self): line = geoutil.huzita_justin.O1(self.selected[0], self.selected[1]) self.selected.clear() self.add_line(line) def on_action_point_point(self): line = geoutil.huzita_justin.O2(self.selected[0], self.selected[1]) self.selected.clear() self.add_line(line) def on_action_line_line(self): lines = geoutil.huzita_justin.O3(self.selected[0], self.selected[1]) if lines: self.selected.clear() self.add_lines(lines) def on_action_line_point(self): for selected in self.selected: if isinstance(selected, geo.Point): point = selected elif isinstance(selected, geo.Line): line = selected line = geoutil.huzita_justin.O4(point, line) self.selected.clear() self.add_line(line) def on_action_point_point_line(self): points = [] for selected in self.selected: if isinstance(selected, geo.Point): points.append(selected) elif isinstance(selected, geo.Line): line = selected lines = geoutil.huzita_justin.O5(points[0], points[1], line) if lines: self.selected.clear() self.add_lines(lines) def on_action_line_point_line(self): lines = [] for selected in self.selected: if isinstance(selected, geo.Point): point = selected elif isinstance(selected, geo.Line): lines.append(selected) line = geoutil.huzita_justin.O7(point, lines[0], lines[1]) if line: self.selected.clear() self.add_line(line) def on_action_valley_fold(self): self.fold = self.selected[0] self.lines = [] self.intersections = [] self.selected.clear() self.highlighted = None self.update_actions() self.ui.canvas.update() def on_action_execute_fold(self): self.sheet.fold(self.fold) self.fold = None self.update_actions() self.ui.canvas.update()
class Main(QMainWindow): def __init__(self): QMainWindow.__init__(self) # This is always the same self.ui = Ui_MainWindow() self.ui.setupUi(self) def add_file(self): """Add files or directories to the list of files/directories""" file_dialog = QFileDialog(self) if file_dialog.exec_(): filenames = file_dialog.selectedFiles() self.ui.listWidget.addItems(filenames) self.ui.encryptButton.setEnabled(True) def remove_file(self): """Removes selected files (addresses) from the list""" listWidget = self.ui.listWidget selected = listWidget.selectedItems() for item in selected: row = listWidget.row(item) listWidget.takeItem(row) del item if listWidget.count() == 0: # if list is empty, remove and encrypt buttons disabled self.ui.removeButton.setEnabled(False) self.ui.encryptButton.setEnabled(False) def selection_changed(self): """ Triggered when there is a change in selection in the list Item selected/deselected in the list. """ listWidget = self.ui.listWidget if listWidget.count() > 0: self.ui.removeButton.setEnabled(True) else: self.ui.removeButton.setEnabled(False) def encrypt(self): """Implementation of UI's "Encrypt" button function""" listWidget = self.ui.listWidget # open a dialog to choose/create file that will be our encrypted file filter = 'Encrypted (*.encrypted)' save_file = QFileDialog.getSaveFileName(self, 'Save encrypted file', filter=filter)[0] tempfile = save_file + ".tmp" if save_file: # Making a tar archive from all files in the list and save tar as # chosen by user in file dialog with tarfile.open(tempfile, "w") as tar: for i in range(listWidget.count()): item = listWidget.item(i).text() tar.add(item, split(item)[1]) # Getting password(key) for encryption pass_dialog = PasswordDlg(self) if pass_dialog.exec_(): password = pass_dialog.password() cipher = MyCipher(str(password), save_file) if cipher.encrypt(): self.message_box("Successful Encryption!") os.remove(tempfile) def browse(self): self.encrypted_file = QFileDialog.getOpenFileName()[0] self.ui.lineEdit.setText(self.encrypted_file) def text_changed(self): if self.ui.lineEdit.text(): self.ui.decryptButton.setEnabled(True) else: self.ui.decryptButton.setEnabled(False) def decrypt(self): """Implementation of UI's "Decrypt" button function""" pass_dialog = PasswordDlg(self) infile = self.ui.lineEdit.text() if not os.path.isfile(infile): self.message_box("File not found!") return if pass_dialog.exec_(): password = pass_dialog.password() cipher = MyCipher(password, infile) outfile = cipher.decrypt() if outfile: dir, fname = split(outfile) prefix = fname.rsplit('.tar', 1)[0] + ' ' outdir = tempfile.mkdtemp(prefix=prefix, dir=dir) with tarfile.open(outfile, 'r') as tar: tar.extractall(outdir) os.remove(outfile) self.message_box("Successful Decryption!") def message_box(self, text, type=BOXTYPE.SUCCESS): msgBox = QMessageBox() msgBox.setText(text) if type == BOXTYPE.SUCCESS: pixmap = QtGui.QPixmap(":/icon/image/check.png") elif type == BOXTYPE.ERROR: pixmap = QtGui.QPixmap(":/icon/image/delete.png") msgBox.setIconPixmap(pixmap) msgBox.exec_()
class MainWindow(QtGui.QMainWindow): """ Main Window Class """ add_windows_trigger = QtCore.pyqtSignal(list) def __init__(self, parent=None, document = None): """ Initialize MainWindow """ QtGui.QMainWindow.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowIcon(QtGui.QIcon(':img/note64.png')) self._preamble = PREAMBLE self.offset = 0 self.docpath = '' self.lastpath = HOME self.rmdoc = False self.displayed_uid = -1 self.okular_notes = [] # Toolbar icons self.ui.actionOpen.setIcon(QtGui.QIcon.fromTheme("document-open")) self.ui.actionExport.setIcon(QtGui.QIcon.fromTheme("document-save-as")) self.ui.actionQuit.setIcon(QtGui.QIcon.fromTheme("application-exit")) self.ui.actionPreambleEditor.setIcon(QtGui.QIcon.fromTheme( "preferences-other")) self.ui.actionAbout.setIcon(QtGui.QIcon.fromTheme("help-about")) # Toolbar connections self.connect(self.ui.actionOpen, QtCore.SIGNAL("triggered()"), self.slot_gui_open) self.connect(self.ui.actionExport, QtCore.SIGNAL("triggered()"), self.slot_export) self.connect(self.ui.actionQuit, QtCore.SIGNAL("triggered()"), self.close) self.connect(self.ui.actionControls, QtCore.SIGNAL("toggled(bool)"), self.ui.controlsWidget.setVisible) self.connect(self.ui.actionAnnotationSource, QtCore.SIGNAL("toggled(bool)"), self.ui.annotationSourceDockWidget.setVisible) self.connect(self.ui.actionAnnotation, QtCore.SIGNAL("toggled(bool)"), self.ui.annotationDockWidget.setVisible) self.connect(self.ui.controlsWidget, QtCore.SIGNAL("visibilityChanged(bool)"), self.slot_hide_controls) self.connect(self.ui.annotationDockWidget, QtCore.SIGNAL("visibilityChanged(bool)"), self.slot_hide_annotation) self.connect(self.ui.annotationSourceDockWidget, QtCore.SIGNAL("visibilityChanged(bool)"), self.slot_hide_annotation_source) self.connect(self.ui.actionAbout, QtCore.SIGNAL("triggered()"), self.slot_about) # Document controls if PLATFORM == 'Windows': self.ui.previousPageButton.setText('Previous') self.ui.nextPageButton.setText('Next') font_metrics = QtGui.QFontMetrics(QtGui.QFont()) size_p = font_metrics.size(QtCore.Qt.TextSingleLine, 'Previous') size_n = font_metrics.size(QtCore.Qt.TextSingleLine, 'Next') self.ui.previousPageButton.setMinimumWidth(size_p.width() + 10) self.ui.nextPageButton.setMinimumWidth(size_n.width() + 10) else: self.ui.previousPageButton.setIcon(QtGui.QIcon.fromTheme("go-previous")) self.ui.nextPageButton.setIcon(QtGui.QIcon.fromTheme("go-next")) self.ui.controlsWidget.mouseMoveEvent = self.highlight_buttons self.offsetWindow = OffsetWindow(self) self.connect(self.ui.offsetCheckBox, QtCore.SIGNAL("stateChanged(int)"), self.offsetWindow.slot_open) # Search widget self.ui.searchWidget = SearchWidget(self.ui.searchDockWidgetContents) self.ui.gridLayout_4.addWidget(self.ui.searchWidget, 0, 0, 1, 1) self.ui.searchDockWidget.hide() self.ui.searchWidget.hide_trigger.connect(self.ui.searchDockWidget.hide) self.ui.searchWidget.change_page_trigger.connect(self.ui.pageSpinBox.setValue) #self.ui.searchWidget.show_trigger.connect(self.ui.searchDockWidget.show) # PDF viewer widget self.ui.scrollArea.setMinimumWidth(0) self.ui.documentWidget = DocumentWidget(self.ui.scrollArea) self.ui.documentWidget.setObjectName("documentWidget") self.ui.scrollArea.setBackgroundRole(QtGui.QPalette.Dark) self.ui.scrollArea.setWidget(self.ui.documentWidget.ImgLabel) self.connect(self.ui.documentWidget.ImgLabel, QtCore.SIGNAL("dropped"), self.slot_load_dropped) self.ui.documentWidget.ImgLabel.change_page_trigger.connect( self.ui.pageSpinBox.setValue) self.ui.documentWidget.ImgLabel.change_scale_trigger.connect( self.ui.scaleSpinBox.setValue) self.ui.documentWidget.ImgLabel.show_search_trigger.connect( self.slot_show_search_widget) self.ui.documentWidget.ImgLabel.hide_search_trigger.connect( self.ui.searchWidget.hide) # Connections for PDF viewer self.connect(self.ui.previousPageButton, QtCore.SIGNAL("clicked()"), self.slot_prev_page) self.connect(self.ui.nextPageButton, QtCore.SIGNAL("clicked()"), self.slot_next_page) self.connect(self.ui.pageSpinBox, QtCore.SIGNAL("valueChanged(int)"), self.ui.documentWidget.change_page) self.connect(self.ui.scaleSpinBox, QtCore.SIGNAL("valueChanged(double)"), self.ui.documentWidget.set_scale) self.connect(self.ui.scaleComboBox, QtCore.SIGNAL("currentIndexChanged(int)"), self.slot_scale) # Scroll Widget for annotation self.ui.scrollAreaAnnotation = QtGui.QScrollArea(self.ui.annotationDockWidget) self.ui.scrollAreaAnnotation.setWidgetResizable(True) self.ui.scrollAreaAnnotation.setObjectName("scrollAreaAnnotation") self.ui.gridLayoutAnnotationDock.addWidget(self.ui.scrollAreaAnnotation, 0, 0, 1, 1) # Beginning note self.current_note = Note(WELCOME, self.preamble) # Annotation PNG widget self.ui.annotationWidget = AnnotationWidget(self.ui.scrollAreaAnnotation, self.current_note.icon) self.ui.annotationWidget.setObjectName("annotationWidget") self.ui.scrollAreaAnnotation.setBackgroundRole(QtGui.QPalette.Light) self.ui.scrollAreaAnnotation.setWidget(self.ui.annotationWidget.ImgLabel) self.ui.actionAnnotation.toggle() # Connections for Annotation widget self.connect(self.ui.compileButton, QtCore.SIGNAL("clicked()"), self.slot_force_compile) # Annotation Source Widget self.ui.annotationSourceTextEdit.setText(WELCOME) self.connect(self.ui.documentWidget.ImgLabel.addNoteAction, QtCore.SIGNAL("triggered()"), self.slot_change_note) self.connect(self.ui.documentWidget.ImgLabel.editNoteAction, QtCore.SIGNAL("triggered()"), self.slot_change_note) #self.connect(self.ui.documentWidget.ImgLabel.removeNoteAction, #QtCore.SIGNAL("triggered()"), self.slot_remove_note) self.ui.documentWidget.ImgLabel.remove_trigger.connect( self.slot_remove_note) self.ui.documentWidget.ImgLabel.toggle_source_trigger.connect( self.ui.actionAnnotationSource.toggle) self.ui.actionAnnotationSource.toggle() # Connections for Annotation Source Widget self.timer = QtCore.QTimer() self.timer.start(3500) self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.slot_compile_annotation) self.old_text = '' # Preamble editor self.preambleEditorWindow = PreambleWindow(self) self.connect(self.ui.actionPreambleEditor, QtCore.SIGNAL("triggered()"), self.preambleEditorWindow.slot_open) # Status bar self.ui.documentWidget.ImgLabel.set_clipboard_trigger.connect( self.slot_set_status) if document is not None: self.load_file(document) @property def preamble(self): return self._preamble @preamble.setter def preamble(self, preamble): self._preamble = preamble self.current_note.preamble = preamble self.slot_compile_annotation() def highlight_buttons(self, event): if self.ui.previousPageButton.underMouse(): self.ui.previousPageButton.setFlat(False) else: self.ui.previousPageButton.setFlat(True) if self.ui.nextPageButton.underMouse(): self.ui.nextPageButton.setFlat(False) else: self.ui.nextPageButton.setFlat(True) def slot_load_dropped(self, files): if self.docpath == '' or files[0].endswith('.xml'): self.load_file(files.pop(0)) windows = [] for doc in files: win = MainWindow(document=doc) windows.append(win) win.show() self.add_windows_trigger.emit(windows) #print files def slot_set_status(self, text): """ Slot to set statusBar with message. """ self.statusBar().showMessage('Copied "%s" to clipboard.' % unicode(text).strip()) def slot_about(self): about_msg = ''' <p><center><font size="4"><b>Notorius %s</b></font></center></p> <p><b>Author</b>: Carlos da Costa</p> <p><b>Code at</b>: <a href="https://github.com/cako/notorius"> https://github.com/cako/notorius<a/></p> <p><b>License</b>: <a href="http://www.gnu.org/licenses/gpl-3.0.txt"> GNU General Public License version 3</a></p> ''' % VERSION QtGui.QMessageBox.about(self, "About me", about_msg) def slot_gui_open(self): """ Slot for actionOpen. """ file_filter = "All supported filetypes (*.pdf *.okular *.zip *.xml);;" file_filter += "PDF files (*.pdf);;" file_filter += "Okular (*.okular);;" file_filter += "ZIP archive (*.zip);;" file_filter += "XML file (*.xml)" filename = unicode( QtGui.QFileDialog.getOpenFileName(self, 'Open file', self.lastpath, file_filter)) self.lastpath = os.path.dirname(filename) self.load_file(filename) def load_file(self, filename = None): def parse_metadata(root): notes = {} for page in root.find('pageList').findall('page'): pg = int(page.attrib['number']) annotlist = page.find('annotationList') for annot in annotlist.findall('annotation'): if ( annot.attrib['type'] == "1" and pg <= self.ui.documentWidget.num_pages ): base = annot.find('base') try: author = base.attrib['author'] except KeyError: author = '' try: text = base.attrib['contents'] except KeyError: text = '' try: cdate = base.attrib['creationDate'] except KeyError: cdate = '' try: mdate = base.attrib['modifyDate'] except KeyError: mdate = '' try: preamble = base.attrib['preamble'] except KeyError: preamble = PREAMBLE try: uname = base.attrib['uniqueName'] # notorius-1-0 becomes 0 uid = int(uname.rsplit('-')[-1]) except KeyError: try: uid = max(notes.keys()) except ValueError: uid = 0 boundary = base.find('boundary') x = float(boundary.attrib['l']) y = float(boundary.attrib['t']) size = self.ui.documentWidget.Document.page( pg).pageSizeF() pos = QtCore.QPointF(x*size.width(), y*size.height()) note = Note(text, preamble, page = pg, pos = pos, uid = uid) notes[uid] = note note.cdate = datetime.datetime.strptime(cdate, "%Y-%m-%dT%H:%M:%S") note.mdate = datetime.datetime.strptime(mdate, "%Y-%m-%dT%H:%M:%S") note.update() else: self.okular_notes.append(annot) return notes loaded = False if filename: self.ui.nextPageButton.setEnabled(True) self.ui.previousPageButton.setEnabled(True) self.ui.pageSpinBox.setEnabled(True) self.ui.offsetCheckBox.setEnabled(True) self.ui.offsetCheckBox.setChecked(False) self.ui.scaleSpinBox.setEnabled(True) self.ui.scaleComboBox.setEnabled(True) #file_dir = os.path.dirname(filename) self.okular_notes = [] if filename.endswith(('.zip', '.okular')): self.rmdoc = True zipf = zipfile.ZipFile(filename, 'r') zipf.extractall(TMPDIR) # [ 'filename.pdf', 'content.xml', 'metadata.xml' ] # becomes [ 'filename.pdf' ] which then becomes 'filename.pdf' # then TMPDIR is added. # Important! filename can have .okular extension! self.docpath = os.path.join(TMPDIR, [ fl for fl in zipf.namelist() if ( fl.rsplit('.')[1] != 'xml') ][0]) # Must insert try statement! self.ui.documentWidget.load_document(self.docpath) loaded = True root = xml.parse(os.path.join(TMPDIR, 'metadata.xml')).getroot() notes = parse_metadata(root) for aux in ['content.xml', 'metadata.xml']: os.remove(os.path.join(TMPDIR, aux)) self.ui.documentWidget.ImgLabel.notes = notes self.ui.documentWidget.update_image() self.setWindowTitle('Notorius - %s' %os.path.basename(filename)) if self.okular_notes: warning = 'Not loading annotations that are ' warning += 'not text notes or are out of range.' QtGui.QMessageBox.warning(self, "Warning", warning) elif filename.endswith('.xml'): if self.docpath == '': QtGui.QMessageBox.warning(self, "Warning", 'You need to load a PDF first!.') loaded = False else: self.rmdoc = False root = xml.parse(filename).getroot() self.ui.documentWidget.ImgLabel.notes = parse_metadata(root) self.ui.documentWidget.update_image() loaded = True self.setWindowTitle( 'Notorius - %s + %s' % (os.path.basename(self.docpath), os.path.basename(filename))) if self.okular_notes: warning = 'Not loading annotations that are ' warning += 'not text notes or are out of range.' QtGui.QMessageBox.warning(self, "Warning", warning) else: if not filename.endswith('.pdf'): print "Treating file as pdf!" self.rmdoc = False self.docpath = filename self.ui.documentWidget.load_document(self.docpath) self.setWindowTitle('Notorius - %s' %os.path.basename(filename)) loaded = True if loaded: self.ui.pageSpinBox.setValue(1) self.ui.pageSpinBox.setMinimum(-self.ui.documentWidget.num_pages + 1) self.ui.pageSpinBox.setMaximum(self.ui.documentWidget.num_pages) self.ui.scaleComboBox.setCurrentIndex(0) self.ui.maxPageLabel.setText("of %d" % self.ui.documentWidget.num_pages) self.ui.actionExport.setEnabled(True) self.ui.searchWidget.documentWidget = self.ui.documentWidget self.statusBar().showMessage('Opened file %s.' % filename) else: print 'No file to load!' def slot_export(self): file_dir = os.path.dirname(self.docpath) file_base = os.path.basename(self.docpath) filt = QtCore.QString() filename = unicode(QtGui.QFileDialog.getSaveFileName(self, 'Save archive as', file_dir, "Okular archive (*.okular);;ZIP archive (*.zip);;XML file (*.xml)", filt)) if filename: # Create the content.xml file if filt != 'XML file (*.xml)': content_path = os.path.join(TMPDIR, 'content.xml') root = xml.Element('OkularArchive') child_files = xml.SubElement(root, 'Files') child_doc = xml.SubElement(child_files, 'DocumentFileName') child_doc.text = file_base child_meta = xml.SubElement(child_files, 'MetadataFileName') child_meta.text = 'metadata.xml' xml.ElementTree(root).write(content_path) # Create the metadata.xml file if filt != 'XML file (*.xml)': metadata_path = os.path.join(TMPDIR, 'metadata.xml') else: metadata_path = filename root = xml.Element('documentInfo') pagelist = xml.SubElement(root, 'pageList') notes = self.ui.documentWidget.ImgLabel.notes for note in notes.values(): try: page = [ pg for pg in pagelist if ( int(pg.attrib['number']) == note.page) ][0] annotlist = page.find('annotationList') except IndexError: page = xml.SubElement(pagelist, 'page') page.set('number', str(note.page)) annotlist = xml.SubElement(page, 'annotationList') annot = xml.SubElement(annotlist, 'annotation') annot.set('type', '1') base = xml.SubElement(annot, 'base') base.set('creationDate', note.cdate.isoformat()) #BOGUS DATE base.set('uniqueName', 'notorius-%d-%d' % (note.page, note.uid)) base.set('author', USERNAME) base.set('contents', note.text) base.set('preamble', note.preamble) base.set('modifyDate', note.mdate.isoformat()) #BOGUS DATE base.set('color', '#ffff00') boundary = xml.SubElement(base, 'boundary') size = self.ui.documentWidget.Document.page(note.page).pageSizeF() posx = note.pos.x()/size.width() posy = note.pos.y()/size.height() boundary.set('l', str(posx)) boundary.set('r', str(posx + 0.03)) # "Empirical values" boundary.set('b', str(posy + 0.022)) boundary.set('t', str(posy)) window = xml.SubElement(base, 'window') window.set('width', '0') window.set('flags', '-1') window.set('title', '') window.set('left', '0') window.set('height', '0') window.set('summary', 'LaTeXNote') window.set('top', '0') text = xml.SubElement(annot, 'text') text.set('icon', 'None') # Write okular notes that are not displayed for annot in self.okular_notes: pg_n = False try: pg_n = annot.find('base').attrib['uniqueName'].split('-')[1] except IndexError: # Did not find page, ignore pass if pg_n: try: page = [ pg for pg in pagelist if ( pg.attrib['number'] == pg_n) ][0] annotlist = page.find('annotationList') except IndexError: page = xml.SubElement(pagelist, 'page') page.set('number', str(note.page)) annotlist = xml.SubElement(page, 'annotationList') annotlist.append(annot) xml.ElementTree(root).write(metadata_path) # Create the archive if ( filt == "ZIP archive (*.zip)" and not filename.endswith('.zip') ): filename += '.zip' elif ( filt == "Okular archive (*.okular)" and not filename.endswith('.okular') ): filename += '.okular' elif ( filt == 'XML file (*.xml)' and not filename.endswith('.xml') ): filename += '.xml' if filt != 'XML file (*.xml)': zipf = zipfile.ZipFile(filename, 'w') zipf.write(self.docpath, file_base) for (path, name) in [(content_path, 'content.xml'), (metadata_path, 'metadata.xml')]: zipf.write(path, name) os.remove(path) zipf.close() self.statusBar().showMessage('Exported annotations to file %s.' % filename) def slot_change_note(self): """ Slot to add or edit note. Replaces current note display in annotationSourceTextEdit and annotationWidget with the new note. """ self.ui.annotationSourceDockWidget.show() self.ui.actionAnnotationSource.setChecked(True) uid = self.ui.documentWidget.ImgLabel.current_uid if (self.displayed_uid != -1 and self.displayed_uid != -2): text = unicode(self.ui.annotationSourceTextEdit.toPlainText()) self.current_note.text = text self.current_note = self.ui.documentWidget.ImgLabel.notes[uid] self.ui.annotationSourceTextEdit.setText(self.current_note.text) self.ui.annotationSourceDockWidget.setWindowTitle('Note %d - Source' % self.current_note.uid) self.ui.annotationDockWidget.setWindowTitle('Note %d - LaTeX' % self.current_note.uid) self.slot_force_compile() def slot_remove_note(self): """ Removes note along with all its files. If the current note is being replaced, blank annotationSourceTextEdit and annotationWidget. """ uid = self.ui.documentWidget.ImgLabel.closest_id #print 'Current note: %d' % self.ui.documentWidget.ImgLabel.current_uid self.ui.documentWidget.ImgLabel.notes[uid].remove_files() self.ui.documentWidget.ImgLabel.notes[uid].remove_png() #print 'Main remove note %d' % uid if self.ui.documentWidget.ImgLabel.current_uid == uid: self.ui.annotationSourceTextEdit.setText('') white_pix = QtGui.QPixmap() white_pix.fill() self.ui.annotationWidget.ImgLabel.setPixmap(white_pix) self.ui.documentWidget.ImgLabel.displayed_uid = -2 self.ui.documentWidget.ImgLabel.current_uid = -2 self.ui.annotationSourceDockWidget.setWindowTitle('') self.ui.annotationDockWidget.setWindowTitle('') del self.ui.documentWidget.ImgLabel.notes[uid] self.ui.documentWidget.update_image() def slot_hide_controls(self): """ Slot to hide controls properly and avoid recursion. """ if self.ui.controlsWidget.isVisible(): self.ui.actionControls.setChecked(True) if self.ui.annotationDockWidget.isHidden(): self.ui.actionControls.setChecked(False) def slot_hide_annotation(self): """ Slot to hide annotation properly and avoid recursion. """ if self.ui.annotationDockWidget.isVisible(): self.ui.actionAnnotation.setChecked(True) if self.ui.annotationDockWidget.isHidden(): self.ui.actionAnnotation.setChecked(False) def slot_hide_annotation_source(self): """ Slot to hide annotation source properly and avoid recursion. """ if self.ui.annotationSourceDockWidget.isVisible(): self.ui.actionAnnotationSource.setChecked(True) if self.ui.annotationSourceDockWidget.isHidden(): self.ui.actionAnnotationSource.setChecked(False) def slot_prev_page(self): """ Slot to go to the previous page. """ self.ui.pageSpinBox.setValue(self.ui.pageSpinBox.value() - 1) def slot_next_page(self): """ Slot to go to the next page. """ self.ui.pageSpinBox.setValue(self.ui.pageSpinBox.value() + 1) def slot_scale(self, event): """ Slot to change the scale. """ if event == 0: self.ui.scaleSpinBox.setEnabled(True) self.ui.documentWidget.set_scale(self.ui.scaleSpinBox.value()) else: self.ui.scaleSpinBox.setEnabled(False) self.ui.documentWidget.fit_to_width_or_height(event) def slot_force_compile(self): """ Slot to force compilation through the compileButton. """ self.old_text = '' self.slot_compile_annotation() def slot_compile_annotation(self): """ Slot to compile the current annotation by changing annotationWidget's ImgLabel's Pixmap to the updated one. """ text = unicode(self.ui.annotationSourceTextEdit.toPlainText()) if (self.old_text != text and self.ui.documentWidget.ImgLabel.current_uid != -2): self.old_text = text self.current_note.remove_png() self.current_note.text = text self.current_note.update() self.displayed_uid = self.current_note.uid self.ui.annotationWidget.ImgLabel.setPixmap( self.current_note.icon) def slot_show_search_widget(self): self.ui.searchDockWidget.show() self.ui.searchWidget.searchLineEdit.selectAll() self.ui.searchWidget.searchLineEdit.setFocus() def keyPressEvent(self, event): if self.docpath != '': if (event.matches(QtGui.QKeySequence.Find) or event.key() == QtCore.Qt.Key_Slash): self.slot_show_search_widget() elif event.key() == QtCore.Qt.Key_Escape: self.ui.searchDockWidget.hide() def resizeEvent(self, event): """ Slot to adjust widgets when MainWindow is resized. """ if self.ui.scaleComboBox.currentIndex() == 1: self.ui.documentWidget.fit_to_width_or_height(1) elif self.ui.scaleComboBox.currentIndex() == 2: self.ui.documentWidget.fit_to_width_or_height(2) def closeEvent(self, event): """ On close, cleanup files. """ for note in self.ui.documentWidget.ImgLabel.notes.values(): note.remove_files() note.remove_png() self.current_note.remove_files() self.current_note.remove_png() if self.rmdoc: os.remove(self.docpath) try: os.rmdir(TMPDIR) except OSError: #print 'Directory %s could not be removed. It could be non-empty.' % TMPDIR pass