Esempio n. 1
0
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        uic.loadUi("mainwindow.ui", self)

        model = QStandardItemModel(3, 2, self)
        model.setItem(0, 0, QStandardItem(_fromUtf8("xiaoming")))
        model.setItem(0, 1, QStandardItem(_fromUtf8("0")))
        model.setItem(1, 0, QStandardItem(_fromUtf8("xiaogang")))
        model.setItem(1, 1, QStandardItem(_fromUtf8("5")))
        model.setItem(2, 0, QStandardItem(_fromUtf8("xiaohong")))
        model.setItem(2, 1, QStandardItem(_fromUtf8("0")))
        model.setItem(3, 0, QStandardItem(_fromUtf8("赵六")))
        model.setItem(3, 1, QStandardItem(_fromUtf8("8")))

        self.mapper = QDataWidgetMapper(self)
        # 设置模型
        self.mapper.setModel(model)
        # 设置窗口部件和模型中的列的映射
        self.mapper.addMapping(self.lineEdit, 0)
        self.mapper.addMapping(self.lineEdit_2, 1)
        # 显示模型中的第一行
        self.mapper.toFirst()

        #----------------------------------------------------------
        tableview = QTableView()
        tableview.setModel(model)
        tableview.show()
Esempio n. 2
0
    def setup_rdpoly_model_and_mapper(self, rd_pol_id):
        """
        Load the data for the Polygon portion of the form
        :param rd_pol_id: str rd_pol_id
        :return:
        """
        # Set up model
        self.rdpoly_model = QSqlTableModel(db=self.db)
        self.rdpoly_model.setTable('rdpoly')
        self.rdpoly_model.setFilter("rd_pol_id = {}".format(int(rd_pol_id)))
        self.rdpoly_model.select()
        if self.rdpoly_model.rowCount() != 1:
            msg = "Table rdpoly query for rd_pol_id = {} returned {} rows".format(
                rd_pol_id, self.rdpoly_model.rowCount())
            raise rn_except.RdpolyFormBadRdpolyRefError(msg)

        # Set up rdpoly_mapper
        self.rdpoly_mapper = QDataWidgetMapper()
        self.rdpoly_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.rdpoly_mapper.setModel(self.rdpoly_model)
        self.rdpoly_mapper.addMapping(self.dlg.ui.rdpolyLineEdit, RD_POL_ID)
        self.rdpoly_mapper.addMapping(self.dlg.ui.numberLineEdit, DESC_3)
        self.rdpoly_mapper.addMapping(self.dlg.ui.elementComboBox, ELEMENT)
        self.rdpoly_mapper.addMapping(self.dlg.ui.hierarchyComboBox, HIERARCHY)
        self.rdpoly_mapper.addMapping(self.dlg.ui.offsetComboBox, OFFSET)
        self.rdpoly_mapper.setItemDelegate(RdpolyEditorDelegate(self.dlg))
        self.rdpoly_mapper.toFirst()
Esempio n. 3
0
    def setup_mcl_model_and_mapper(self, mcl_ref):
        """
        Load the data for the MCL portion of the form
        :param mcl_ref: str mcl_ref
        :return:
        """
        # Set up model
        self.mcl_model = QSqlTableModel(db=self.db)
        self.mcl_model.setTable('mcl')
        self.mcl_model.setFilter("mcl_ref = {}".format(int(mcl_ref)))
        self.mcl_model.select()
        if self.mcl_model.rowCount() != 1:
            msg = "MCL query for mcl_ref = {} returned {} rows".format(
                mcl_ref, self.mcl_model.rowCount())
            raise rn_except.RdpolyFormBadMclRefError(msg)

        # Set up mcl_mapper
        self.mcl_mapper = QDataWidgetMapper()
        self.mcl_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mcl_mapper.setModel(self.mcl_model)
        self.mcl_mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF)
        self.mcl_mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN)
        self.mcl_mapper.addMapping(self.dlg.ui.lorDescPlainTextEdit, LOR_DESC)
        self.mcl_mapper.addMapping(self.dlg.ui.laneNumberLineEdit, LANE_NUMBER)
        self.mcl_mapper.addMapping(self.dlg.ui.speedLineEdit, SPEED_LIMIT)
        self.mcl_mapper.toFirst()
Esempio n. 4
0
    def setup_model_and_mapper(self, mcl_ref):
        """
        Load the table data for selected record into a model and map to widgets.
        """
        # Set up model
        self.model = QSqlTableModel(db=self.db)
        self.model.setTable('mcl')
        self.model.setFilter("mcl_ref = {}".format(int(mcl_ref)))
        self.model.select()
        if self.model.rowCount() != 1:
            msg = "MCL query for mcl_ref = {} returned {} rows".format(
                mcl_ref, self.model.rowCount())
            raise rn_except.MclFormBadMclRefError(msg)

        # Set up mapper
        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF)
        self.mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN)
        self.mapper.addMapping(self.dlg.ui.streetClassComboBox, STREET_CLASS)
        self.mapper.addMapping(self.dlg.ui.ref1LineEdit, LOR_REF_1)
        self.mapper.addMapping(self.dlg.ui.ref2LineEdit, LOR_REF_2)
        self.mapper.addMapping(self.dlg.ui.laneNumberComboBox, LANE_NUMBER)
        self.mapper.addMapping(self.dlg.ui.carriagewayComboBox, CARRIAGEWAY)
        self.mapper.addMapping(self.dlg.ui.ruralUrbanComboBox, RURAL_URBAN_ID)
        self.mapper.addMapping(self.dlg.ui.speedLimitComboBox, SPEED_LIMIT)
        self.mapper.addMapping(self.dlg.ui.sectionTypeComboBox, SECTION_TYPE)
        self.mapper.addMapping(self.dlg.ui.sectionDescriptionPlainTextEdit,
                               LOR_DESC)
        self.mapper.setItemDelegate(MclEditorDelegate(self.dlg))
        self.mapper.toFirst()
Esempio n. 5
0
 def setup_mapper(self):
     """
     Create the data widget mapper and set a proxy on the model
     """
     self.mapper = QDataWidgetMapper()
     self.proxy = QSortFilterProxyModel()
     self.proxy.setSourceModel(self.model)
     self.proxy.setDynamicSortFilter(True)
     self.mapper.setModel(self.proxy)
     self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
     # Set custom delegate for mapping to date widgets
     self.mapper.setItemDelegate(DateMapperCustomDelegate(self.date_cols))
     self.map_widgets(self.mapper)
Esempio n. 6
0
 def setup_proxy_and_mapper(self):
     """
     Map data fields to widgets in street browser and create proxy for filtering
     """
     self.mapper = QDataWidgetMapper()
     self.proxy = QSortFilterProxyModel()
     self.proxy.setSourceModel(self.model)
     self.proxy.setDynamicSortFilter(True)
     self.mapper.setModel(self.proxy)
     self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
     # Set custom delegate for mapping to date widgets
     self.mapper.setItemDelegate(DateMapperCustomDelegate([6, 7, 8, 18]))
     self.mapper.currentIndexChanged.connect(self.mapper_idx_changed)
     self.map_widgets(self.mapper)
Esempio n. 7
0
    def setupMappers(self):
        '''
            Initialize all the application mappers
        '''
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.mModel)
        self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
        self.mapper.addMapping(self.dateEdit, MDATA)
        self.mapper.addMapping(self.fattLineEdit, MDOC)

        relationModel = self.mModel.relationModel(MIDTDOC)
        relationModel.setSort(1, Qt.AscendingOrder)
        relationModel.select()
        self.tipoFattComboBox.setModel(relationModel)
        self.tipoFattComboBox.setModelColumn(relationModel.fieldIndex("tfatt"))
        self.mapper.addMapping(self.tipoFattComboBox, MIDTDOC)

        relationModel = self.mModel.relationModel(MIDCLI)
        relationModel.setSort(CRAGSOC, Qt.AscendingOrder)
        relationModel.select()
        self.cliComboBox.setModel(relationModel)
        self.cliComboBox.setModelColumn(relationModel.fieldIndex("ragsoc"))
        self.mapper.addMapping(self.cliComboBox, MIDCLI)

        self.mapper.addMapping(self.tipoPagLineEdit, MPAG)
        self.mapper.addMapping(self.cauLineEdit, MCAU)
        self.mapper.addMapping(self.noteLineEdit, MNOTE)
        self.mapper.toFirst()
Esempio n. 8
0
 def __init__(self, config, parent=None):
     QDialog.__init__(self, parent)
     curdir = os.path.abspath(os.path.dirname(__file__))
     PyQt4.uic.loadUi(os.path.join(curdir, 'manager.ui'), self)
     self.model = QStandardItemModel()
     self.projectsmodel = QStandardItemModel()
     self.projectlist.setModel(self.projectsmodel)
     self.clientlist.setModel(self.model)
     self.clientlist.selectionModel().selectionChanged.connect(self.update)
     self.installbutton.pressed.connect(self.installToClient)
     self.mapper = QDataWidgetMapper()
     self.mapper.setModel(self.model)
     self.mapper.addMapping(self.installpath, 1)
     self.config = config
     self.populateProjects()
     self.populateClients()
Esempio n. 9
0
 def setupMappers(self):
     '''
         Initialize all the application mappers
     '''
     self.mapper = QDataWidgetMapper(self)
     self.mapper.setModel(self.mModel)
     self.mapper.addMapping(self.scaffLineEdit, SCAFF)
     self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
     self.mapper.toFirst()
Esempio n. 10
0
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0, 0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(
            self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()
Esempio n. 11
0
    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        for i in range(2, self.tableView.horizontalHeader().count() + 1):
            self.tableView.horizontalHeader().resizeSection(
                i, self.set_width_with_dpi(80))
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8)
        self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        #self.speakerList = QStringList(self.db.get_speaker_list())
        #self.categoryList = QStringList(self.db.get_category_list())
        #self.eventList = QStringList(self.db.get_event_list())
        #self.roomList = QStringList(self.db.get_room_list())

        #Disble input
        self.talkDetailsWidget.disable_input_fields()
Esempio n. 12
0
    def __init__(self, do, model, bp, parent):
        ComplexToolTip.__init__(self, parent)
        self.ui = Ui_BreakpointWidget()
        self.ui.setupUi(self)

        self.ui.description.setText("Breakpoint %s at %s (%s)" % (bp.number, bp.where, bp.addr))
        self.ui.icon.setPixmap(bp.icon.pixmap(16, 16))
        self.ui.action.init(do)

        row, _ = model.findRowForNumber(bp.number)
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(model)
        self.mapper.addMapping(self.ui.enabled, 1)
        self.mapper.addMapping(self.ui.condition, 4)
        self.mapper.addMapping(self.ui.skip, 5)
        self.mapper.addMapping(self.ui.hits, 6)
        self.mapper.addMapping(self.ui.autoContinue, 7)
        self.mapper.addMapping(self.ui.name, 8)
        self.mapper.addMapping(self.ui.action, 9)
        self.mapper.setCurrentIndex(row)

        # for some reason, the enabled checkbox does not autosubmit while the autoContinue one does
        self.ui.enabled.clicked.connect(self.mapper.submit)
Esempio n. 13
0
	def __init__(self, config, parent=None):
		QDialog.__init__(self, parent)
		curdir = os.path.abspath(os.path.dirname(__file__))
		PyQt4.uic.loadUi(os.path.join(curdir,'manager.ui'), self)
		self.model = QStandardItemModel()
		self.projectsmodel = QStandardItemModel()
		self.projectlist.setModel(self.projectsmodel)
		self.clientlist.setModel(self.model)
		self.clientlist.selectionModel().selectionChanged.connect(self.update)
		self.installbutton.pressed.connect(self.installToClient)
		self.mapper = QDataWidgetMapper()
		self.mapper.setModel(self.model)
		self.mapper.addMapping(self.installpath, 1)
		self.config = config
		self.populateProjects()
		self.populateClients()
Esempio n. 14
0
    def __init__(self, parent, own_toolbar=False):
        """
        @param parent: El widget padre de esta ventana
        @param own_toolbar: Si este widget dibujara su toolbar en el padre o en el mismo
        @type parent: QWidget
        @type own_toolbar: bool
        """
        super(Base, self).__init__(parent)
        self.user = user.LoggedUser
        self._status = True
        self.parentWindow = parent
        self.own_toolbar = own_toolbar

        self.database = QSqlDatabase.database()
        """
        @type: QSqlDatabase
        @ivar: La base de datos a la cual se conecta el sistema
        """

        self.mapper = QDataWidgetMapper(self)
        u"""
        @type: QDataWidgetMapper
        @ivar: El mapper que se encarga de asignar los 
        datos del modelo de navegación a los distintos widgets
        """

        self.printProgressBar = QProgressBar(self)
        self.webview = QWebView()
        """
        @ivar: EL objeto webview usado para cargar los reportes
        @type: QWebView
        """
        self.loaded = False
        """
        @ivar: Si se pudo o no cargar un reporte
        @type: bool
        """

        self.startUi()

        self.editmodel = None
        self.printer = QPrinter()

        self._status = False
Esempio n. 15
0
    def __init__(self, parent=None):
        super(FrmOperations, self).__init__(parent)
        self.setupUi(self)
        self.__status = False
        self.database = QSqlDatabase.database()

        self.navmodel = QSqlQueryModel()
        self.navproxymodel = QSortFilterProxyModel()
        self.navproxymodel.setFilterKeyColumn(-1)
        self.navproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.navproxymodel.setSourceModel(self.navmodel)

        self.detailsmodel = QSqlQueryModel()
        self.detailsproxymodel = QSortFilterProxyModel()
        self.detailsproxymodel.setSourceModel(self.detailsmodel)

        self.navproxymodel.setDynamicSortFilter(True)
        self.detailsproxymodel.setDynamicSortFilter(True)

        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.navproxymodel)

        self.user = user.LoggedUser

        self.editModel = None

        self.tableNavigation.setModel(self.navproxymodel)
        self.tableDetails.setModel(self.detailsproxymodel)

        self.tableDetails.setColumnHidden(IDCUENTA, True)
        self.tableDetails.setColumnHidden(IDDOCUMENTOC, True)

        self.actionCancelar.setVisible(False)
        self.actionGuardar.setVisible(False)

        #        self.actionGuardar.activated.connect( self.save )
        self.tableNavigation.selectionModel().selectionChanged[QItemSelection, QItemSelection].connect(
            self.updateDetails
        )

        QTimer.singleShot(0, self.updateModels)
Esempio n. 16
0
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0,0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()
Esempio n. 17
0
    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        for i in range(2, self.tableView.horizontalHeader().count() + 1):
            self.tableView.horizontalHeader().resizeSection(i, self.set_width_with_dpi(80))
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8)
        self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        # self.speakerList = QStringList(self.db.get_speaker_list())
        # self.categoryList = QStringList(self.db.get_category_list())
        # self.eventList = QStringList(self.db.get_event_list())
        # self.roomList = QStringList(self.db.get_room_list())

        # Disble input
        self.talkDetailsWidget.disable_input_fields()
Esempio n. 18
0
class TalkEditorApp(FreeseerApp):
    '''Freeseer talk database editor main gui class'''
    def __init__(self, config, db):
        FreeseerApp.__init__(self)

        self.config = config
        self.db = db

        icon = QIcon()
        icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)
        self.resize(960, 600)

        #
        # Setup Layout
        #
        self.mainWidget = QWidget()
        self.mainLayout = QVBoxLayout()
        self.mainWidget.setLayout(self.mainLayout)
        self.setCentralWidget(self.mainWidget)
        self.mainLayout.setAlignment(QtCore.Qt.AlignTop)

        # Add the Title Row (Use BOLD / Big Font)
        #self.titleLayout = QHBoxLayout()
        #self.backButton = QPushButton('Back to Recorder')
        #if backButton:  # Only show the back button if requested by caller
        #    self.titleLayout.addWidget(self.backButton)
        #self.titleLayout.addStretch()

        # Add custom widgets
        self.commandButtons = CommandButtons()
        self.tableView = QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.talkDetailsWidget = TalkDetailsWidget()
        self.importTalksWidget = ImportTalksWidget()
        self.mainLayout.addWidget(self.importTalksWidget)
        #self.mainLayout.addLayout(self.titleLayout)
        self.mainLayout.addWidget(self.commandButtons)
        self.mainLayout.addWidget(self.tableView)
        self.mainLayout.addWidget(self.talkDetailsWidget)
        self.mainLayout.addWidget(self.importTalksWidget)
        # --- End Layout

        # Initialize geometry, to be used for restoring window positioning.
        self.geometry = None

        #
        # Setup Menubar
        #
        self.actionExportCsv = QAction(self)
        self.actionExportCsv.setObjectName('actionExportCsv')
        self.actionRemoveAll = QAction(self)
        self.actionRemoveAll.setObjectName('actionRemoveAll')

        # Actions
        self.menuFile.insertAction(self.actionExit, self.actionExportCsv)
        self.menuFile.insertAction(self.actionExit, self.actionRemoveAll)
        # --- End Menubar

        #
        # TableView Connections
        #
        self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected)

        # Import Widget
        self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import)
        self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks)
        self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget)
        self.importTalksWidget.setHidden(True)
        self.connect(self.importTalksWidget.csvFileSelectButton, QtCore.SIGNAL('clicked()'), self.csv_file_select)
        self.connect(self.importTalksWidget.csvLineEdit, QtCore.SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.importTalksWidget.rssLineEdit, QtCore.SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.actionExportCsv, QtCore.SIGNAL('triggered()'), self.export_talks_to_csv)
        self.connect(self.actionRemoveAll, QtCore.SIGNAL('triggered()'), self.confirm_reset)

        # Command Buttons
        self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk)
        self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset)
        self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget)
        self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv)
        self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks)

        # Talk Details Buttons
        self.connect(self.talkDetailsWidget.addButton, SIGNAL('clicked()'), self.confirm_add)
        self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.add_talk)

        # Load default language
        actions = self.menuLanguage.actions()
        for action in actions:
            if action.data().toString() == self.config.default_language:
                action.setChecked(True)
                self.translate(action)
                break

        # Load Talk Database
        self.load_presentations_model()

        # Setup Autocompletion
        self.update_autocomple_fields()

        # Select first item
        #self.tableView.setCurrentIndex(self.proxy.index(0,0))
        #self.talk_selected(self.proxy.index(0,0))

    #
    # Translation
    #
    def retranslate(self):
        self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor"))

        #
        # Reusable Strings
        #
        self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database")
        self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp",
                                                               "Are you sure you want to clear the DB?")
        self.confirmTalkDetailsClearTitleString = self.app.translate("TalkEditorApp", "Unsaved Data")
        self.confirmTalkDetailsClearQuestionString = self.app.translate("TalkEditorApp",
                                                                        "Unsaved talk details will be lost. Continue?")
        # --- End Reusable Strings

        #
        # Menubar
        #
        self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV"))
        self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks"))

        # --- End Menubar

        #
        # TalkDetailsWidget
        #
        self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title"))
        self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter"))
        self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category"))
        self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event"))
        self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room"))
        self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date"))
        self.talkDetailsWidget.timeLabel.setText(self.app.translate("TalkEditorApp", "Time"))
        # --- End TalkDetailsWidget

        #
        # Import Talks Widget Translations
        #
        self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL"))
        self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File"))
        self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        # --- End Talks Widget Translations

        #
        # Command Button Translations\
        #
        #self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add"))
        self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export"))
        self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove"))
        self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All"))
        # --- End Command Butotn Translations

        #
        # Search Widget Translations
        #
        self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search"))
        # --- End Command Button Translations

    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.timeEdit, 8)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        #self.speakerList = QStringList(self.db.get_speaker_list())
        #self.categoryList = QStringList(self.db.get_category_list())
        #self.eventList = QStringList(self.db.get_event_list())
        #self.roomList = QStringList(self.db.get_room_list())

        #Disble input
        self.talkDetailsWidget.disable_input_fields()

    def search_talks(self):
        # The default value is 0. If the value is -1, the keys will be read from all columns.
        self.proxy.setFilterKeyColumn(-1)
        self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text())

    def talk_selected(self, model):
        self.talkDetailsWidget.saveButton.setEnabled(False)
        self.mapper.setCurrentIndex(model.row())
        self.talkDetailsWidget.enable_input_fields()

    def toggle_import(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.importTalksWidget.csvLineEdit.setEnabled(True)
            self.importTalksWidget.csvFileSelectButton.setEnabled(True)
            self.importTalksWidget.rssLineEdit.setEnabled(False)
        else:
            self.importTalksWidget.csvLineEdit.setEnabled(False)
            self.importTalksWidget.csvFileSelectButton.setEnabled(False)
            self.importTalksWidget.rssLineEdit.setEnabled(True)

    def show_import_talks_widget(self):
        self.commandButtons.setHidden(True)
        self.tableView.setHidden(True)
        self.talkDetailsWidget.setHidden(True)
        self.importTalksWidget.setHidden(False)

    def hide_import_talks_widget(self):
        self.commandButtons.setHidden(False)
        self.tableView.setHidden(False)
        self.talkDetailsWidget.setHidden(False)
        self.importTalksWidget.setHidden(True)

    def add_talk(self):
        date = self.talkDetailsWidget.dateEdit.date()
        time = self.talkDetailsWidget.timeEdit.time()
        #datetime = QtCore.QDateTime(date, time)
        presentation = Presentation(
            unicode(self.talkDetailsWidget.titleLineEdit.text()).strip(),
            unicode(self.talkDetailsWidget.presenterLineEdit.text()).strip(),
            unicode(self.talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(),
            unicode(self.talkDetailsWidget.categoryLineEdit.text()).strip(),
            unicode(self.talkDetailsWidget.eventLineEdit.text()).strip(),
            unicode(self.talkDetailsWidget.roomLineEdit.text()).strip(),
            unicode(date.toString(QtCore.Qt.ISODate)),
            unicode(time.toString(QtCore.Qt.ISODate)))

        # Do not add talks if they are empty strings
        if (len(presentation.title) == 0):
            return
        self.db.insert_presentation(presentation)

        # Update Model, Refreshes TableView
        self.presentationModel.select()

        # Select Last Row
        self.tableView.selectRow(self.presentationModel.rowCount() - 1)
        self.tableView.setCurrentIndex(self.proxy.index(self.proxy.rowCount() - 1, 0))
        self.talk_selected(self.proxy.index(self.proxy.rowCount() - 1, 0))

        self.update_autocomple_fields()
        self.talkDetailsWidget.disable_input_fields()

    def confirm_add(self):
        """Requests confirmation before clearing fields for a new talk."""
        if self.are_fields_enabled() and self.unsaved_details_exist():
            confirm = QMessageBox.question(self,
                                           self.confirmTalkDetailsClearTitleString,
                                           self.confirmTalkDetailsClearQuestionString,
                                           QMessageBox.Yes,
                                           QMessageBox.No)

            if confirm == QMessageBox.Yes:
                self.clear_talk_details_widget()
        else:
            self.clear_talk_details_widget()

    def clear_talk_details_widget(self):
        self.talkDetailsWidget.saveButton.setEnabled(True)
        self.talkDetailsWidget.enable_input_fields()
        self.talkDetailsWidget.titleLineEdit.clear()
        self.talkDetailsWidget.presenterLineEdit.clear()
        self.talkDetailsWidget.descriptionTextEdit.clear()
        self.talkDetailsWidget.categoryLineEdit.clear()
        #self.talkDetailsWidget.eventLineEdit.clear()
        #self.talkDetailsWidget.roomLineEdit.clear()
        self.presentationModel.select()

    def remove_talk(self):
        try:
            rows_selected = self.tableView.selectionModel().selectedRows()
        except:
            return

        # Reversed because rows in list change position once row is removed
        for row in reversed(rows_selected):
            self.presentationModel.removeRow(row.row())

    def load_talk(self):
        try:
            self.tableView.currentIndex().row()
        except:
            return

        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.presentationModel.select()

    def reset(self):
        self.db.clear_database()
        self.presentationModel.select()

    def confirm_reset(self):
        """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database.
        If Yes call the reset() function"""
        confirm = QMessageBox.question(self,
                                       self.confirmDBClearTitleString,
                                       self.confirmDBClearQuestionString,
                                       QMessageBox.Yes |
                                       QMessageBox.No,
                                       QMessageBox.No)

        if confirm == QMessageBox.Yes:
            self.reset()

    def add_talks_from_rss(self):
        rss_url = unicode(self.importTalksWidget.rssLineEdit.text())
        if rss_url:
            self.db.add_talks_from_rss(rss_url)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please enter a RSS URL")
            error.exec_()

    def closeEvent(self, event):
        log.info('Exiting talk database editor...')
        self.geometry = self.saveGeometry()
        event.accept()

    def csv_file_select(self):
        fname = QFileDialog.getOpenFileName(
            self, 'Select file', "", "*.csv")
        if fname:
            self.importTalksWidget.csvLineEdit.setText(fname)

    def add_talks_from_csv(self):
        fname = self.importTalksWidget.csvLineEdit.text()

        if fname:
            self.db.add_talks_from_csv(fname)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please select a file")
            error.exec_()

    def import_talks(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.add_talks_from_csv()
        else:
            self.add_talks_from_rss()

        self.update_autocomple_fields()

    def export_talks_to_csv(self):
        fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv")
        if fname:
            self.db.export_talks_to_csv(fname)

    def update_autocomple_fields(self):
        self.titleList = QStringList(self.db.get_string_list("Title"))
        self.speakerList = QStringList(self.db.get_string_list("Speaker"))
        self.categoryList = QStringList(self.db.get_string_list("Category"))
        self.eventList = QStringList(self.db.get_string_list("Event"))
        self.roomList = QStringList(self.db.get_string_list("Room"))

        self.titleCompleter = QCompleter(self.titleList)
        self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.speakerCompleter = QCompleter(self.speakerList)
        self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.categoryCompleter = QCompleter(self.categoryList)
        self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.eventCompleter = QCompleter(self.eventList)
        self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.roomCompleter = QCompleter(self.roomList)
        self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive)

        self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter)
        self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter)
        self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter)
        self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter)
        self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter)

    def are_fields_enabled(self):
        return (self.talkDetailsWidget.titleLineEdit.isEnabled() and
                self.talkDetailsWidget.presenterLineEdit.isEnabled() and
                self.talkDetailsWidget.categoryLineEdit.isEnabled() and
                self.talkDetailsWidget.eventLineEdit.isEnabled() and
                self.talkDetailsWidget.roomLineEdit.isEnabled() and
                self.talkDetailsWidget.dateEdit.isEnabled() and
                self.talkDetailsWidget.timeEdit.isEnabled())

    def unsaved_details_exist(self):
        """Checks if details exist for a new talk

        Looks for text in the input fields and check the enabled state of the Save Talk button
        If the Save Talk button is enabled, the input fields contain values for a new talk
        Otherwise, the input fields contain values for an existing selected talk
        """
        return (self.talkDetailsWidget.saveButton.isEnabled() and
                (self.talkDetailsWidget.titleLineEdit.text() or
                self.talkDetailsWidget.presenterLineEdit.text() or
                self.talkDetailsWidget.categoryLineEdit.text() or
                self.talkDetailsWidget.descriptionTextEdit.toPlainText()))
Esempio n. 19
0
class TalkEditorApp(FreeseerApp):
    '''Freeseer talk database editor main gui class'''
    def __init__(self, config, db):
        FreeseerApp.__init__(self)

        self.config = config
        self.db = db

        icon = QIcon()
        icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)
        self.resize(960, 600)

        #
        # Setup Layout
        #
        self.mainWidget = QWidget()
        self.mainLayout = QVBoxLayout()
        self.mainWidget.setLayout(self.mainLayout)
        self.setCentralWidget(self.mainWidget)
        self.mainLayout.setAlignment(QtCore.Qt.AlignTop)

        # Add the Title Row (Use BOLD / Big Font)
        #self.titleLayout = QHBoxLayout()
        #self.backButton = QPushButton('Back to Recorder')
        #if backButton:  # Only show the back button if requested by caller
        #    self.titleLayout.addWidget(self.backButton)
        #self.titleLayout.addStretch()

        # Add custom widgets
        self.commandButtons = CommandButtons()
        self.tableView = QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.talkDetailsWidget = TalkDetailsWidget()
        self.importTalksWidget = ImportTalksWidget()
        self.mainLayout.addWidget(self.importTalksWidget)
        #self.mainLayout.addLayout(self.titleLayout)
        self.mainLayout.addWidget(self.commandButtons)
        self.mainLayout.addWidget(self.tableView)
        self.mainLayout.addWidget(self.talkDetailsWidget)
        self.mainLayout.addWidget(self.importTalksWidget)
        # --- End Layout

        # Initialize geometry, to be used for restoring window positioning.
        self.geometry = None

        #
        # Setup Menubar
        #
        self.actionExportCsv = QAction(self)
        self.actionExportCsv.setObjectName('actionExportCsv')
        self.actionRemoveAll = QAction(self)
        self.actionRemoveAll.setObjectName('actionRemoveAll')

        # Actions
        self.menuFile.insertAction(self.actionExit, self.actionExportCsv)
        self.menuFile.insertAction(self.actionExit, self.actionRemoveAll)
        # --- End Menubar

        #
        # TableView Connections
        #
        self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected)

        # Import Widget
        self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import)
        self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks)
        self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget)
        self.importTalksWidget.setHidden(True)
        self.connect(self.importTalksWidget.csvFileSelectButton, QtCore.SIGNAL('clicked()'), self.csv_file_select)
        self.connect(self.importTalksWidget.csvLineEdit, QtCore.SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.importTalksWidget.rssLineEdit, QtCore.SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.actionExportCsv, QtCore.SIGNAL('triggered()'), self.export_talks_to_csv)
        self.connect(self.actionRemoveAll, QtCore.SIGNAL('triggered()'), self.confirm_reset)

        # Command Buttons
        self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk)
        self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset)
        self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget)
        self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv)
        self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks)

        # Talk Details Buttons
        self.connect(self.talkDetailsWidget.addButton, SIGNAL('clicked()'), self.clear_talk_details_widget)
        self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.add_talk)

        # Load default language
        actions = self.menuLanguage.actions()
        for action in actions:
            if action.data().toString() == self.config.default_language:
                action.setChecked(True)
                self.translate(action)
                break

        # Load Talk Database
        self.load_presentations_model()

        # Setup Autocompletion
        self.update_autocomple_fields()

        # Select first item
        #self.tableView.setCurrentIndex(self.proxy.index(0,0))
        #self.talk_selected(self.proxy.index(0,0))

    #
    # Translation
    #
    def retranslate(self):
        self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor"))

        #
        # Reusable Strings
        #
        self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database")
        self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp",
            "Are you sure you want to clear the DB?")
        # --- End Reusable Strings

        #
        # Menubar
        #
        self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV"))
        self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks"))

        # --- End Menubar

        #
        # TalkDetailsWidget
        #
        self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title"))
        self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter"))
        self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category"))
        self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event"))
        self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room"))
        self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date"))
        self.talkDetailsWidget.timeLabel.setText(self.app.translate("TalkEditorApp", "Time"))
        # --- End TalkDetailsWidget

        #
        # Import Talks Widget Translations
        #
        self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL"))
        self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File"))
        self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        # --- End Talks Widget Translations

        #
        # Command Button Translations\
        #
        #self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add"))
        self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export"))
        self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove"))
        self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All"))
        # --- End Command Butotn Translations

        #
        # Search Widget Translations
        #
        self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search"))
        # --- End Command Button Translations

    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.timeEdit, 8)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        #self.speakerList = QStringList(self.db.get_speaker_list())
        #self.categoryList = QStringList(self.db.get_category_list())
        #self.eventList = QStringList(self.db.get_event_list())
        #self.roomList = QStringList(self.db.get_room_list())

        #Disble input
        self.talkDetailsWidget.disable_input_fields()

    def search_talks(self):
        # The default value is 0. If the value is -1, the keys will be read from all columns.
        self.proxy.setFilterKeyColumn(-1)
        self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text())

    def talk_selected(self, model):
        self.talkDetailsWidget.saveButton.setEnabled(False)
        self.mapper.setCurrentIndex(model.row())
        self.talkDetailsWidget.enable_input_fields()

    def toggle_import(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.importTalksWidget.csvLineEdit.setEnabled(True)
            self.importTalksWidget.csvFileSelectButton.setEnabled(True)
            self.importTalksWidget.rssLineEdit.setEnabled(False)
        else:
            self.importTalksWidget.csvLineEdit.setEnabled(False)
            self.importTalksWidget.csvFileSelectButton.setEnabled(False)
            self.importTalksWidget.rssLineEdit.setEnabled(True)

    def show_import_talks_widget(self):
        self.commandButtons.setHidden(True)
        self.tableView.setHidden(True)
        self.talkDetailsWidget.setHidden(True)
        self.importTalksWidget.setHidden(False)

    def hide_import_talks_widget(self):
        self.commandButtons.setHidden(False)
        self.tableView.setHidden(False)
        self.talkDetailsWidget.setHidden(False)
        self.importTalksWidget.setHidden(True)

    def add_talk(self):
        date = self.talkDetailsWidget.dateEdit.date()
        time = self.talkDetailsWidget.timeEdit.time()
        #datetime = QtCore.QDateTime(date, time)
        presentation = Presentation(
            unicode(self.talkDetailsWidget.titleLineEdit.text()),
            unicode(self.talkDetailsWidget.presenterLineEdit.text()),
            unicode(self.talkDetailsWidget.descriptionTextEdit.toPlainText()),
            unicode(self.talkDetailsWidget.categoryLineEdit.text()),
            unicode(self.talkDetailsWidget.eventLineEdit.text()),
            unicode(self.talkDetailsWidget.roomLineEdit.text()),
            unicode(date.toString(QtCore.Qt.ISODate)),
            unicode(time.toString(QtCore.Qt.ISODate)))

        # Do not add talks if they are empty strings
        if (len(presentation.title) == 0):
            return
        self.db.insert_presentation(presentation)

        # Update Model, Refreshes TableView
        self.presentationModel.select()

        # Select Last Row
        self.tableView.selectRow(self.presentationModel.rowCount() - 1)
        self.tableView.setCurrentIndex(self.proxy.index(self.proxy.rowCount() - 1, 0))
        self.talk_selected(self.proxy.index(self.proxy.rowCount() - 1, 0))

        self.update_autocomple_fields()
        self.talkDetailsWidget.disable_input_fields()

    def clear_talk_details_widget(self):
        self.talkDetailsWidget.saveButton.setEnabled(True)
        self.talkDetailsWidget.enable_input_fields()
        self.talkDetailsWidget.titleLineEdit.clear()
        self.talkDetailsWidget.presenterLineEdit.clear()
        self.talkDetailsWidget.descriptionTextEdit.clear()
        #self.talkDetailsWidget.categoryLineEdit.clear()
        #self.talkDetailsWidget.eventLineEdit.clear()
        #self.talkDetailsWidget.roomLineEdit.clear()
        self.presentationModel.select()

    def remove_talk(self):
        try:
            rows_selected = self.tableView.selectionModel().selectedRows()
        except:
            return

        # Reversed because rows in list change position once row is removed
        for row in reversed(rows_selected):
            self.presentationModel.removeRow(row.row())

    def load_talk(self):
        try:
            self.tableView.currentIndex().row()
        except:
            return

        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.presentationModel.select()

    def reset(self):
        self.db.clear_database()
        self.presentationModel.select()

    def confirm_reset(self):
        """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database.
        If Yes call the reset() function"""
        confirm = QMessageBox.question(self,
                                       self.confirmDBClearTitleString,
                                       self.confirmDBClearQuestionString,
                                       QMessageBox.Yes |
                                       QMessageBox.No,
                                       QMessageBox.No)

        if confirm == QMessageBox.Yes:
            self.reset()

    def add_talks_from_rss(self):
        rss_url = unicode(self.importTalksWidget.rssLineEdit.text())
        if rss_url:
            self.db.add_talks_from_rss(rss_url)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please enter a RSS URL")
            error.exec_()

    def closeEvent(self, event):
        log.info('Exiting talk database editor...')
        self.geometry = self.saveGeometry()
        event.accept()

    def csv_file_select(self):
        fname = QFileDialog.getOpenFileName(
            self, 'Select file', "", "*.csv")
        if fname:
            self.importTalksWidget.csvLineEdit.setText(fname)

    def add_talks_from_csv(self):
        fname = self.importTalksWidget.csvLineEdit.text()

        if fname:
            self.db.add_talks_from_csv(fname)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please select a file")
            error.exec_()

    def import_talks(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.add_talks_from_csv()
        else:
            self.add_talks_from_rss()

        self.update_autocomple_fields()

    def export_talks_to_csv(self):
        fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv")
        if fname:
            self.db.export_talks_to_csv(fname)

    def update_autocomple_fields(self):
        self.titleList = QStringList(self.db.get_string_list("Title"))
        self.speakerList = QStringList(self.db.get_string_list("Speaker"))
        self.categoryList = QStringList(self.db.get_string_list("Category"))
        self.eventList = QStringList(self.db.get_string_list("Event"))
        self.roomList = QStringList(self.db.get_string_list("Room"))

        self.titleCompleter = QCompleter(self.titleList)
        self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.speakerCompleter = QCompleter(self.speakerList)
        self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.categoryCompleter = QCompleter(self.categoryList)
        self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.eventCompleter = QCompleter(self.eventList)
        self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.roomCompleter = QCompleter(self.roomList)
        self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive)

        self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter)
        self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter)
        self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter)
        self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter)
        self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter)
Esempio n. 20
0
class FrmOperations(QMainWindow, Ui_frmOperations):
    def __init__(self, parent=None):
        super(FrmOperations, self).__init__(parent)
        self.setupUi(self)
        self.__status = False
        self.database = QSqlDatabase.database()

        self.navmodel = QSqlQueryModel()
        self.navproxymodel = QSortFilterProxyModel()
        self.navproxymodel.setFilterKeyColumn(-1)
        self.navproxymodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.navproxymodel.setSourceModel(self.navmodel)

        self.detailsmodel = QSqlQueryModel()
        self.detailsproxymodel = QSortFilterProxyModel()
        self.detailsproxymodel.setSourceModel(self.detailsmodel)

        self.navproxymodel.setDynamicSortFilter(True)
        self.detailsproxymodel.setDynamicSortFilter(True)

        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.navproxymodel)

        self.user = user.LoggedUser

        self.editModel = None

        self.tableNavigation.setModel(self.navproxymodel)
        self.tableDetails.setModel(self.detailsproxymodel)

        self.tableDetails.setColumnHidden(IDCUENTA, True)
        self.tableDetails.setColumnHidden(IDDOCUMENTOC, True)

        self.actionCancelar.setVisible(False)
        self.actionGuardar.setVisible(False)

        #        self.actionGuardar.activated.connect( self.save )
        self.tableNavigation.selectionModel().selectionChanged[QItemSelection, QItemSelection].connect(
            self.updateDetails
        )

        QTimer.singleShot(0, self.updateModels)

    def updateModels(self):
        try:
            if not self.database.isOpen():
                if not self.database.open():
                    raise UserWarning("No se pudo conectar con la base de datos")
            self.navmodel.setQuery(
                """
            SELECT 
                d.iddocumento, 
                d.ndocimpreso as 'N Doc', 
                d.fechacreacion as 'Fecha', 
                c.descripcion as 'Concepto'
            FROM documentos d
            JOIN conceptos c ON c.idconcepto = d.idconcepto
            WHERE d.idtipodoc = %d
            ORDER BY d.iddocumento DESC
            """
                % constantes.IDAJUSTECONTABLE
            )
            self.detailsmodel.setQuery(
                """
            SELECT 
                cxd.idcuenta,  
                cc.codigo as 'Codigo Cuenta', 
                cc.descripcion as 'Nombre Cuenta',
                CONCAT('C$',FORMAT(cxd.monto,4)) as Monto,
                cxd.iddocumento  
            FROM cuentasxdocumento cxd 
            JOIN cuentascontables cc ON cxd.idcuenta = cc.idcuenta
            JOIN documentos d ON d.iddocumento = cxd.iddocumento 
            WHERE d.idtipodoc = %d
            ORDER BY nlinea 
            """
                % constantes.IDAJUSTECONTABLE
            )

            self.mapper.addMapping(self.dtPicker, FECHACREACION)
            self.mapper.addMapping(self.txtConcept, CONCEPTO)
            self.tableNavigation.selectionModel().setCurrentIndex(
                self.navproxymodel.index(0, 0), QItemSelectionModel.Select
            )

            self.tableNavigation.setColumnHidden(IDDOCUMENTO, True)
            self.tableDetails.setColumnHidden(IDDOCUMENTOC, True)
            self.tableDetails.setColumnHidden(IDCUENTA, True)

            self.tableDetails.setColumnWidth(CODIGO, 240)
            self.tableDetails.setColumnWidth(DESCRIPCION, 250)

            self.tableNavigation.setColumnWidth(FECHACREACION, 200)
            self.tableNavigation.setColumnWidth(CONCEPTO, 250)
        except UserWarning as inst:
            logging.error(inst)
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
        except Exception as inst:
            logging.critical(inst)

    def updateDetails(self, selected, _deselected):
        if len(selected.indexes()) > 0:
            self.mapper.setCurrentModelIndex(selected.indexes()[0])
            self.detailsproxymodel.setFilterKeyColumn(IDDOCUMENTOC)
            self.detailsproxymodel.setFilterRegExp(self.navproxymodel.data(selected.indexes()[0]).toString())

    def setStatus(self, status):
        """
        Cambiar el modo del formulario
        
        true = adding
        false = navigating
        
        @param status: El modo del formulario
        @type status:bool
        """

        self.widget.setHidden(status)
        self.txtSearch.setEnabled(not status)
        self.actionNuevo.setVisible(not status)
        self.actionCancelar.setVisible(status)
        self.actionGuardar.setVisible(status)
        self.cbConcepts.setEnabled(status)
        self.tableDetails.setEditTriggers(QTableView.AllEditTriggers if status else QTableView.NoEditTriggers)
        self.tableNavigation.setEnabled(not status)
        self.tableDetails.setEditTriggers(QTableView.AllEditTriggers)
        #        self.stackedWidget.setCurrentIndex( 0 if status else 1 )
        self.stConcepts.setCurrentIndex(1 if status else 0)

    def getStatus(self):
        return self.__status

    status = property(getStatus, setStatus)

    @pyqtSlot()
    def on_actionCancelar_activated(self):
        self.status = False
        self.editModel = None
        self.tableDetails.setModel(self.detailsproxymodel)
        self.tableDetails.setColumnHidden(IDDOCUMENTOC, True)
        self.tableDetails.setColumnHidden(IDCUENTA, True)

    @pyqtSlot()
    def on_actionGuardar_activated(self):
        self.save()

    @pyqtSlot()
    def on_actionNuevo_activated(self):
        try:
            if not self.database.isOpen():
                if not self.database.open():
                    raise UserWarning("No se pudo abrir la base de datos")

            self.editModel = AccountsSelectorModel()
            self.editModel.insertRow(1)

            delegate = AccountsSelectorDelegate(
                QSqlQuery(
                    """
            SELECT 
                c.idcuenta, 
                c.codigo, 
                c.descripcion 
            FROM cuentascontables c 
            JOIN cuentascontables p ON c.padre = p.idcuenta AND p.padre != 1
            """
                )
            )

            self.dtPicker.setDateTime(QDateTime.currentDateTime())
            self.dtPicker.setMaximumDateTime(QDateTime.currentDateTime())

            self.conceptsmodel = QSqlQueryModel()
            q = """
            SELECT
                idconcepto,
                descripcion
            FROM conceptos
            WHERE idtipodoc = %d and idconcepto <>%d
             """ % (
                constantes.IDAJUSTECONTABLE,
                constantes.IDCONCEPTOBALANCEINICIAL,
            )

            self.conceptsmodel.setQuery(q)

            if self.conceptsmodel.rowCount() < 1:
                raise UserWarning(
                    "No existen conceptos para ajustes contables, por favor comuniquese con el administrador del sistema"
                )

            self.cbConcepts.setModel(self.conceptsmodel)
            self.cbConcepts.setModelColumn(1)
            self.tableDetails.setModel(self.editModel)
            self.tableDetails.setColumnHidden(IDCUENTA, True)
            self.tableDetails.setColumnHidden(IDDOCUMENTOC, True)
            self.tableDetails.setItemDelegate(delegate)

            self.status = True

            self.tableDetails.resizeColumnsToContents()
        except UserWarning as inst:
            self.status = False
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            logging.error(unicode(inst))
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al tratar de iniciar un nuevo ajuste")
            logging.critical(unicode(inst))
            self.status = False

    @pyqtSlot("QString")
    def on_txtSearch_textChanged(self, text):

        self.navproxymodel.setFilterRegExp(text)

    def save(self):
        query = QSqlQuery()

        try:
            if not self.editModel.valid:
                raise UserWarning("El documento no es valido, no se puede guardar")

            if not self.database.isOpen():
                if not self.database.open():
                    raise UserWarning("No se pudo conectar con la base de datos")

            if not self.database.transaction():
                raise Exception(u"No se pudo comenzar la transacción")
            #               Cargar el numero del asiento actual
            query.prepare(
                """
            SELECT
                  MAX(CAST(ndocimpreso AS SIGNED))+1
            FROM documentos d
            WHERE idtipodoc=24
            ;
            """
            )

            query.exec_()
            query.first()

            n = query.value(0).toString()
            if n == "0":
                n = "1"

            if not query.prepare(
                """
            INSERT INTO documentos (ndocimpreso, fechacreacion, idconcepto,   idtipodoc)
            VALUES (:ndocimpreso, :fechacreacion, :idconcepto,  %d)
            """
                % constantes.IDAJUSTECONTABLE
            ):
                raise Exception("No se pudo preparar la consulta para guardar el documento")
            query.bindValue(":ndocimpreso", n)
            query.bindValue(":fechacreacion", self.dtPicker.dateTime().toString("yyyyMMddhhmmss"))
            query.bindValue(
                ":idconcepto", self.conceptsmodel.record(self.cbConcepts.currentIndex()).value("idconcepto").toInt()[0]
            )

            if not query.exec_():
                raise Exception("No se pudo ejecutar la consulta para guardar el asiento")

            insertedId = query.lastInsertId().toInt()[0]

            if not query.prepare(
                """
            INSERT INTO personasxdocumento (idpersona, iddocumento, idaccion) 
            VALUES (:usuario, :documento, :idaccion)
            """
            ):
                raise Exception("No se pudo preparar la consulta para insertar el usuario")
            query.bindValue(":usuario", self.user.uid)
            query.bindValue(":documento", insertedId)
            query.bindValue(":idaccion", constantes.ACCCREA)

            if not query.exec_():
                raise Exception(u"No se pudo guardar la relación con el usuario")

            for lineid, line in enumerate(self.editModel.lines):
                if line.valid:
                    line.save(insertedId, lineid + 1)

            if not self.database.commit():
                raise Exception("No se pudo ejecutar la transaccion")
            self.tableDetails.setModel(self.detailsproxymodel)
            self.updateModels()

            self.status = False
        except UserWarning as inst:
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            logging.error(inst)
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al tratar de guardar su ajuste")
            self.database.rollback()
            logging.critical(inst)
            logging.critical(query.lastError().text())
        finally:
            if self.database.isOpen():
                self.database.close()
Esempio n. 21
0
class TemplateWidget(QWidget, Ui_TemplateWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0, 0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(
            index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(
            self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()

    def selectedTemplate(self):
        index = self.listViewTemplates.selectionModel().currentIndex().row()
        if index >= 0:
            self.mapper.setCurrentIndex(index)

            server = self._templateList._templateList[index].server
            self.labelServerName.setText(server)
            self.loadServerMeta(server)

            self.setObjectclasses()
            self.setAttributes()
            self.tableViewAttributes.resizeColumnsToContents()
            self.tableViewAttributes.resizeRowsToContents()

    def setObjectclasses(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.objectclassTM.setTemplateObject(templateObject)

    def setAttributes(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.attributeTM.setTemplateObject(templateObject)

    def loadServerMeta(self, serverName):
        serverName = unicode(serverName)
        if not (serverName in self.preloadedServerMeta.keys()):
            serverMeta = self._serverList.getServerObject(serverName)
            self.preloadedServerMeta[serverName] = ObjectClassAttributeInfo(
                serverMeta)
        return self.preloadedServerMeta[serverName]

    def setRightSideEnabled(self, enabled):
        self.lineEditDescription.setEnabled(enabled)
        self.groupBoxObjectclasses.setEnabled(enabled)
        self.groupBoxAttributes.setEnabled(enabled)

    def clearAll(self):
        self.lineEditDescription.clear()
        self.labelServerName.clear()
        self.objectclassTM.setTemplateObject(None)
        self.attributeTM.setTemplateObject(None)

    def getSelectedTemplateObject(self):
        templateIndexes = self.listViewTemplates.selectedIndexes()
        if len(templateIndexes) > 0:
            return self._templateList.getTable()[templateIndexes[0].row()]
        return None

    def getSelectedObjectclass(self, index):
        return self.objectclassTM.getObjectclass(index)

    def getSelectedAttribute(self, index):
        return self.attributeTM.getAttribute(index)

    def addTemplate(self):
        dialog = AddTemplateDialog(self._serverList)
        if dialog.exec_():
            name = dialog.lineEditTemplateName.text()
            if len(name) < 1 or self._templateList.getTemplateObject(
                    name) != None:
                QMessageBox.information(self, 'Error',
                                        "Invalid name or already used.")
                return
            server = dialog.comboBoxServer.currentText()
            if len(server) < 1:
                QMessageBox.information(self, 'Error', "Invalid server.")
                return
            description = dialog.lineEditDescription.text()
            tO = TemplateObject(name, server, description)

            m = self.templateTM
            m.beginInsertRows(QModelIndex(), m.rowCount(), m.rowCount())
            m.insertRow(tO)
            m.endInsertRows()

            i = m.index(m.rowCount() - 1, 0)
            self.listViewTemplates.selectionModel().select(
                i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(
                i, QItemSelectionModel.ClearAndSelect)  #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()
            if i.row() == 0:
                self.setRightSideEnabled(True)

    def deleteTemplate(self):
        if self.listViewTemplates.selectionModel().currentIndex().row() < 0:
            return

        re = QMessageBox.question(self, "Delete", "Are you sure?",
                                  QMessageBox.Yes, QMessageBox.No)

        if re == QMessageBox.Yes:
            index = self.listViewTemplates.selectedIndexes()[
                0]  #Currently selected

            # Delete the template
            self.listViewTemplates.model().removeRow(index)

            # When deleting, the view gets updated and selects a new current.
            # Get it and give it to the mapper
            newIndex = self.listViewTemplates.selectionModel().currentIndex()
            self.mapper.setCurrentIndex(newIndex.row())

        # Disable editing if no templates left
        if self.templateTM.rowCount() == 0:
            self.setRightSideEnabled(False)
            self.clearAll()

    def duplicateTemplate(self):
        name, ok = QInputDialog.getText(self, 'Duplicate', 'Template name')
        if ok:
            if len(name) < 1 or self._templateList.getTemplateObject(
                    name) != None:
                QMessageBox.information(self, 'Error',
                                        "Invalid name or already used.")
                return
            tO = copy.deepcopy(self.getSelectedTemplateObject())
            tO.templateName = name

            m = self.listViewTemplates.model()
            m.insertRow(tO)
            i = m.index(m.rowCount() - 1, 0)
            self.listViewTemplates.selectionModel().select(
                i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(
                i, QItemSelectionModel.ClearAndSelect)  #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()

    def saveTemplate(self):
        self._templateList.save()

    def addObjectclass(self):
        server = self.labelServerName.text()
        dialog = AddObjectclassDialog(self.loadServerMeta(server),
                                      self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.listWidgetObjectclasses.selectedIndexes():
                item = dialog.listWidgetObjectclasses.itemFromIndex(i)
                self.objectclassTM.insertRow(str(item.text()))

        self.refreshMustAttributes()

    def deleteObjectclass(self):
        dOc = self.listViewObjectclasses.selectedIndexes()
        if dOc:
            server = self.labelServerName.text()
            tO = self.getSelectedTemplateObject()
            attributes = self.attributeTM.attributes
            dialog = DeleteObjectclassDialog(self.loadServerMeta(server), tO,
                                             dOc, attributes)
            if dialog.exec_():
                self.objectclassTM.removeRows(dOc)
                self.refreshAllAttributes()

    def refreshMustAttributes(self):
        tO = self.getSelectedTemplateObject()
        for attr in tO.attributes.values():
            if attr.must:
                self.attributeTM.removeAlways(attr)

        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        attributeNameList = ocai.getAllMusts(tO.objectclasses)
        for name in attributeNameList:
            single = ocai.isSingle(name)
            binary = ocai.isBinary(name)
            self.attributeTM.addRow(name, True, single, binary, "", False)

    def refreshAllAttributes(self):
        tO = self.getSelectedTemplateObject()
        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        must, may = ocai.getAllAttributes(tO.objectclasses)
        for attr in tO.attributes.items():
            if (not attr[0] in must) and (not attr[0] in may):
                self.attributeTM.removeAlways(attr[1])
            elif not attr[0] in must:
                attr[1].must = False

    def addAttribute(self):
        server = self.labelServerName.text()
        dialog = AddAttributeDialog(self.loadServerMeta(server),
                                    self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.tableView.selectedIndexes():
                if (i.column() == 0):
                    a = dialog.attributeTM.getAttribute(i)
                    self.attributeTM.addRow(a.attributeName, a.must, a.single,
                                            a.binary, a.defaultValue,
                                            a.customMust)

        self.tableViewAttributes.resizeRowsToContents()
        self.tableViewAttributes.resizeColumnsToContents()

    def deleteAttributes(self):
        if len(self.tableViewAttributes.selectedIndexes()):
            re = QMessageBox.question(
                self, self.tr('Delete'),
                self.
                tr("Are you sure you want to delete the selected attributes?"),
                QMessageBox.Yes, QMessageBox.No)
            if re == QMessageBox.Yes:
                self.attributeTM.removeRows(
                    self.tableViewAttributes.selectedIndexes())

    def changeEvent(self, e):
        """Overloaded so we can catch the LanguageChange event, and at
        translation support to the plugin
        """
        if e.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi(self)
        else:
            QWidget.changeEvent(self, e)

    def retranslate(self, all=True):
        """For dynamic retranslation of the plugin text strings
        """

        self.retranslateUi(self)
Esempio n. 22
0
class MainWindow(QMainWindow, magazzino_ui.Ui_MainWindow):

    FIRST, PREV, NEXT, LAST = range(4)
    Clipboard = [] # lista di oggetti

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

        self.setupUi(self)
        self.setupMenu()
        self.restoreWinSettings()

        self.editindex = None
        self.filename = None
        self.db = QSqlDatabase.addDatabase("QSQLITE")

        self.loadInitialFile()
        self.setupUiSignals()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Down:
            self.addDettRecord()
        else:
            QMainWindow.keyPressEvent(self, event)

    def creaStrutturaDB(self):
        query = QSqlQuery()
        if not ("magamaster" in self.db.tables()):
            if not query.exec_("""CREATE TABLE magamaster (
                                id INTEGER PRIMARY KEY AUTOINCREMENT 
                                UNIQUE NOT NULL,
                                scaff VARCHAR(10) NOT NULL)"""):
                QMessageBox.warning(self, "Magazzino",
                                QString("Creazione tabella fallita!"))
                return False

        if not ("magaslave" in self.db.tables()):
            if not query.exec_("""CREATE TABLE magaslave (
                                id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                                datains DATE NOT NULL,
                                abbi VARCHAR(50),
                                angro VARCHAR(50),
                                desc VARCHAR(100),
                                qt INTEGER NOT NULL DEFAULT '1',
                                imp DOUBLE NOT NULL DEFAULT '0.0',
                                equiv VARCHAR(100),
                                mmid INTEGER NOT NULL,
                                fatt VARCHAR(50),
                                note VARCHAR(200),
                                FOREIGN KEY (mmid) REFERENCES magamaster)"""):
                QMessageBox.warning(self, "Magazzino",
                                QString("Creazione tabella fallita!"))
                return False
            QMessageBox.information(self, "Magazzino",
                                QString("Database Creato!"))

        return True

    def loadFile(self, fname=None):
        if fname is None:
            return
        if self.db.isOpen():
            self.db.close()
        self.db.setDatabaseName(QString(fname))
        if not self.db.open():
            QMessageBox.warning(self, "Magazzino",
                                QString("Database Error: %1")
                                .arg(self.db.lastError().text()))
        else:
            if not self.creaStrutturaDB():
                return
            self.filename = unicode(fname)
            self.setWindowTitle("Gestione Magazzino - %s" % self.filename)
            self.setupModels()
            self.setupMappers()
            self.setupTables()
            #self.setupItmSignals()
            self.restoreTablesSettings()
            self.mmUpdate()


    def loadInitialFile(self):
        settings = QSettings()
        fname = unicode(settings.value("Settings/lastFile").toString())
        if fname and QFile.exists(fname):
            self.loadFile(fname)


    def openFile(self):
        dir = os.path.dirname(self.filename) \
                if self.filename is not None else "."
        fname = QFileDialog.getOpenFileName(self,
                    "Gestione Magazzino - Scegli database",
                    dir, "*.db")
        if fname:
            self.loadFile(fname)


    def newFile(self):
        dir = os.path.dirname(self.filename) \
                if self.filename is not None else "."
        fname = QFileDialog.getSaveFileName(self,
                    "Gestione Magazzino - Scegli database",
                    dir, "*.db")
        if fname:
            self.loadFile(fname)

    def setupMenu(self):
        # AboutBox
        self.connect(self.actionA_bout, SIGNAL("triggered()"),
                    self.showAboutBox)
        # FileNew
        self.connect(self.action_New_File, SIGNAL("triggered()"),
                    self.newFile)

        # FileLoad
        self.connect(self.action_Load_File, SIGNAL("triggered()"),
                    self.openFile)


    def showAboutBox(self):
        dlg = aboutmaga.AboutBox(self)
        dlg.exec_()


    def printInventory(self):
        '''
            Print Inventory
        '''
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        querygrp = QSqlQuery()
        querydett = QSqlQuery()

        querygrp.exec_("SELECT abbi,qt,imp,sum(qt*imp) "
                    "FROM magaslave GROUP BY abbi")
        querydett.prepare("SELECT datains,abbi,angro,desc,qt,imp "
                        "FROM magaslave WHERE abbi = :abbi AND "
                        "qt > 0 ORDER BY datains")

        from reportlab.pdfgen.canvas import Canvas
        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
        from reportlab.lib.units import cm
        from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER
        from reportlab.platypus import Spacer, SimpleDocTemplate 
        from reportlab.platypus import Table, TableStyle, Paragraph
        from reportlab.rl_config import defaultPageSize
        from reportlab.lib import colors

        PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize
        styles = getSampleStyleSheet()
        styleN = styles['Normal']
        styleH = styles['Heading1']
        styleH.alignment=TA_CENTER
        Elements = []
        #add some flowables
        p=Paragraph
        ps=ParagraphStyle

        Title = unicode(self.prtTitleLineEdit.text())
        Year = unicode(self.prtDateLineEdit.text())
        Author = "Stefano Zamprogno"
        URL = "http://www.zamprogno.it/"
        email = "*****@*****.**"

        pageinfo = "%s / %s / %s" % (Author, email, Title)

        def myFirstPage(canvas, doc):
            canvas.saveState()
            canvas.setStrokeColorRGB(0.50,0.50,0.50)
            canvas.setLineWidth(10)
            canvas.line(45,72,45,PAGE_HEIGHT-72)
            #canvas.setFont('Times-Bold',16)
            #canvas.drawCentredString(3*cm, 1.5*cm,Title)
            canvas.setFont('Times-Roman',9)
            canvas.drawString(3*cm, 1.5*cm, "First Page / %s" % pageinfo)
            canvas.restoreState()

        def myLaterPages(canvas, doc):
            canvas.saveState()
            canvas.setStrokeColorRGB(0.50,0.50,0.50)
            canvas.setLineWidth(5)
            canvas.line(45,72,45,PAGE_HEIGHT-72)
            canvas.setFont('Times-Roman',9)
            canvas.drawString(3*cm, 1.5*cm, "Page %d %s" % (doc.page, pageinfo))
            canvas.restoreState()

        Elements.append(Paragraph(Title, styleH))
        Elements.append(Paragraph(Year,styleN))
        Elements.append(Spacer(0.5*cm, 0.5*cm))

        tot=0
        while querygrp.next():
            tot += querygrp.value(3).toDouble()[0]
            querydett.bindValue(":abbi", QVariant(querygrp.value(0).toString()))
            querydett.exec_()
            data = [['Abbi', 'Angro', 'Descrizione', 'Qt', 'Imp'],]
            while querydett.next():
                data.append([ p(unicode(querydett.value(1).toString()),
                                                ps(name='Normal')),
                                p(unicode(querydett.value(2).toString()),
                                                ps(name='Normal')),
                                p(unicode(querydett.value(3).toString()),
                                                ps(name='Normal')),
                                querydett.value(4).toInt()[0],
                                unicode("%.2f" %
                                        querydett.value(5).toDouble()[0])])
            data.append([None, None,
                        unicode("GRUPPO '%s'" % querygrp.value(0).toString()),
                        unicode("Subtotale:"),
                        unicode("€ %.2f" % querygrp.value(3).toDouble()[0])])
            Elements.append(Table(data,repeatRows=1,
                                style=(['LINEBELOW', (3,-2), (-1,-2),
                                            1, colors.black],
                                        ['LINEBELOW', (0,0), (-1,0),
                                            1, colors.black],
                                        ['ALIGN', (1,0), (3,-1),'CENTER'],
                                        ['ALIGN', (4,0), (-1,0),'RIGHT'],
                                        ['VALIGN', (0,0), (-1,-1), 'TOP'],
                                        ['ALIGN', (4,0), (-1,-1), 'RIGHT'],
#                                        ['TEXTCOLOR', (0,0), (-1,0),
#                                                colors.red],
                                        ['BACKGROUND',(0,0),(-1,0),
                                                colors.lightgrey],
                                        ['GRID',(0,0),(-1,-1), 0.2,
                                                colors.black],
                                        ['FONT', (0, 0), (-1, 0),
                                                'Helvetica-Bold', 10],
                                        ['FONT', (3, -1), (3, -1),
                                                'Helvetica-Bold', 10])))
            Elements.append(Spacer(0.5*cm, 0.5*cm))

        Elements.append(Paragraph("<para align=right><b>TOTALE GENERALE:"
                                    "€ %.2f</b></para>" % tot, styleN))

        doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__),
                        'mydoc.pdf'))
        doc.build(Elements,onFirstPage=myFirstPage, onLaterPages=myLaterPages)

        subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__),
                        'mydoc.pdf')])

    def setupMappers(self):
        '''
            Initialize all the application mappers
        '''
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setModel(self.mModel)
        self.mapper.addMapping(self.scaffLineEdit, SCAFF)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.toFirst()

    def setupTables(self):
        """
            Initialize all the application tablesview
        """
        self.sTableView.setModel(self.sModel)
        self.sTableView.setItemDelegate(MSDelegate(self))
        self.sTableView.setColumnHidden(ID, True)
        self.sTableView.setColumnHidden(MMID, True)
        self.sTableView.setWordWrap(True)
        self.sTableView.resizeRowsToContents()
        self.sTableView.setAlternatingRowColors(True)
        self.sItmSelModel = QItemSelectionModel(self.sModel)
        self.sTableView.setSelectionModel(self.sItmSelModel)
        self.sTableView.setSelectionBehavior(QTableView.SelectRows)
        #self.sTableView.setTabKeyNavigation(True)


        self.fTableView.setModel(self.fModel)
        self.fTableView.setColumnHidden(ID, True)
        self.fTableView.setWordWrap(True)
        self.fTableView.resizeRowsToContents()
        self.fTableView.setAlternatingRowColors(True)
        self.fItmSelModel = QItemSelectionModel(self.fModel)
        self.fTableView.setSelectionModel(self.fItmSelModel)

    def setupModels(self):
        """
            Initialize all the application models
        """
        # setup slaveModel
        self.sModel = ssModel(self)
        self.sModel.setTable(QString("magaslave"))
        self.sModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID"))
        self.sModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns"))
        self.sModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi"))
        self.sModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro"))
        self.sModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc"))
        self.sModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt"))
        self.sModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp"))
        self.sModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv"))
        self.sModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId"))
        self.sModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt"))
        self.sModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note"))
        self.sModel.setSort(DATAINS, Qt.AscendingOrder)
        self.sModel.setEditStrategy(QSqlTableModel.OnRowChange)
        self.sModel.select()

        # setup masterModel
        self.mModel = QSqlTableModel(self)
        self.mModel.setTable(QString("magamaster"))
        self.mModel.setSort(SCAFF, Qt.AscendingOrder)
        self.mModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID"))
        self.mModel.setHeaderData(SCAFF, Qt.Horizontal, QVariant("Scaff"))
        self.mModel.select()

        # setup findModel
        self.fModel = QSqlRelationalTableModel(self)
        self.fModel.setTable(QString("magaslave"))
        self.fModel.setHeaderData(ID, Qt.Horizontal, QVariant("ID"))
        self.fModel.setHeaderData(DATAINS, Qt.Horizontal, QVariant("DataIns"))
        self.fModel.setHeaderData(ABBI, Qt.Horizontal, QVariant("Abbi"))
        self.fModel.setHeaderData(ANGRO, Qt.Horizontal, QVariant("Angro"))
        self.fModel.setHeaderData(DESC, Qt.Horizontal, QVariant("Desc"))
        self.fModel.setHeaderData(QT, Qt.Horizontal, QVariant("Qt"))
        self.fModel.setHeaderData(IMP, Qt.Horizontal, QVariant("Imp"))
        self.fModel.setHeaderData(EQUIV, Qt.Horizontal, QVariant("Equiv"))
        self.fModel.setHeaderData(MMID, Qt.Horizontal, QVariant("ScaffId"))
        self.fModel.setHeaderData(FATT, Qt.Horizontal, QVariant("Fatt"))
        self.fModel.setHeaderData(NOTE, Qt.Horizontal, QVariant("Note"))
        self.fModel.setSort(MMID, Qt.AscendingOrder)
        self.fModel.setRelation(MMID, QSqlRelation("magamaster",
                                            "id", "scaff"))
        self.fModel.select()

    def clipCopy(self):
        self.Clipboard = self.sTableView.selectedIndexes()
        selrows = self.sItmSelModel.selectedRows()
        # TODO : da usare:  selrows = self.sItmSelModel.selectedRows()
        print(selrows, len(selrows))
        print(len(self.Clipboard))
        # FIXME : bla bla bla

    def clipDel(self):
        self.delDettRecord()

    def clipPaste(self):
        pass

    def ctxtMenu(self, point):
        menu = QMenu(self)
        copyAction = menu.addAction("&Copy")
        self.connect(copyAction, SIGNAL("triggered()"), self.clipCopy)
        delAction = menu.addAction("&Del")
        self.connect(delAction, SIGNAL("triggered()"), self.clipDel)
        if len(self.Clipboard) > 0:
            pasteAction = menu.addAction("&Paste")
            self.connect(pasteAction, SIGNAL("triggered()"), self.clipPaste)

        menu.exec_(self.sTableView.mapToGlobal(point))


    def setupUiSignals(self):
        self.sTableView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.sTableView,  SIGNAL(
                        "customContextMenuRequested(const QPoint &)"),
                        self.ctxtMenu)
        self.connect(self.scaffLineEdit, SIGNAL("returnPressed()"),
                    lambda: self.saveRecord(MainWindow.FIRST))
        self.connect(self.findLineEdit, SIGNAL("returnPressed()"),
                    self.globalFilter)
        self.connect(self.printPushButton, SIGNAL("clicked()"),
                    self.printInventory)
        self.connect(self.createFilterPushButton, SIGNAL("clicked()"),
                    self.createFilter)
        self.connect(self.findPushButton, SIGNAL("clicked()"),
                    self.applyFilter)
        self.connect(self.gSearchPushButton, SIGNAL("clicked()"),
                    self.globalFilter)
        self.connect(self.addscaffPushButton, SIGNAL("clicked()"),
                    self.addScaffRecord)
        self.connect(self.adddettPushButton, SIGNAL("clicked()"),
                    self.addDettRecord)
        self.connect(self.deldettPushButton, SIGNAL("clicked()"),
                    self.delDettRecord)
        self.connect(self.delscaffPushButton, SIGNAL("clicked()"),
                    self.delScaffRecord)
        self.connect(self.scaffFirstPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.FIRST))
        self.connect(self.scaffPrevPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.PREV))
        self.connect(self.scaffNextPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.NEXT))
        self.connect(self.scaffLastPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.LAST))


    def globalFilter(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        txt = self.findLineEdit.text()
        qry =   ("(datains like '%s') OR "
                "(abbi like '%s') OR "
                "(angro like '%s') OR "
                "(desc like '%s') OR "
                "(equiv like '%s') OR"
                "(fatt like '%s') OR"
                "(note like '%s')") % ((txt,)*7)
        self.fModel.setFilter(qry)
        self.updateFilter()

    def updateFilter(self):
        self.fModel.select()
        self.fTableView.setColumnHidden(ID, True)

    def applyFilter(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        self.fModel.setFilter(self.findLineEdit.text())
        self.updateFilter()

    def createFilter(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        headerDef = ("datains VARCHAR(100)",
                            "abbi VARCHAR(100)",
                            "angro VARCHAR(100)",
                            "desc VARCHAR(100)",
                            "qt VARCHAR(100)",
                            "imp VARCHAR(100)",
                            "equiv VARCHAR(100)",
                            "fatt VARCHAR(100)",
                            "note VARCHAR(100)")
        dlg = filterdialog.FilterDialog(headerDef,
                        QSqlDatabase.database(), self)
        if(dlg.exec_()):
            self.findLineEdit.setText(dlg.filterDone() 
                                        if dlg.filterDone() else "")
            self.applyFilter()

    #~ def editEsc(self, idxcur, idxold):
        #~ if self.editindex and self.editindex.isValid():
            #~ if idxcur.row() != self.editindex.row():
                #~ self.sModel.revertAll()
                #~ self.editindex = None

    def mmUpdate(self):
        row = self.mapper.currentIndex()
        id = self.mModel.data(self.mModel.index(row,ID)).toString()
        self.sModel.setFilter("mmid=%s" % id)
        self.sModel.select()
        self.sTableView.setColumnHidden(ID, True)
        self.sTableView.setColumnHidden(MMID, True)

    def saveRecord(self, where):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mapper.currentIndex()
        self.mapper.submit()
        self.sModel.revertAll()
        if where == MainWindow.FIRST:
            row=0
        elif where == MainWindow.PREV:
            row = 0 if row <= 1 else row - 1
        elif where == MainWindow.NEXT:
            row += 1
            if row >= self.mModel.rowCount():
                row = self.mModel.rowCount() -1
        elif where == MainWindow.LAST:
            row = self.mModel.rowCount()- 1
        self.mapper.setCurrentIndex(row)
        self.mmUpdate()

    def addScaffRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mModel.rowCount()
        self.mapper.submit()
        self.mModel.insertRow(row)
        self.mapper.setCurrentIndex(row)
        self.scaffLineEdit.setFocus()
        self.mmUpdate()

    def addDettRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        rowscaff = self.mapper.currentIndex()
        record = self.mModel.record(rowscaff)
        masterid = record.value(ID).toInt()[0]
        if masterid < 1:
            self.statusbar.showMessage(
                "Scaffale non valido o non confermato...",
                5000)
            self.scaffLineEdit.setFocus()
            return
        # aggiunge la nuova riga alla vista
        self.sModel.submitAll()
        self.sModel.select()
        row = self.sModel.rowCount()
        self.sModel.insertRow(row)
        if row > 1:
            precfatt = self.sModel.data(self.sModel.index(row-1, FATT))
        else:
            precfatt = ''
        if row > 1:
            lastData = self.sModel.data(self.sModel.index(row-1, DATAINS))
        else:
            lastData = ''
        self.sModel.setData(self.sModel.index(row, MMID),
                                                QVariant(masterid))
        self.sModel.setData(self.sModel.index(row, QT),
                                                QVariant(1))
        self.sModel.setData(self.sModel.index(row, IMP),
                                                QVariant(0.0))
        self.sModel.setData(self.sModel.index(row, FATT),
                                                QVariant(precfatt))
        self.editindex = self.sModel.index(row, DATAINS)
        self.sTableView.setCurrentIndex(self.editindex)
        self.sTableView.edit(self.editindex)

    def delDettRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        selrows = self.sItmSelModel.selectedRows()
        if not selrows:
            self.statusbar.showMessage(
                "No articles selected to delete...",
                5000)
            return
        if(QMessageBox.question(self, "Cancella Articoli",
                "Vuoi cancellare: {0} articoli?".format(len(selrows)),
                QMessageBox.Yes|QMessageBox.No) ==
                QMessageBox.No):
            return
        QSqlDatabase.database().transaction()
        query = QSqlQuery()
        query.prepare("DELETE FROM magaslave WHERE id = :val")
        for i in selrows:
            if i.isValid():
                query.bindValue(":val", QVariant(i.data().toInt()[0]))
                query.exec_()
        QSqlDatabase.database().commit()
        self.sModel.revertAll()
        self.mmUpdate()

    def delScaffRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mapper.currentIndex()
        if row == -1:
            self.statusbar.showMessage(
                        "Nulla da cancellare...",
                        5000)
            return
        record = self.mModel.record(row)
        id = record.value(ID).toInt()[0]
        scaff = record.value(SCAFF).toString()
        if(QMessageBox.question(self, "Cancella Scaffale",
                    "Vuoi cancellare lo scaffale: {0} ?".format(scaff),
                    QMessageBox.Yes|QMessageBox.No) ==
                    QMessageBox.No):
            self.statusbar.showMessage(
                        "Cancellazione scaffale annullata...",
                        5000)
            return
        # cancella scaffale
        self.mModel.removeRow(row)
        self.mModel.submitAll()
        if row + 1 >= self.mModel.rowCount():
            row = self.mModel.rowCount() - 1
        self.mapper.setCurrentIndex(row)
        if self.mModel.rowCount() == 0:
            self.scaffLineEdit.setText(QString(""))

        # cancella tutti gli articoli che si riferiscono
        # allo scaffale cancellato
        self.sModel.setFilter("mmid=%s" % id)
        self.sModel.select()
        self.sModel.removeRows(0, self.sModel.rowCount())
        self.sModel.submitAll()
        self.statusbar.showMessage(
                        "Cancellazione eseguita...",
                        5000)
        self.mmUpdate()

    def restoreTablesSettings(self):
        settings = QSettings(self)
        if self.saveTableGeometryCheckBox.isChecked():
            # per la tabella slave
            for c in range(1, self.sModel.columnCount()-1):
                width = settings.value("Settings/sTableView/%s" % c,
                                        QVariant(60)).toInt()[0]
                self.sTableView.setColumnWidth(c,
                                            width if width > 0 else 60)

            # per la tabella find
            for c in range(1, self.fModel.columnCount()):
                width = settings.value("Settings/fTableView/%s" % c,
                                        QVariant(60)).toInt()[0]
                self.fTableView.setColumnWidth(c,
                                            width if width > 0 else 60)

    def restoreWinSettings(self):
        settings = QSettings()
        self.prtTitleLineEdit.setText(QString(settings.value(
                            "Settings/printTitle", QVariant(
                            "Situazione Magazzino - TIME di Stefano Zamprogno")).toString()))
        self.prtDateLineEdit.setText(QString(settings.value(
                            "Settings/printDate", QVariant(
                            "Al 31/12/2008")).toString()))
        self.saveWinPosCheckBox.setChecked(
                settings.value("Settings/saveWinPos", QVariant(True)).toBool())
        self.saveTableGeometryCheckBox.setChecked(
                settings.value("Settings/saveTableGeometry",
                QVariant(True)).toBool())
        self.restoreGeometry(
                settings.value("MainWindow/Geometry").toByteArray())

    def closeEvent(self, event):
        settings = QSettings()
        if self.filename is not None:
            settings.setValue("Settings/lastFile", QVariant(self.filename))
        settings.setValue("MainWindow/Geometry", QVariant(
                          self.saveGeometry()))
        settings.setValue("Settings/saveWinPos", QVariant(
                          self.saveWinPosCheckBox.isChecked()))
        settings.setValue("Settings/saveTableGeometry", QVariant(
                          self.saveTableGeometryCheckBox.isChecked()))
        settings.setValue("Settings/printTitle", QVariant(
                          self.prtTitleLineEdit.text()))
        settings.setValue("Settings/printDate", QVariant(
                          self.prtDateLineEdit.text()))

        if self.db.isOpen():
            # salva larghezza colonne tabella slave
            for c in range(1, self.sModel.columnCount()-1):
                width = self.sTableView.columnWidth(c)
                if width:
                    settings.setValue("Settings/sTableView/%s" % c,
                                        QVariant(width))

            # salva larghezza colonne tabella find
            for c in range(1, self.fModel.columnCount()):
                width = self.fTableView.columnWidth(c)
                if width:
                    settings.setValue("Settings/fTableView/%s" % c,
                        QVariant(width))
        self.db.close()
        del self.db
Esempio n. 23
0
class MclRecordEditor(object):
    """
    Handles forms and database connections for editing RAMP features.
    """
    edit_linked_polys_tool = None
    original_linked_polys = None
    mcl_ref = None
    dlg = None
    model = None
    mapper = None

    def __init__(self, db, selector_tool, iface):
        self.db = db
        self.selector_tool = selector_tool
        self.iface = iface
        self.prepare_dialog()
        self.connect_signals()

    def prepare_dialog(self):
        """
        Prepare MCL edit dialog including setting comobox entries and
        validation.
        :return: RampMclEditorDlg
        """
        self.dlg = RampMclEditorDlg()
        self.dlg.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.dlg.move(5, 5)
        self.set_combobox_items()
        self.set_dialog_validators()

    def set_combobox_items(self):
        """
        Populate the items in the comboboxes.
        """
        self.dlg.ui.streetClassComboBox.addItems([''] + STREET_CLASS_VALUES)
        self.dlg.ui.laneNumberComboBox.addItems([''] + LANE_NUMBER_VALUES)
        self.dlg.ui.carriagewayComboBox.addItems([''] + CARRIAGEWAY_VALUES)
        self.dlg.ui.ruralUrbanComboBox.addItems([''] + RURAL_URBAN_VALUES)
        self.dlg.ui.speedLimitComboBox.addItems([''] + SPEED_LIMIT_VALUES)
        self.dlg.ui.sectionTypeComboBox.addItems([''] + SECTION_TYPE_VALUES)

    def set_dialog_validators(self):
        """
        Add validators to the free-text fields of the dialog.
        """
        # These widgets are 'free-text'
        self.dlg.ui.usrnLineEdit.setValidator(
            QRegExpValidator(QRegExp(r"\d{0,8}")))
        self.dlg.ui.ref1LineEdit.setValidator(
            QRegExpValidator(QRegExp(r"[ABCUFTMZ]{1,2}-?\d{0,}")))
        self.dlg.ui.ref2LineEdit.setValidator(
            QRegExpValidator(QRegExp(r"\d{0,}")))

        # There isn't length validation for plain text edit, so implement our own
        self.dlg.ui.sectionDescriptionPlainTextEdit.textChanged.connect(
            self.trim_section_description)

    def trim_section_description(self):
        """
        Trim text in street section description to within 150 characters.
        """
        editor = self.dlg.ui.sectionDescriptionPlainTextEdit
        text = editor.toPlainText()
        if len(text) > 150:
            text = text[:150]
            editor.setPlainText(text)
            editor.moveCursor(QTextCursor.End)

    def connect_signals(self):
        """
        Connect GUI signals and slots.  Extends parent class function
        """
        # GUI controls
        self.selector_tool.selected_id.connect(self.select_record)
        save_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Save)
        cancel_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Cancel)
        save_button.clicked.connect(self.save_record)
        cancel_button.clicked.connect(self.close_tool)
        self.dlg.rejected.connect(self.close_tool)
        self.dlg.ui.editLinksPushButton.clicked.connect(
            self.launch_edit_linked_polys_tool)

        # Auto updates on combined ref line edit
        self.dlg.ui.ref1LineEdit.textChanged.connect(self.update_combined_ref)
        self.dlg.ui.ref2LineEdit.textChanged.connect(self.update_combined_ref)

    def select_record(self, mcl_ref):
        """
        Update the GUI to populate with data from the chosen record.  Show if
        not already visible.
        :param mcl_ref: int, emitted by selector_tool
        """
        self.mcl_ref = mcl_ref
        self.setup_model_and_mapper(mcl_ref)
        self.populate_length_lineedit(mcl_ref)
        self.original_linked_polys = self.get_linked_polys_in_db(mcl_ref)
        self.set_linked_poly_box_items(self.original_linked_polys)

        if not self.dlg.isVisible():
            self.dlg.show()

    def launch_edit_linked_polys_tool(self):
        """
        Create new instance of edit linked polys tool for current record
        """
        linked_polys = self.get_items_from_linked_poly_box()
        self.edit_linked_polys_tool = EditLinkedPolysTool(
            linked_polys, self.iface, self.dlg)
        self.edit_linked_polys_tool.linked_polys_updated.connect(
            self.set_linked_poly_box_items)
        self.edit_linked_polys_tool.launch()

    def close_tool(self):
        """
        Close the dialog, reverting unsaved changes.
        """
        self.mapper.revert()
        self.dlg.hide()

    def save_record(self):
        """
        Save changes to the record, then close dialog.
        """
        self.mapper.submit()
        self.update_db_linked_polys()
        self.iface.mapCanvas().refresh()
        self.dlg.hide()

    def setup_model_and_mapper(self, mcl_ref):
        """
        Load the table data for selected record into a model and map to widgets.
        """
        # Set up model
        self.model = QSqlTableModel(db=self.db)
        self.model.setTable('mcl')
        self.model.setFilter("mcl_ref = {}".format(int(mcl_ref)))
        self.model.select()
        if self.model.rowCount() != 1:
            msg = "MCL query for mcl_ref = {} returned {} rows".format(
                mcl_ref, self.model.rowCount())
            raise rn_except.MclFormBadMclRefError(msg)

        # Set up mapper
        self.mapper = QDataWidgetMapper()
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.model)
        self.mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF)
        self.mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN)
        self.mapper.addMapping(self.dlg.ui.streetClassComboBox, STREET_CLASS)
        self.mapper.addMapping(self.dlg.ui.ref1LineEdit, LOR_REF_1)
        self.mapper.addMapping(self.dlg.ui.ref2LineEdit, LOR_REF_2)
        self.mapper.addMapping(self.dlg.ui.laneNumberComboBox, LANE_NUMBER)
        self.mapper.addMapping(self.dlg.ui.carriagewayComboBox, CARRIAGEWAY)
        self.mapper.addMapping(self.dlg.ui.ruralUrbanComboBox, RURAL_URBAN_ID)
        self.mapper.addMapping(self.dlg.ui.speedLimitComboBox, SPEED_LIMIT)
        self.mapper.addMapping(self.dlg.ui.sectionTypeComboBox, SECTION_TYPE)
        self.mapper.addMapping(self.dlg.ui.sectionDescriptionPlainTextEdit,
                               LOR_DESC)
        self.mapper.setItemDelegate(MclEditorDelegate(self.dlg))
        self.mapper.toFirst()

    def update_combined_ref(self):
        """
        Update combinedRefLineEdit with value derived from other fields.
        """
        ref1 = self.dlg.ui.ref1LineEdit.text()
        ref2 = self.dlg.ui.ref2LineEdit.text()
        new_text = "{}/{}".format(ref1, ref2)

        self.dlg.ui.combinedRefLineEdit.setText(new_text)

    def populate_length_lineedit(self, mcl_ref):
        """
        Calculate the length of the MCL and populate lineedit with data.
        :param mcl_ref: int, id of the MCL to calculate
        """
        # Don't do calculation if spatialite version is too low. (libgeos bug)
        if lor.get_spatialite_version_as_int(self.db) < 430:
            length_text = "Spatialite < 4.3.0"
            self.dlg.ui.lengthLineEdit.setText(length_text)
            return

        # Run query
        sql = """
            SELECT GLength(geometry) AS length FROM mcl
            WHERE mcl_ref = {}
            ;""".format(mcl_ref)
        query = QSqlQuery(sql, self.db)

        # Raise exception if query fails
        if not query.first():
            msg = ("Could not calculate MCL length.  Query:\n{}\n"
                   "Database returned:\n{}".format(sql,
                                                   query.lastError().text()))
            raise rn_except.MclFormLengthCalculationError(msg)

        # Update field
        length = query.record().value('length')
        length_text = "{:.2f}".format(length)
        self.dlg.ui.lengthLineEdit.setText(length_text)

    def update_db_linked_polys(self):
        """
        Update the database with changes to linked polygons.
        """
        linked_polys = self.get_items_from_linked_poly_box()

        # Clear links for polygons that have been removed
        for polygon in self.original_linked_polys:
            if polygon not in linked_polys:
                self.clear_rdpoly_mcl_fields(polygon)

        # Create links for polygons that have been added.
        for polygon in linked_polys:
            if polygon not in self.original_linked_polys:
                self.clear_rdpoly_mcl_fields(polygon)
                self.set_rdpoly_mcl_links_in_db(polygon, self.mcl_ref)

    def get_items_from_linked_poly_box(self):
        """
        Get the values from the Linked Polygons box
        :return: list of strings
        """
        poly_box = self.dlg.ui.linkedPolygonsListWidget
        items = []
        for i in range(poly_box.count()):
            items.append(poly_box.item(i).data(Qt.DisplayRole))
        return items

    def set_linked_poly_box_items(self, items):
        """
        Populate the Linked Polygons box with items
        :param items: list of strings
        """
        # Cannot link already linked polygon
        try:
            self.validate_polygon_links(items)
        except rn_except.RampRdPolyAlreadyLinkedPopupError:
            # Don't update if polygons already have links to other MCLs
            return

        poly_box = self.dlg.ui.linkedPolygonsListWidget
        poly_box.clear()
        poly_box.addItems(items)

    def validate_polygon_links(self, linked_polys):
        """
        Raise exception if any polygons have link to other MCLs.
        """
        already_linked = []
        for rd_pol_id in linked_polys:
            linked_mcl_cref = self.get_mcl_cref(rd_pol_id)

            if linked_mcl_cref == str(self.mcl_ref):
                # OK if linked to current MCL
                continue
            elif linked_mcl_cref in ('', 'NULL', 'Null'):
                # Null is OK
                continue
            else:
                # Otherwise already linked to other polygon
                already_linked.append(rd_pol_id)

        if already_linked:
            msg = "Cannot update links.  The following polygons are already linked"
            msg += " to other MCLs.\n\n"
            msg += ", ".join(already_linked)
            raise rn_except.RampRdPolyAlreadyLinkedPopupError(msg)

    def get_mcl_cref(self, rd_pol_id):
        """
        Get the MCL ref attached to given polygon
        :param rd_pol_id:
        :return: str, mcl_cref
        """
        sql = """
            SELECT mcl_cref FROM rdpoly
            WHERE rd_pol_id = '{}'
            ;""".format(rd_pol_id)
        query = QSqlQuery(sql, self.db)

        if not query.isActive():
            msg = "Invalid rd_pol_id:"
            msg += "\n\nSQL command:\n\n{}".format(sql)
            msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text())
            raise rn_except.RampRdPolyUpdateFailedPopupError(msg)

        query.first()
        mcl_ref = str(query.record().value('mcl_cref'))

        return mcl_ref

    def get_linked_polys_in_db(self, mcl_ref):
        """
        Get the polygons that have current mcl_ref
        :param mcl_ref: str with reference
        :return: list of strings
        """
        sql = """
            SELECT rd_pol_id FROM rdpoly
            WHERE mcl_cref = {}
            ;""".format(mcl_ref)
        query = QSqlQuery(sql, self.db)

        linked_polys = []
        while query.next():
            record = query.record()
            rd_pol_id = str(record.value('rd_pol_id'))
            linked_polys.append(rd_pol_id)

        return linked_polys

    def set_rdpoly_mcl_links_in_db(self, rd_pol_id, mcl_ref):
        """
        Update the fields of the rdpoly table with values for the given
        mcl_ref from the mcl table.
        :param rd_pol_id: str, rd_pol_id to update
        :param mcl_ref: str, mcl_ref to supply values
        """
        if config.DEBUG_MODE:
            print(
                "DEBUG_MODE: Updating rdpoly {} with data from mcl {}".format(
                    rd_pol_id, mcl_ref))

        # Get update values
        mcl_attrs = self.get_mcl_attrs_for_rdpoly(mcl_ref)
        mcl_attrs['mcl_ref'] = mcl_ref
        mcl_attrs['rd_pol_id'] = rd_pol_id

        # Update database
        sql = """
            UPDATE rdpoly SET part_label = "{part_label}",
                 mcl_cref = {mcl_cref}
            WHERE rd_pol_id = {rd_pol_id}
            ;""".format(**mcl_attrs)
        if config.DEBUG_MODE:
            print(sql)
        query = QSqlQuery(sql, self.db)

        if not query.isActive():
            msg = "Failed to update rdpoly with mcl data."
            msg += "\n\nSQL command:\n\n{}".format(sql)
            msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text())
            raise rn_except.RampRdPolyUpdateFailedPopupError(msg)

    def clear_rdpoly_mcl_fields(self, rd_pol_id):
        """
        Clear values in rdpoly that were derived from linked MCL.  Used when
        MCL is unlinked.
        :param rd_pol_id: str, rd_pol_id
        """
        sql = """
            UPDATE rdpoly SET
                element = NULL, hierarchy = NULL,
                ref_1 = NULL, ref_2 = NULL, ref_3 = NULL,
                desc_1 = NULL, desc_2 = NULL, desc_3 = NULL,
                part_label = NULL, label = NULL, label1 = NULL,
                feature_length = NULL, r_usrn = NULL, mcl_cref = NULL
            WHERE rd_pol_id = {}
            ;""".format(rd_pol_id)
        if config.DEBUG_MODE:
            print(sql)
        query = QSqlQuery(sql, self.db)

        if not query.isActive():
            msg = "Problem updating rdpoly with mcl data."
            msg += "\n\nSQL command:\n\n{}".format(sql)
            msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text())
            raise rn_except.RampRdPolyUpdateFailedPopupError(msg)

    def get_mcl_attrs_for_rdpoly(self, mcl_ref):
        """
        Get values from database and prepare attributes to insert into rdpoly
        table.
        :param mcl_ref: str, mcl_ref
        :return: dict, mcl_attributes
        """
        sql = """
            SELECT lor_ref_1 || "/" || lor_ref_2 AS part_label
            FROM mcl WHERE mcl_ref={};""".format(mcl_ref)
        query = QSqlQuery(sql, self.db)

        if not query.isActive():
            msg = "Failed to get MCL attributes."
            msg += "\n\nSQL command:\n\n{}".format(sql)
            msg += "\n\nDatabase reply:\n\n{}".format(query.lastError().text())
            raise rn_except.RampRdPolyUpdateFailedPopupError(msg)

        query.first()
        part_label = query.record().value("part_label")
        mcl_attrs = {'mcl_cref': mcl_ref, 'part_label': part_label}

        return mcl_attrs
Esempio n. 24
0
class TemplateWidget(QWidget, Ui_TemplateWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.setupUi(self)
        self.setObjectName('TemplatePlugin')
        self._serverList = ServerList()

        templateList = TemplateList()
        self._templateList = copy.deepcopy(templateList)
        self._templateListCopy = None
        self._returnList = None

        #ObjectclassAttributeInfo
        self.preloadedServerMeta = {}

        self.templateTM = TemplateTableModel(self._templateList, self)
        self.listViewTemplates.setModel(self.templateTM)

        self.objectclassTM = ObjectclassTableModel(self)
        self.listViewObjectclasses.setModel(self.objectclassTM)

        self.attributeTM = AttributeTableModel(self)
        self.tableViewAttributes.setModel(self.attributeTM)

        # Enable/disable editing depending on if we have a server to edit
        if self.templateTM.rowCount(QModelIndex()) > 0:
            self.setRightSideEnabled(True)
        else:
            self.setRightSideEnabled(False)
        # Select the first template in the model)
        index = self.templateTM.index(0,0)
        # Select the template in the view
        self.listViewTemplates.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect)
        self.listViewTemplates.selectionModel().selectionChanged.connect(self.selectedTemplate)
        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.templateTM)
        self.mapper.addMapping(self.lineEditDescription, 2)
        # Set-up of the non-mapped information
        self.selectedTemplate()

    def selectedTemplate(self):
        index = self.listViewTemplates.selectionModel().currentIndex().row()
        if index >= 0:
            self.mapper.setCurrentIndex(index)

            server = self._templateList._templateList[index].server
            self.labelServerName.setText(server)
            self.loadServerMeta(server)

            self.setObjectclasses()
            self.setAttributes()
            self.tableViewAttributes.resizeColumnsToContents()
            self.tableViewAttributes.resizeRowsToContents()

    def setObjectclasses(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.objectclassTM.setTemplateObject(templateObject)


    def setAttributes(self):
        templateObject = self.getSelectedTemplateObject()
        if templateObject:
            self.attributeTM.setTemplateObject(templateObject)

    def loadServerMeta(self, serverName):
        serverName = unicode(serverName)
        if not (serverName in self.preloadedServerMeta.keys()):
            serverMeta = self._serverList.getServerObject(serverName)
            self.preloadedServerMeta[serverName] = ObjectClassAttributeInfo(serverMeta)
        return self.preloadedServerMeta[serverName]

    def setRightSideEnabled(self, enabled):
        self.lineEditDescription.setEnabled(enabled)
        self.groupBoxObjectclasses.setEnabled(enabled)
        self.groupBoxAttributes.setEnabled(enabled)

    def clearAll(self):
        self.lineEditDescription.clear()
        self.labelServerName.clear()
        self.objectclassTM.setTemplateObject(None)
        self.attributeTM.setTemplateObject(None)

    def getSelectedTemplateObject(self):
        templateIndexes = self.listViewTemplates.selectedIndexes()
        if len(templateIndexes) > 0:
            return self._templateList.getTable()[templateIndexes[0].row()]
        return None

    def getSelectedObjectclass(self, index):
        return self.objectclassTM.getObjectclass(index)

    def getSelectedAttribute(self, index):
        return self.attributeTM.getAttribute(index)

    def addTemplate(self):
        dialog = AddTemplateDialog(self._serverList)
        if dialog.exec_():
            name = dialog.lineEditTemplateName.text()
            if len(name) < 1 or self._templateList.getTemplateObject(name) != None:
                QMessageBox.information(self, 'Error', "Invalid name or already used.")
                return
            server = dialog.comboBoxServer.currentText()
            if len(server) < 1:
                QMessageBox.information(self, 'Error', "Invalid server.")
                return
            description = dialog.lineEditDescription.text()
            tO = TemplateObject(name, server, description)

            m = self.templateTM
            m.beginInsertRows(QModelIndex(), m.rowCount(), m.rowCount())
            m.insertRow(tO)
            m.endInsertRows()

            i = m.index(m.rowCount()-1,0)
            self.listViewTemplates.selectionModel().select(i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(i, QItemSelectionModel.ClearAndSelect) #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()
            if i.row() == 0:
                self.setRightSideEnabled(True)


    def deleteTemplate(self):
        if self.listViewTemplates.selectionModel().currentIndex().row() < 0:
            return

        re = QMessageBox.question(self, "Delete", "Are you sure?", QMessageBox.Yes, QMessageBox.No)

        if re == QMessageBox.Yes:
            index = self.listViewTemplates.selectedIndexes()[0] #Currently selected

            # Delete the template
            self.listViewTemplates.model().removeRow(index)

            # When deleting, the view gets updated and selects a new current.
            # Get it and give it to the mapper
            newIndex = self.listViewTemplates.selectionModel().currentIndex()
            self.mapper.setCurrentIndex(newIndex.row())

        # Disable editing if no templates left
        if self.templateTM.rowCount() == 0:
            self.setRightSideEnabled(False)
            self.clearAll()

    def duplicateTemplate(self):
        name, ok = QInputDialog.getText(self, 'Duplicate', 'Template name')
        if ok:
            if len(name) < 1 or self._templateList.getTemplateObject(name) != None:
                QMessageBox.information(self, 'Error', "Invalid name or already used.")
                return
            tO = copy.deepcopy(self.getSelectedTemplateObject())
            tO.templateName = name

            m = self.listViewTemplates.model()
            m.insertRow(tO)
            i = m.index(m.rowCount()-1,0)
            self.listViewTemplates.selectionModel().select(i, QItemSelectionModel.ClearAndSelect)
            self.listViewTemplates.selectionModel().setCurrentIndex(i, QItemSelectionModel.ClearAndSelect) #Mark it as current
            self.mapper.setCurrentIndex(i.row())
            self.selectedTemplate()

    def saveTemplate(self):
        self._templateList.save()

    def addObjectclass(self):
        server = self.labelServerName.text()
        dialog = AddObjectclassDialog(self.loadServerMeta(server), self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.listWidgetObjectclasses.selectedIndexes():
                item = dialog.listWidgetObjectclasses.itemFromIndex(i)
                self.objectclassTM.insertRow(str(item.text()))

        self.refreshMustAttributes()

    def deleteObjectclass(self):
        dOc = self.listViewObjectclasses.selectedIndexes()
        if dOc:
            server = self.labelServerName.text()
            tO = self.getSelectedTemplateObject()
            attributes = self.attributeTM.attributes
            dialog = DeleteObjectclassDialog(self.loadServerMeta(server), tO, dOc, attributes)
            if dialog.exec_():
                self.objectclassTM.removeRows(dOc)
                self.refreshAllAttributes()


    def refreshMustAttributes(self):
        tO = self.getSelectedTemplateObject()
        for attr in tO.attributes.values():
            if attr.must:
                self.attributeTM.removeAlways(attr)


        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        attributeNameList = ocai.getAllMusts(tO.objectclasses)
        for name in attributeNameList:
            single = ocai.isSingle(name)
            binary = ocai.isBinary(name)
            self.attributeTM.addRow(name, True, single, binary, "", False)

    def refreshAllAttributes(self):
        tO = self.getSelectedTemplateObject()
        server = self.labelServerName.text()
        ocai = self.loadServerMeta(server)
        must, may = ocai.getAllAttributes(tO.objectclasses)
        for attr in tO.attributes.items():
            if (not attr[0] in must) and (not attr[0] in may):
                self.attributeTM.removeAlways(attr[1])
            elif not attr[0] in must:
                attr[1].must = False

    def addAttribute(self):
        server = self.labelServerName.text()
        dialog = AddAttributeDialog(self.loadServerMeta(server), self.getSelectedTemplateObject())
        if dialog.exec_():
            for i in dialog.tableView.selectedIndexes():
                if(i.column() == 0):
                    a = dialog.attributeTM.getAttribute(i)
                    self.attributeTM.addRow(a.attributeName, a.must, a.single, a.binary, a.defaultValue, a.customMust)

        self.tableViewAttributes.resizeRowsToContents()
        self.tableViewAttributes.resizeColumnsToContents()

    def deleteAttributes(self):
        if len(self.tableViewAttributes.selectedIndexes()):
            re = QMessageBox.question(self, self.tr('Delete'),
                                      self.tr("Are you sure you want to delete the selected attributes?"), QMessageBox.Yes, QMessageBox.No)
            if re == QMessageBox.Yes:
                self.attributeTM.removeRows(self.tableViewAttributes.selectedIndexes())

    def changeEvent(self, e):
        """Overloaded so we can catch the LanguageChange event, and at
        translation support to the plugin
        """
        if e.type() == QtCore.QEvent.LanguageChange:
            self.retranslateUi(self)
        else:
            QWidget.changeEvent(self, e)

    def retranslate(self, all=True):
        """For dynamic retranslation of the plugin text strings
        """

        self.retranslateUi(self)
Esempio n. 25
0
class MainWindow(QMainWindow, fatture_ui.Ui_MainWindow):

    FIRST, PREV, NEXT, LAST = range(4)

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

        self.setupUi(self)
        self.setupMenu()
        self.restoreWinSettings()

        self.editindex = None
        self.filename = None
        self.db = QSqlDatabase.addDatabase("QSQLITE")

        self.loadInitialFile()
        self.setupUiSignals()

    def mmUpdate(self):
        row = self.mapper.currentIndex()
        id = self.mModel.data(self.mModel.index(row,MID)).toString()
        self.sModel.setFilter("mmid=%s" % id)
        self.sModel.select()
        self.sTableView.setColumnHidden(SID, True)
        self.sTableView.setColumnHidden(SMID, True)


    def addDdtRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mModel.rowCount()
        self.mapper.submit()
        self.mModel.insertRow(row)
        self.mapper.setCurrentIndex(row)
        self.dateEdit.setDate(QDate.currentDate())
        self.dateEdit.setFocus()
        self.mmUpdate()

    def delDdtRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mapper.currentIndex()
        if row == -1:
            self.statusbar.showMessage(
                        "Nulla da cancellare...",
                        5000)
            return
        record = self.mModel.record(row)
        id = record.value(MID).toInt()[0]
        fatt = record.value(MDOC).toString()
        if(QMessageBox.question(self, "Cancella Scaffale",
                    "Vuoi cancellare il ddt N': {0} ?".format(fatt),
                    QMessageBox.Yes|QMessageBox.No) ==
                    QMessageBox.No):
            self.statusbar.showMessage(
                        "Cancellazione ddt annullata...",
                        5000)
            return
        # cancella scaffale
        self.mModel.removeRow(row)
        self.mModel.submitAll()
        if row + 1 >= self.mModel.rowCount():
            row = self.mModel.rowCount() - 1
        self.mapper.setCurrentIndex(row)
        if self.mModel.rowCount() == 0:
            self.cauLineEdit.setText(QString(""))
            self.noteLineEdit.setText(QString(""))
            self.ddtLineEdit.setText(QString(""))
            self.cliComboBox.setCurrentIndex(-1)

        # cancella tutti gli articoli che si riferiscono
        # allo scaffale cancellato
        self.sModel.setFilter("mmid=%s" % id)
        self.sModel.select()
        self.sModel.removeRows(0, self.sModel.rowCount())
        self.sModel.submitAll()
        self.statusbar.showMessage(
                        "Cancellazione eseguita...",
                        5000)
        self.mmUpdate()

    def addDettRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        rowfatt = self.mapper.currentIndex()
        record = self.mModel.record(rowfatt)
        masterid = record.value(MID).toInt()[0]
        if masterid < 1:
            self.statusbar.showMessage(
                "Scaffale non valido o non confermato...",
                5000)
            self.dateEdit.setFocus()
            return
        # aggiunge la nuova riga alla vista
        self.sModel.submitAll()
        self.sModel.select()
        row = self.sModel.rowCount()
        self.sModel.insertRow(row)
        self.sModel.setData(self.sModel.index(row, SMID),
                                                QVariant(masterid))
        self.sModel.setData(self.sModel.index(row, SQT),
                                                QVariant(1))
        self.sModel.setData(self.sModel.index(row, SDESC),
                                                QVariant(""))
        self.sModel.setData(self.sModel.index(row, SIMP),
                                                QVariant(0.0))
        self.sModel.setData(self.sModel.index(row, SIVA),
                                                QVariant(20.0))
        self.editindex = self.sModel.index(row, SQT)
        self.sTableView.setCurrentIndex(self.editindex)
        self.sTableView.edit(self.editindex)

    def delDettRecord(self):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        selrows = self.sItmSelModel.selectedRows()
        if not selrows:
            self.statusbar.showMessage(
                "No articles selected to delete...",
                5000)
            return
        if(QMessageBox.question(self, "Cancellazione righe",
                "Vuoi cancellare: {0} righe?".format(len(selrows)),
                QMessageBox.Yes|QMessageBox.No) ==
                QMessageBox.No):
            return
        QSqlDatabase.database().transaction()
        query = QSqlQuery()
        query.prepare("DELETE FROM fattslave WHERE id = :val")
        for i in selrows:
            if i.isValid():
                query.bindValue(":val", QVariant(i.data().toInt()[0]))
                query.exec_()
        QSqlDatabase.database().commit()
        self.sModel.revertAll()
        self.mmUpdate()


    def setupMenu(self):
        # AboutBox
        self.connect(self.action_About, SIGNAL("triggered()"),
                    self.showAboutBox)
        # FileNew
        self.connect(self.action_New_File, SIGNAL("triggered()"),
                    self.newFile)

        # FileLoad
        self.connect(self.action_Load_File, SIGNAL("triggered()"),
                    self.openFile)

        # Edit customers
        self.connect(self.action_Add_Customers, SIGNAL("triggered()"),
                    self.editCustomers)


    def editCustomers(self):
        relpath = os.path.dirname(__file__)
        if relpath:
            relpath = "%s/" % relpath
        subprocess.call(['python',os.path.join("%s../clienti/" %
                                        relpath, "clienti.py")])
        self.setupModels()
        self.setupMappers()
        self.setupTables()
        self.mmUpdate()

    def showAboutBox(self):
        dlg = aboutfatt.AboutBox(self)
        dlg.exec_()

    def creaStrutturaDB(self):
        query = QSqlQuery()
        if not ("tipofatt" in self.db.tables()):
            if not query.exec_("""CREATE TABLE tipofatt (
                        id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                        tfatt VARCHAR(50) NOT NULL)"""):
                QMessageBox.warning(self, "Gestione Fatture",
                                QString("Creazione tabella tipofatt fallita!"))
                return False
            else:
                # aggiungi voci !!!!
                query.exec_("""INSERT INTO tipofatt
                            VALUES (NULL,'Fattura Semplice')""")
                query.exec_("""INSERT INTO tipofatt
                            VALUES (NULL,'Fattura Accompagnatoria')""")
                query.exec_("""INSERT INTO tipofatt
                            VALUES (NULL,'Nota Accredito')""")


        if not ("fattmaster" in self.db.tables()):
            if not query.exec_("""CREATE TABLE fattmaster (
                        id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                        data DATE NOT NULL,
                        doc VARCHAR(50) NOT NULL,
                        idtdoc INTEGER NOT NULL,
                        idcli INTEGER NOT NULL,
                        tpag VARCHAR(50) NOT NULL DEFAULT 'Contanti',
                        causale VARCHAR(200),
                        note VARCHAR(200))"""):
                QMessageBox.warning(self, "Gestione Fatture",
                                QString("Creazione tabella master fallita!"))
                return False

        if not ("fattslave" in self.db.tables()):
            if not query.exec_("""CREATE TABLE fattslave (
                                id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                                qt INTEGER NOT NULL DEFAULT '1',
                                desc VARCHAR(200) NOT NULL,
                                imp DOUBLE NOT NULL DEFAULT '0.0',
                                iva DOUBLE NOT NULL DEFAULT '20.0',
                                mmid INTEGER NOT NULL,
                                FOREIGN KEY (mmid) REFERENCES master)"""):
                QMessageBox.warning(self, "Gestione Fatture",
                                QString("Creazione tabella slave fallita!"))
                return False
            QMessageBox.information(self, "Gestione Fatture",
                                QString("Database Creato!"))
            return True


        if not ("clienti" in self.db.tables()):
            if not query.exec_("""CREATE TABLE clienti (
                                id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                                ragsoc VARCHAR(200) NOT NULL,
                                indirizzo VARCHAR(200) NOT NULL,
                                piva VARCHAR(15),
                                cf VARCHAR(15),
                                tel VARCHAR(30),
                                fax VARCHAR(30),
                                cell VARCHAR(30),
                                email VARCHAR(50))"""):
                QMessageBox.warning(self, "Gestione Fatture",
                                QString("Creazione tabella clienti fallita!"))
                return False
        return True

    def loadFile(self, fname=None):
        if fname is None:
            return
        if self.db.isOpen():
            self.db.close()
        self.db.setDatabaseName(QString(fname))
        if not self.db.open():
            QMessageBox.warning(self, "Gestione Fatture",
                                QString("Database Error: %1")
                                .arg(db.lastError().text()))
        else:
            if not self.creaStrutturaDB():
                return
            self.filename = unicode(fname)
            self.setWindowTitle("Gestione Fatture - %s" % self.filename)
            self.setupModels()
            self.setupMappers()
            self.setupTables()
            #self.setupItmSignals()
            self.restoreTablesSettings()
            self.mmUpdate()


    def loadInitialFile(self):
        settings = QSettings()
        fname = unicode(settings.value("Settings/lastFile").toString())
        if fname and QFile.exists(fname):
            self.loadFile(fname)


    def openFile(self):
        dir = os.path.dirname(self.filename) \
                if self.filename is not None else "."
        fname = QFileDialog.getOpenFileName(self,
                    "Gestione Fatture - Scegli database",
                    dir, "*.db")
        if fname:
            self.loadFile(fname)


    def newFile(self):
        dir = os.path.dirname(self.filename) \
                if self.filename is not None else "."
        fname = QFileDialog.getSaveFileName(self,
                    "Gestione Fatture - Scegli database",
                    dir, "*.db")
        if fname:
            self.loadFile(fname)

    def restoreWinSettings(self):
        settings = QSettings()
        self.restoreGeometry(
                settings.value("MainWindow/Geometry").toByteArray())

    def restoreTablesSettings(self):
        settings = QSettings(self)
        # per la tablelview
        for column in range(1, self.sModel.columnCount()-1):
            width = settings.value("Settings/sTableView/%s" % column,
                                    QVariant(60)).toInt()[0]
            self.sTableView.setColumnWidth(column,
                                        width if width > 0 else 60)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Down:
            self.addDettRecord()
        else:
            QMainWindow.keyPressEvent(self, event)

    def closeEvent(self, event):
        self.mapper.submit()
        settings = QSettings()
        settings.setValue("MainWindow/Geometry", QVariant(
                          self.saveGeometry()))
        if self.filename is not None:
            settings.setValue("Settings/lastFile", QVariant(self.filename))
        if self.db.isOpen():
            # salva larghezza colonne tabella
            for column in range(1, self.sModel.columnCount()-1):
                width = self.sTableView.columnWidth(column)
                if width:
                    settings.setValue("Settings/sTableView/%s" % column,
                                        QVariant(width))
            self.db.close()
            del self.db

    def setupModels(self):
        """
            Initialize all the application models
        """
        # setup slaveModel
        self.sModel = MyQSqlTableModel(self)
        self.sModel.setTable(QString("fattslave"))
        self.sModel.setHeaderData(SID, Qt.Horizontal, QVariant("ID"))
        self.sModel.setHeaderData(SQT, Qt.Horizontal, QVariant("Qt"))
        self.sModel.setHeaderData(SDESC, Qt.Horizontal, QVariant("Descrizione"))
        self.sModel.setHeaderData(SIMP, Qt.Horizontal, QVariant("Importo"))
        self.sModel.setHeaderData(SIVA, Qt.Horizontal, QVariant("Iva"))
        self.sModel.setHeaderData(SMID, Qt.Horizontal, QVariant("idlegato"))
        self.sModel.setEditStrategy(QSqlTableModel.OnRowChange)
        self.sModel.select()

        # setup masterModel
        self.mModel = QSqlRelationalTableModel(self)
        self.mModel.setTable(QString("fattmaster"))
        self.mModel.setSort(MDATA, Qt.AscendingOrder)
        self.mModel.setRelation(MIDCLI, QSqlRelation("clienti",
                                            "id", "ragsoc"))
        self.mModel.setRelation(MIDTDOC, QSqlRelation("tipofatt",
                                            "id", "tfatt"))
        self.mModel.select()

    def setupMappers(self):
        '''
            Initialize all the application mappers
        '''
        self.mapper = QDataWidgetMapper(self)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.setModel(self.mModel)
        self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
        self.mapper.addMapping(self.dateEdit, MDATA)
        self.mapper.addMapping(self.fattLineEdit, MDOC)

        relationModel = self.mModel.relationModel(MIDTDOC)
        relationModel.setSort(1, Qt.AscendingOrder)
        relationModel.select()
        self.tipoFattComboBox.setModel(relationModel)
        self.tipoFattComboBox.setModelColumn(relationModel.fieldIndex("tfatt"))
        self.mapper.addMapping(self.tipoFattComboBox, MIDTDOC)

        relationModel = self.mModel.relationModel(MIDCLI)
        relationModel.setSort(CRAGSOC, Qt.AscendingOrder)
        relationModel.select()
        self.cliComboBox.setModel(relationModel)
        self.cliComboBox.setModelColumn(relationModel.fieldIndex("ragsoc"))
        self.mapper.addMapping(self.cliComboBox, MIDCLI)

        self.mapper.addMapping(self.tipoPagLineEdit, MPAG)
        self.mapper.addMapping(self.cauLineEdit, MCAU)
        self.mapper.addMapping(self.noteLineEdit, MNOTE)
        self.mapper.toFirst()

    def setupTables(self):
        """
            Initialize all the application tablesview
        """
        self.sTableView.setModel(self.sModel)
        self.sTableView.setColumnHidden(SID, True)
        self.sTableView.setColumnHidden(SMID, True)
        self.sTableView.setWordWrap(True)
        self.sTableView.resizeRowsToContents()
        self.sTableView.setAlternatingRowColors(True)
        self.sItmSelModel = QItemSelectionModel(self.sModel)
        self.sTableView.setSelectionModel(self.sItmSelModel)
        self.sTableView.setSelectionBehavior(QTableView.SelectRows)
        self.sTableView.setTabKeyNavigation(False)
        self.myDelegate = MyQSqlRelationalDelegate(self)
        self.sTableView.setItemDelegate(self.myDelegate)
        self.connect(self.myDelegate, SIGNAL("addDettRecord()"),
            self.addDettRecord)

    def setupUiSignals(self):
        self.connect(self.printPushButton, SIGNAL("clicked()"),
                    self.printFatt)
        self.connect(self.addMPushButton, SIGNAL("clicked()"),
                    self.addDdtRecord)
        self.connect(self.delMPushButton, SIGNAL("clicked()"),
                    self.delDdtRecord)
        self.connect(self.addSPushButton, SIGNAL("clicked()"),
                    self.addDettRecord)
        self.connect(self.delSPushButton, SIGNAL("clicked()"),
                    self.delDettRecord)
        self.connect(self.firstMPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.FIRST))
        self.connect(self.prevMPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.PREV))
        self.connect(self.nextMPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.NEXT))
        self.connect(self.lastMPushButton, SIGNAL("clicked()"),
                    lambda: self.saveRecord(MainWindow.LAST))

    def saveRecord(self, where):
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return
        row = self.mapper.currentIndex()
        self.mapper.submit()
        self.sModel.revertAll()
        if where == MainWindow.FIRST:
            row=0
        elif where == MainWindow.PREV:
            row = 0 if row <= 1 else row - 1
        elif where == MainWindow.NEXT:
            row += 1
            if row >= self.mModel.rowCount():
                row = self.mModel.rowCount() -1
        elif where == MainWindow.LAST:
            row = self.mModel.rowCount()- 1
        self.mapper.setCurrentIndex(row)
        self.mmUpdate()

    def printFatt(self):
        '''
            Print Inventory
        '''
        if not self.db.isOpen():
            self.statusbar.showMessage(
                "Database non aperto...",
                5000)
            return

        def makeFATT(copia="Copia Cliente"):
            qmaster = QSqlQuery()
            qcli = QSqlQuery()
            qslave = QSqlQuery()

            curidx = self.mapper.currentIndex()
            currec = self.mModel.record(curidx)
            masterid = currec.value("id").toInt()[0]

            qmaster.exec_("SELECT id,data,doc,idtdoc,idcli,causale,note "
                        "FROM fattmaster WHERE doc = '%s'" % (currec.value("doc").toString()))
            qmaster.next()
            curcli = qmaster.value(4).toInt()[0]
            qcli.exec_("SELECT id,ragsoc,indirizzo,piva "
                        "FROM clienti WHERE id = %d" % (curcli))
            qslave.exec_("SELECT mmid,qt,desc,imp,iva "
                            "FROM fattslave WHERE mmid = '%s'" % (masterid))

            qcli.next()
            # variabili utili alla stampa del report
            datadoc = currec.value("data").toDate().toString(DATEFORMAT)
            causaledoc = currec.value("causale").toString()
            notedoc = currec.value("note").toString()
            tipodoc = currec.value(3).toString()
            numdoc = currec.value("doc").toString()
            cliragsoc = qcli.value(1).toString()
            cliind = qcli.value(2).toString()
            clipiva = qcli.value(3).toString()

            from reportlab.pdfgen.canvas import Canvas
            from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
            from reportlab.lib.units import cm
            from reportlab.lib.enums import TA_LEFT,TA_RIGHT,TA_CENTER
            from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, Paragraph, KeepTogether
            from reportlab.rl_config import defaultPageSize
            from reportlab.lib import colors
            from reportlab.lib.pagesizes import letter, A4
            from reportlab.lib import textsplit

            PAGE_WIDTH, PAGE_HEIGHT=defaultPageSize
            styles = getSampleStyleSheet()
            styleN = styles['Normal']
            styleH = styles['Heading1']
            styleH.alignment=TA_CENTER
            Elements = []
            #add some flowables
            p=Paragraph
            ps=ParagraphStyle

            Author = "Stefano Zamprogno"
            URL = "http://www.zamprogno.it/"
            email = "*****@*****.**"

            pageinfo = "%s / %s" % (Author, email)

            def myLaterPages(c, doc):
                c.saveState()
                c.setFont("Times-Bold", 82)
                c.rotate(45)
                c.setFillColorRGB(0.9,0.9,0.9)
                c.drawString(11*cm,2*cm, copia)
                c.rotate(-45)
                c.setFillColorRGB(0,0,0)
                # HEADER
                if tipodoc == "Fattura Accompagnatoria":
                    subt = 0
                else:
                    subt = 3
                c.setLineWidth(0.1*cm)
                c.setStrokeColorRGB(0,0,0)
                c.line(1.8*cm,(6.2-subt)*cm,19.5*cm,(6.2-subt)*cm)
                c.setStrokeColorRGB(0.5,0.5,0.5)
                c.line(1.9*cm,(6.1-subt)*cm,19.6*cm,(6.1-subt)*cm)
                # cerchi carta
                c.circle(0.9*cm,6*cm,0.3*cm, fill=1)
                c.circle(0.9*cm,24*cm,0.3*cm, fill=1)
                c.setFont("Times-Bold", 14)
                c.drawCentredString(5*cm, 28*cm, r1)
                c.setFont("Times-Bold", 9)
                c.drawCentredString(5*cm, 27.5*cm, r2)
                c.drawCentredString(5*cm, 27*cm, r3)
                c.drawCentredString(5*cm, 26.5*cm, r4)
                c.drawCentredString(5*cm, 26*cm, r5)
                # numero ddt e descrizione copia
                c.setFont("Times-Bold", 12)
                c.drawCentredString(18*cm, 28*cm, "DOC N: %s" % (numdoc))
                c.setFont("Times-Bold", 7)
                c.drawCentredString(18*cm, 27.6*cm, "(%s)" % (copia))
                c.drawCentredString(18*cm, 27.2*cm, "%s" % (tipodoc.toUpper()))
                # Data e causale
                c.setFont("Times-Bold", 10)
                c.drawString(1.8*cm, 25*cm, "Data:")
                c.drawString(1.8*cm, 24.5*cm, "Causale:")
                c.setFont("Times-Roman", 10)
                c.drawString(4*cm, 25*cm, unicode(datadoc))
                c.drawString(4*cm, 24.5*cm, unicode(causaledoc))
                # Cliente
                c.setFont("Times-Bold", 10)
                c.drawString(11*cm, 25*cm, "Destinatario:")
                c.setFont("Times-Roman", 10)
                c.drawCentredString(16*cm, 25*cm, unicode(cliragsoc))
                c.drawCentredString(16*cm, 24.5*cm, unicode(cliind))
                c.drawCentredString(16*cm, 24*cm, unicode(clipiva))
                # FOOTER
                c.setFont("Times-Bold", 10)
                c.setLineWidth(0.01*cm)
                c.drawString(1.8*cm, (5.5-subt)*cm, "Note:")
                c.setFont("Times-Roman", 10)
                strt = (5.5-subt)*cm
                for i in textsplit.wordSplit(unicode(notedoc),6*cm,
                                            "Times-Roman", 10):
                    c.drawString(3*cm, strt, i[1])
                    strt -= 0.5*cm
                if tipodoc == "Fattura Accompagnatoria":
                    c.setFont("Times-Bold", 10)
                    c.drawString(12*cm, 5.5*cm, "Data inizio trasporto:")
                    c.line(15.5*cm,5.4*cm,19*cm,5.4*cm)
                    c.drawString(12*cm, 5*cm, "Aspetto dei beni:")
                    c.line(15*cm,4.9*cm,19*cm,4.9*cm)
                    c.drawString(12*cm, 4.5*cm, "Numero colli:")
                    c.line(15*cm,4.4*cm,19*cm,4.4*cm)
                    c.drawString(12*cm, 3.8*cm, "Conducente:")
                    c.line(15*cm,3.7*cm,19*cm,3.7*cm)
                    c.drawString(12*cm, 3*cm, "Destinatario:")
                    c.line(15*cm,2.9*cm,19*cm,2.9*cm)
                    c.drawString(1.8*cm, 4*cm, "Trasporto a Mezzo:")
                    c.line(2.3*cm,3*cm,7*cm,3*cm)
                # note pie' pagina
                c.setFont('Times-Roman',9)
                c.drawString(12.4*cm, 1.5*cm, "Pagina %d %s" % (doc.page, pageinfo))
                c.restoreState()

            # crea il body del ddt
            data = [['Qt', 'Descrizione dei beni, natura e qualità',
                     'Importo', 'IVA'],]

            totimp = 0
            totiva = 0
            totesiva = 0
            while qslave.next():
                if qslave.value(4).toDouble()[0]!= 0:
                    totimp += qslave.value(3).toDouble()[0]
                    totiva += (qslave.value(3).toDouble()[0]*
                                qslave.value(4).toDouble()[0] / 100.0)
                else:
                    totesiva += qslave.value(3).toDouble()[0]

                data.append([qslave.value(1).toInt()[0],
                            p(unicode(qslave.value(2).toString()),
                                ps(name='Normal')),
                            "€ %.2f" % qslave.value(3).toDouble()[0],
                            "%.2f %%" % qslave.value(4).toDouble()[0]])

            Elements.append(Table(data,colWidths=(1*cm,12.5*cm,2*cm,2*cm),repeatRows=1,
                                style=(
                                        ['LINEBELOW', (0,0), (-1,0),
                                            1, colors.black],
                                        ['BACKGROUND',(0,0),(-1,0),
                                            colors.lightgrey],
                                        ['GRID',(0,0),(-1,-1), 0.2,
                                            colors.black],
                                        ['FONT', (0, 0), (-1, 0),
                                            'Helvetica-Bold', 10],
                                        ['VALIGN', (0,0), (-1,-1), 'TOP'],
                                        ['ALIGN', (0,0), (-1,0), 'CENTER'],
                                        ['ALIGN', (2,1), (3,-1), 'RIGHT'],

                                )))

            summary = []
            summary.append(Spacer(0.5*cm, 0.5*cm))
            summary.append(Paragraph("<para align=right><b>___________________________________"
                            "</b></para>", styleN))
            summary.append(Paragraph("<para align=right><b>TOTALE IMPONIBILE: "
                            "€ %.2f</b></para>" % totimp, styleN))
            summary.append(Paragraph("<para align=right><b>TOTALE IVA: "
                            "€ %.2f</b></para>" % totiva, styleN))
            summary.append(Paragraph("<para align=right><b>TOTALE Es.IVA: "
                            "€ %.2f</b></para>" % totesiva, styleN))
            summary.append(Spacer(0.5*cm, 0.5*cm))
            summary.append(Paragraph("<para align=right><b>TOTALE GENERALE: "
                            "€ %.2f</b></para>" % (totesiva+totimp+totiva), styleN))
            Elements.append(KeepTogether(summary))

            # 'depure' numddt
            numdoc = numdoc.replace("/",".")
            if tipodoc == "Fattura Accompagnatoria":
                doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__),
                                "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=6.2*cm)
            else:
                doc = SimpleDocTemplate(os.path.join(os.path.dirname(__file__),
                                "fatt%s.%s.pdf" % (numdoc, copia.replace(" ","."))),topMargin=6.2*cm, bottomMargin=3*cm)

            doc.build(Elements,onFirstPage=myLaterPages,onLaterPages=myLaterPages)

            subprocess.Popen(['gnome-open',os.path.join(os.path.dirname(__file__),
                            "fatt%s.%s.pdf" % (numdoc, copia.replace(" ",".")))])

        if self.copiaCliCheckBox.isChecked():
            makeFATT()
        if self.copiaIntCheckBox.isChecked():
            makeFATT(copia="Copia Interna")
        if self.copiaVettCheckBox.isChecked():
            makeFATT(copia="Copia Vettore")
Esempio n. 26
0
class ServerDialog(QDialog, Ui_ServerDialogDesign):

    # The threadpool for the workers
    _threadPool = []
    # And it's lock
    _threadLock = RLock()

    def __init__(self, server=None, parent=None):
        """The `ServerDialog` constructor.

        Parameters:

        - `serverList`: a `ServerList` instance containing the list of
          available servers.
        - `server`: the name of a server. If provided, this server will
          be selected in the serverList view.
        """
        super(ServerDialog, self).__init__(parent)
        self.setupUi(self)

        self.networkIcon.setPixmap(pixmapFromTheme(
            'preferences-system-network',
            ':/icons/48/preferences-system-network')
        )
        self.authIcon.setPixmap(pixmapFromTheme(
            'preferences-other',
            ':/icons/48/preferences-other')
        )
        self.securityIcon.setPixmap(pixmapFromTheme(
            'preferences-system',
            ':/icons/48/preferences-system')
        )
        
        self.__serverList = ServerList() #Load the serverlist from disk.
        self.__serverListCopy = None # When we click "Save", the current list is saved here
        
        # The list actually returned to the caller. Could be the copy or current active list
        self.__returnList = None 

        # Create the model used by the views and connect signals for registering
        # changes (to define the "Cancel"-buttons behaviour).
        self.slm = ServerListModel(self.__serverList, self)
        self.slm.dataChanged.connect(self.wasChanged)
        self.slm.rowsInserted.connect(self.wasChanged)
        self.slm.rowsRemoved.connect(self.wasChanged)
        
        # Used for determining if we should confirm cancel
        self.isChanged = False

        # The serverListView works on the servermodel
        self.serverListView.setModel(self.slm)

        # Enable/disable editing depending on if we have a server to edit
        if self.slm.hasServers():
            self.tabWidget.setEnabled(True)
            self.testConnectionButton.setEnabled(True)
        else:
            self.tabWidget.setEnabled(False)
            self.testConnectionButton.setEnabled(False)

        self.splitter.setStretchFactor(1, 0)

        # Update list of baseDNs on serverchange
        self.serverListView.selectionModel().selectionChanged.connect(self.setBaseDN) #Same as below

        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.slm)
        
        # The delegate handles the comboboxes and to-from the list of custom baseDNs
        # (delegate is used manually for the baseDNs)
        self.serverDelegate = ServerDelegate()
        self.mapper.setItemDelegate(self.serverDelegate)
        self.mapper.addMapping(self.hostEdit, 1)
        self.mapper.addMapping(self.portSpinBox, 2)
        self.mapper.addMapping(self.bindAnonBox, 3)
        self.mapper.addMapping(self.baseDNBox, 4)
        self.mapper.addMapping(self.bindAsEdit, 6)
        self.mapper.addMapping(self.passwordEdit, 7)
        self.mapper.addMapping(self.encryptionBox, 8)
        self.mapper.addMapping(self.mechanismBox, 9)
        self.mapper.addMapping(self.aliasBox, 10)
        self.mapper.addMapping(self.useClientCertBox, 11)
        self.mapper.addMapping(self.certFileEdit, 12)
        self.mapper.addMapping(self.certKeyfileEdit, 13)
        self.mapper.addMapping(self.validateBox, 14)

        # Workaround to ensure model being updated (Mac OS X bug)
        self.aliasBox.clicked.connect(self.aliasBox.setFocus)
        self.baseDNBox.clicked.connect(self.baseDNBox.setFocus)
        self.bindAnonBox.clicked.connect(self.bindAnonBox.setFocus)
        self.useClientCertBox.clicked.connect(self.useClientCertBox.setFocus)

        # Select the first servers (as the serverlistview does)
        self.mapper.setCurrentIndex(0)
        self.setBaseDN()

        # Let the mapper know when another server is selected in the list
        self.serverListView.selectionModel().currentRowChanged.connect(self.mapper.setCurrentModelIndex)
        
        # Enable checks for SSL enabled but with a non-standard port.
        self.encryptionBox.activated[int].connect(self.checkSSLport)

        # Used by the connection-test
        self.testProgress = QProgressDialog("Trying to connect to server.",
                "Abort",
                0, 0,
                self)
        self.testProgress.setWindowModality(Qt.WindowModal)

        # If a servername is supplied we try to get its index, 
        # And make it selected, else we select the first server
        # in the model)
        if not server is None:
            serverIndex = self.__serverList.getIndexByName(server)
            if serverIndex == -1:
                serverIndex = 0
            index = self.serverListView.model().index(serverIndex, 0)
        else:
            index = self.serverListView.model().index(0, 0)
        # Select it in the view
        self.serverListView.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)
        self.serverListView.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect)
        
    def checkSSLport(self, index):
        """ If SSL is choosen with a port other than 636, confirm this with the user
        """
        if index == ServerEncryptionMethod.SSL and self.portSpinBox.value() != 636:
            ans = QMessageBox.information(self, QCoreApplication.translate("ServerDialog","SSL")
                ,QCoreApplication.translate("ServerDialog","You have choosen to use SSL but with a port other than 636.\n Do you want this automatically changed?")
                ,QMessageBox.Yes|QMessageBox.No)
            if ans == QMessageBox.Yes:
                self.portSpinBox.setValue(636)
        if index == ServerEncryptionMethod.Unencrypted and self.portSpinBox.value() != 389:
            ans = QMessageBox.information(self, QCoreApplication.translate("ServerDialog","Unencrypted")
                ,QCoreApplication.translate("ServerDialog","You have choosen to use unencryped LDAP but with a port other than 389.\n Do you want this automatically changed?")
                ,QMessageBox.Yes|QMessageBox.No)
            if ans == QMessageBox.Yes:
                self.portSpinBox.setValue(389)

    def wasChanged(self):
        """Slot to register that some server settings is changed.
        """
        self.isChanged = True

    def addBaseDN(self):
        """Slot for adding a base DN
        """
        tmpBaseDN = unicode(self.baseDNEdit.text()).strip()
        if tmpBaseDN == u"":
            return
        self.baseDNListWidget.addItem(QListWidgetItem(tmpBaseDN)) #Add to list

        # Save the list of baseDNs
        serverIndex = self.serverListView.selectedIndexes()[0]
        index = self.slm.createIndex(serverIndex.row(), 5) # 5 = column for baseDNs
        self.serverDelegate.setModelData(self.baseDNListWidget, self.slm, index) #save to model
        self.baseDNEdit.clear() #Clear textfield
        self.mapper.submit() #Force push to model

    def deleteBaseDN(self):
        """Slot for deleting a base DN
        """
        # Delete every selected baseDN
        for tmpItem in self.baseDNListWidget.selectedItems():
            if not (None == tmpItem):
                index = self.baseDNListWidget.indexFromItem(tmpItem) #get the index to the basedn
                d = self.baseDNListWidget.takeItem(index.row()) #delete (actually steal) the baseDN from the list
                if d != 0:
                    del d # Per the QT-docs, someone needs to delete it

        # Save to model (see addBaseDN())
        serverIndex = self.serverListView.selectedIndexes()[0]
        index = self.slm.createIndex(serverIndex.row(), 5)
        self.serverDelegate.setModelData(self.baseDNListWidget, self.slm, index)
        self.mapper.submit() #Force push changes to model

    def setBaseDN(self):
        """Slot for setting the base DN-list.
        """
        serverIndex = self.serverListView.selectedIndexes()
        if len(serverIndex) > 0:
            index = self.slm.createIndex(serverIndex[0].row(), 5)
            self.serverDelegate.setEditorData(self.baseDNListWidget, index)

    def addServer(self):
        """Create a new ServerObject and add it to the model, and thus
        the server list.
        """
        name, ok = QInputDialog.getText(self, self.tr('Add server'), self.tr('Name:'))
        if ok:
            if len(name) < 1 or self.__serverList.getServerObject(name) != None:
                QMessageBox.information(self, self.tr('Error'), self.tr("Invalid name or already used."))
                return

            sO = ServerObject()
            sO.name = unicode(name)

            # Insert into the model
            m = self.serverListView.model()
            success, index = m.addServer(sO)
            if success:
                # Display the added server
                self.serverListView.selectionModel().select(index, QItemSelectionModel.ClearAndSelect) #Select it
                self.serverListView.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect) #Mark it as current      
                self.mapper.setCurrentIndex(index.row()) # Update the mapper
                self.tabWidget.setEnabled(True) # Make sure editing is enabled
                self.testConnectionButton.setEnabled(True)

    def deleteServer(self):
        """Delete a server from the model/list
        """
        if self.serverListView.selectionModel().currentIndex().row() < 0:
            #No server selected
            return

        re = QMessageBox.question(self, self.tr('Delete'),
                     self.tr("Are you sure?"), 
                     QMessageBox.Yes, 
                     QMessageBox.No)

        if re == QMessageBox.Yes:
            index = self.serverListView.selectionModel().currentIndex() #Currently selected

            # Delete the server
            if self.serverListView.model().delServerAtIndex(index):
                # When deleting, the view gets updated and selects a new current.
                # Get it and give it to the mapper
                newIndex = self.serverListView.selectionModel().currentIndex()
                self.mapper.setCurrentIndex(newIndex.row())

        if not self.slm.hasServers():
            self.tabWidget.setEnabled(False) #Disable editing if no servers left
            self.testConnectionButton.setEnabled(False)

    def saveServerlist(self):
        """Called when the Save-button is clicked
        """
        self.mapper.submit()

        if not self.baseDNsOK():
            if not self.isBaseDNsOkMessage():
                # If we got here, we DO NOT WANT TO SAVE/QUIT
                return False

        self.__serverList.writeServerList()
        self.__serverListCopy = copy.deepcopy(self.__serverList)

        return True

    def reject(self):
        """Called when the users clicks cancel or presses escape
        """
        # If no changes: just quit
        if not self.isChanged:
            QDialog.reject(self)
            return


        # Really quit?
        r = QMessageBox.question(self, self.tr("Exit?"), self.tr("Are you sure you want to exit the server editor?\n Any unsaved changes will be lost!"), QMessageBox.Ok | QMessageBox.Cancel)
        if not r == QMessageBox.Ok:
            # Don't quit
            return

        # If "save" has been clicked, return the saved list by calling accept()
        if self.__serverListCopy: #This is non-None if Save has been clicked.
            self.__returnList = self.__serverListCopy # Return the saved on instead
            QDialog.accept(self) # Closes the window while indicating the caller needs to get the new list (self.__returnList)
            return
        QDialog.reject(self)

    def accept(self):
        """Called when OK-button is clicked
        """
        if not self.saveServerlist():
            # DO NOT QUIT
            return
        self.__returnList = self.__serverList
        QDialog.accept(self)

    def isBaseDNsOkMessage(self):
        r = QMessageBox.question(self,
            self.tr("BaseDNs not defined"),
            self.tr("One or more server(s) are setup to use custom base DNs without specifying any.\nDo you still want to save?"),
            QMessageBox.Yes | QMessageBox.No)
        if r == QMessageBox.No:
            return False
        else:
            return True

    def baseDNsOK(self):
        for server in self.__serverList.getTable(): 
            if server.autoBase == False and len(server.baseDN) < 1:
                return False
        return True

    def getResult(self):
        return self.__returnList

    def certFileDialog(self):
        """Slot for selecting a certificate file.
        """
        certFile = QFileDialog.getOpenFileName(self, self.trUtf8('Select certificate file'), '')

        if not certFile is None:
            self.certFileEdit.setText(certFile)
            self.mapper.submit()

    def certKeyfileDialog(self):
        """Slot for selecting a certificate keyfile.
        """
        certKeyfile = QFileDialog.getOpenFileName(self, self.trUtf8('Select certificate keyfile'), '')

        if not certKeyfile is None:
            self.certKeyfileEdit.setText(certKeyfile)
            self.mapper.submit()

    def testConnection(self):
        """
        Tries to bind to the currently selected server.
        """
        currentServerId = self.serverListView.currentIndex().row()
        sO = self.__serverList.getServerObjectByIndex(currentServerId)

        # Busy-dialog
        self.testProgress.reset()
        self.testProgress.show()
        
        # Try to bind
        conn = LumaConnectionWrapper(sO, self)
        conn.bindFinished.connect(self.testFinished)
        conn.bindAsync(sO.name) #Send the serverName as identifier

    @pyqtSlot(bool, Exception, str)
    def testFinished(self, success, exception, serverName):
        # Unparent the LumaConnectionParent from this object
        # so that it is GCed (that is the only reference to it.)
        self.sender().setParent(None)

        self.testProgress.hide()

        if self.testProgress.wasCanceled():
            return

        if success:
            # Success-message
            QMessageBox.information(self, serverName, unicode(self.tr("Bind to {0} successful!")).format(serverName))
        else:
            # Error-message
            if exception[0]["desc"] == "Invalid credentials":
                QMessageBox.warning(self, serverName,
                        unicode(self.tr("Bind to {0} failed:\n{1}\n\n(You do not have to spesify passwords here -- you will be asked when needed.)")).format(serverName,exception[0]["desc"]))
                return
            QMessageBox.warning(self, serverName, unicode(self.tr("Bind to {0} failed:\n{1}")).format(serverName, exception[0]["desc"]))
Esempio n. 27
0
class SrwrViewRecord(object):
    """
    Functionality to view a SRWR record in separate form. This class is generic and can be used by all 3 SRWR tabs.
    """
    whole_road_col = int()

    def __init__(self, model, iface, dialog, whole_rd_col, widget_info,
                 params):
        """
        Basic setup of class variables and some initial setup of mapper.
        :param model: Model from tableview
        :param iface: qgis iface hook
        :param dialog: dialog which is unique to each tab
        :param whole_rd_col: int for whole road column in tab table
        :param widget_info: List of widgetinfo objects for the provided dialog
        """
        self.view_dlg = dialog
        self.widgets = widget_info

        # Find the date columns from the widget info objects
        self.date_cols = []
        self.id_lineedit = None
        for w in widget_info:
            if w.date_col:
                self.date_cols.append(w.db_col)
            if w.id_col:
                self.id_lineedit = w.widget

        self.model = model
        self.whole_road_col = whole_rd_col
        self.iface = iface
        self.mapper = None
        self.proxy = None
        self.params = params
        self.view_dlg.setWindowFlags(Qt.Window | Qt.WindowTitleHint
                                     | Qt.CustomizeWindowHint)

        self.setup_mapper()
        self.view_dlg.ui.mapPushButton.clicked.connect(self.zoom_to_map)
        self.view_dlg.ui.closePushButton.clicked.connect(self.complete)

    def whole_rd_state(self, state):
        """
        Checks if its a whole record and set checkbox accordingly
        :param state: Current state
        """
        checked = True
        if state == 2:
            checked = False
        self.view_dlg.ui.wholeRoadCheckBox.blockSignals(True)
        self.view_dlg.ui.wholeRoadCheckBox.setChecked(checked)
        self.view_dlg.ui.wholeRoadCheckBox.setChecked(False)

    def view(self, idx, usrn):
        """
        View a record details in a dialog
        :param idx: index of view in the model
        :param usrn: usrn of current record
        """
        row = idx.row()
        self.mapper.setCurrentIndex(row)
        self.view_dlg.ui.wholeRoadCheckBox.setEnabled(False)
        self.whole_road_checkbox(row)
        self.hide_buttons()
        self.view_dlg.show()

    def zoom_to_map(self):
        """
        Zoom the canvas to the start/end coords of the maint record
        """
        startx = self.view_dlg.ui.startXLineEdit.text()
        endx = self.view_dlg.ui.endXLineEdit.text()
        starty = self.view_dlg.ui.startYLineEdit.text()
        endy = self.view_dlg.ui.endYLineEdit.text()
        # Only zoom if values are present
        if startx and starty:
            coords_f = [
                QgsPoint(float(startx), float(starty)),
                QgsPoint(float(endx), float(endy))
            ]
            geom = QgsGeometry().fromMultiPoint(coords_f)
            bbox = geom.boundingBox()
            self.iface.mapCanvas().setExtent(bbox)
            self.iface.mapCanvas().refresh()

    def complete(self):
        """
        Close the view form.
        """
        self.view_dlg.close()

    def whole_road_checkbox(self, row):
        """
        Sets whole road combo box based on value as it cannot be mapped.
        :param row: row in model
        """
        whole_rd = self.model.data(self.model.index(row, self.whole_road_col),
                                   Qt.DisplayRole)
        if whole_rd == 1 or str(whole_rd).lower() == "yes":
            self.view_dlg.ui.wholeRoadCheckBox.setChecked(True)
            self.view_dlg.ui.locationTextEdit.setPlainText("Whole road")
        else:
            self.view_dlg.ui.wholeRoadCheckBox.setChecked(False)

    def hide_buttons(self):
        """
        Hide buttons
        """
        self.view_dlg.ui.editLinkPushButton.setVisible(False)
        self.view_dlg.ui.editCoordsPushButton.setVisible(False)

    def setup_mapper(self):
        """
        Create the data widget mapper and set a proxy on the model
        """
        self.mapper = QDataWidgetMapper()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.model)
        self.proxy.setDynamicSortFilter(True)
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        # Set custom delegate for mapping to date widgets
        self.mapper.setItemDelegate(DateMapperCustomDelegate(self.date_cols))
        self.map_widgets(self.mapper)

    def map_widgets(self, mapper):
        """
        Map widgets to columns
        :param mapper: QDataWidgetMapper
        """
        for w in self.widgets:
            if w.mapped:
                mapper.addMapping(w.widget, w.db_col)
Esempio n. 28
0
    def __init__(self, server=None, parent=None):
        """The `ServerDialog` constructor.

        Parameters:

        - `serverList`: a `ServerList` instance containing the list of
          available servers.
        - `server`: the name of a server. If provided, this server will
          be selected in the serverList view.
        """
        super(ServerDialog, self).__init__(parent)
        self.setupUi(self)

        self.networkIcon.setPixmap(pixmapFromTheme(
            'preferences-system-network',
            ':/icons/48/preferences-system-network')
        )
        self.authIcon.setPixmap(pixmapFromTheme(
            'preferences-other',
            ':/icons/48/preferences-other')
        )
        self.securityIcon.setPixmap(pixmapFromTheme(
            'preferences-system',
            ':/icons/48/preferences-system')
        )
        
        self.__serverList = ServerList() #Load the serverlist from disk.
        self.__serverListCopy = None # When we click "Save", the current list is saved here
        
        # The list actually returned to the caller. Could be the copy or current active list
        self.__returnList = None 

        # Create the model used by the views and connect signals for registering
        # changes (to define the "Cancel"-buttons behaviour).
        self.slm = ServerListModel(self.__serverList, self)
        self.slm.dataChanged.connect(self.wasChanged)
        self.slm.rowsInserted.connect(self.wasChanged)
        self.slm.rowsRemoved.connect(self.wasChanged)
        
        # Used for determining if we should confirm cancel
        self.isChanged = False

        # The serverListView works on the servermodel
        self.serverListView.setModel(self.slm)

        # Enable/disable editing depending on if we have a server to edit
        if self.slm.hasServers():
            self.tabWidget.setEnabled(True)
            self.testConnectionButton.setEnabled(True)
        else:
            self.tabWidget.setEnabled(False)
            self.testConnectionButton.setEnabled(False)

        self.splitter.setStretchFactor(1, 0)

        # Update list of baseDNs on serverchange
        self.serverListView.selectionModel().selectionChanged.connect(self.setBaseDN) #Same as below

        # Map columns of the model to fields in the gui
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.slm)
        
        # The delegate handles the comboboxes and to-from the list of custom baseDNs
        # (delegate is used manually for the baseDNs)
        self.serverDelegate = ServerDelegate()
        self.mapper.setItemDelegate(self.serverDelegate)
        self.mapper.addMapping(self.hostEdit, 1)
        self.mapper.addMapping(self.portSpinBox, 2)
        self.mapper.addMapping(self.bindAnonBox, 3)
        self.mapper.addMapping(self.baseDNBox, 4)
        self.mapper.addMapping(self.bindAsEdit, 6)
        self.mapper.addMapping(self.passwordEdit, 7)
        self.mapper.addMapping(self.encryptionBox, 8)
        self.mapper.addMapping(self.mechanismBox, 9)
        self.mapper.addMapping(self.aliasBox, 10)
        self.mapper.addMapping(self.useClientCertBox, 11)
        self.mapper.addMapping(self.certFileEdit, 12)
        self.mapper.addMapping(self.certKeyfileEdit, 13)
        self.mapper.addMapping(self.validateBox, 14)

        # Workaround to ensure model being updated (Mac OS X bug)
        self.aliasBox.clicked.connect(self.aliasBox.setFocus)
        self.baseDNBox.clicked.connect(self.baseDNBox.setFocus)
        self.bindAnonBox.clicked.connect(self.bindAnonBox.setFocus)
        self.useClientCertBox.clicked.connect(self.useClientCertBox.setFocus)

        # Select the first servers (as the serverlistview does)
        self.mapper.setCurrentIndex(0)
        self.setBaseDN()

        # Let the mapper know when another server is selected in the list
        self.serverListView.selectionModel().currentRowChanged.connect(self.mapper.setCurrentModelIndex)
        
        # Enable checks for SSL enabled but with a non-standard port.
        self.encryptionBox.activated[int].connect(self.checkSSLport)

        # Used by the connection-test
        self.testProgress = QProgressDialog("Trying to connect to server.",
                "Abort",
                0, 0,
                self)
        self.testProgress.setWindowModality(Qt.WindowModal)

        # If a servername is supplied we try to get its index, 
        # And make it selected, else we select the first server
        # in the model)
        if not server is None:
            serverIndex = self.__serverList.getIndexByName(server)
            if serverIndex == -1:
                serverIndex = 0
            index = self.serverListView.model().index(serverIndex, 0)
        else:
            index = self.serverListView.model().index(0, 0)
        # Select it in the view
        self.serverListView.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)
        self.serverListView.selectionModel().setCurrentIndex(index, QItemSelectionModel.ClearAndSelect)
Esempio n. 29
0
class QMapManager(QDialog):
	def __init__(self, config, parent=None):
		QDialog.__init__(self, parent)
		curdir = os.path.abspath(os.path.dirname(__file__))
		PyQt4.uic.loadUi(os.path.join(curdir,'manager.ui'), self)
		self.model = QStandardItemModel()
		self.projectsmodel = QStandardItemModel()
		self.projectlist.setModel(self.projectsmodel)
		self.clientlist.setModel(self.model)
		self.clientlist.selectionModel().selectionChanged.connect(self.update)
		self.installbutton.pressed.connect(self.installToClient)
		self.mapper = QDataWidgetMapper()
		self.mapper.setModel(self.model)
		self.mapper.addMapping(self.installpath, 1)
		self.config = config
		self.populateProjects()
		self.populateClients()
		
	def installToClient(self):
		index = self.clientlist.selectionModel().currentIndex()
		item = self.model.itemFromIndex(index)
		print "Deploying to " + item.text()
		build.deployTargetByName(item.text())

	def update(self, selected, deselected ):
		index = selected.indexes()[0]
		self.mapper.setCurrentModelIndex(index)
		item = self.model.itemFromIndex(index)
		settings = item.data()

		for row in xrange(0,self.projectsmodel.rowCount()):
			index = self.projectsmodel.index(row, 0)
			item = self.projectsmodel.itemFromIndex(index)
			item.setCheckState(Qt.Unchecked)

		projects = settings['projects']
		
		for project in projects:
			if project == "All":
				i = 0
				while self.projectsmodel.item(i):
					item = self.projectsmodel.item(i)
					item.setCheckState(Qt.Checked)
					i += 1
				break
			
			projectitem = self.projectsmodel.findItems(project)[0]
		 	projectitem.setCheckState(Qt.Checked)
				
	def populateClients(self):
		row = 0
		for client, settings in self.config['clients'].iteritems():
			name = QStandardItem(client)
			name.setData(settings)
			path = QStandardItem(settings['path'])
			self.model.insertRow(row, [name, path])
			row += 1

	def populateProjects(self):
		row = 0
		for project in getProjects():
			projectitem = QStandardItem(project.name)
			projectitem.setCheckable(True)
			self.projectsmodel.insertRow(row, projectitem)
			row += 1
Esempio n. 30
0
class Base(QMainWindow):
    """
    Esta clase sirve de base para todos aquellos 
    formularios que siguen el estandar de dos pestañas, una para navegación
    y otra para edición
    """

    orientation = QPrinter.Portrait
    pageSize = QPrinter.Letter
    web = ""

    def __init__(self, parent, own_toolbar=False):
        """
        @param parent: El widget padre de esta ventana
        @param own_toolbar: Si este widget dibujara su toolbar en el padre o en el mismo
        @type parent: QWidget
        @type own_toolbar: bool
        """
        super(Base, self).__init__(parent)
        self.user = user.LoggedUser
        self._status = True
        self.parentWindow = parent
        self.own_toolbar = own_toolbar

        self.database = QSqlDatabase.database()
        """
        @type: QSqlDatabase
        @ivar: La base de datos a la cual se conecta el sistema
        """

        self.mapper = QDataWidgetMapper(self)
        u"""
        @type: QDataWidgetMapper
        @ivar: El mapper que se encarga de asignar los 
        datos del modelo de navegación a los distintos widgets
        """

        self.printProgressBar = QProgressBar(self)
        self.webview = QWebView()
        """
        @ivar: EL objeto webview usado para cargar los reportes
        @type: QWebView
        """
        self.loaded = False
        """
        @ivar: Si se pudo o no cargar un reporte
        @type: bool
        """

        self.startUi()

        self.editmodel = None
        self.printer = QPrinter()

        self._status = False

    def startUi(self):
        """
        Iniciar todos los elementos graficos
        """
        self.setupUi(self)
        if not self.own_toolbar:
            self.parent().addToolBar(self.toolBar)
            self.removeToolBar(self.toolBar)

        settings = QSettings()
        self.restoreState(settings.value(self.windowTitle() + "/State").toByteArray())

        """
        @ivar: El MainWindow al que pertenece este widget
        """
        self.createActions()

        self.printProgressBar.setVisible(False)

        _tab1shortcut = QShortcut(QKeySequence("Ctrl+1"), self, functools.partial(self.tabWidget.setCurrentIndex, 0))
        _tab2shortcut = QShortcut(QKeySequence("Ctrl+2"), self, functools.partial(self.tabWidget.setCurrentIndex, 1))

        self.mapper.currentIndexChanged[int].connect(self.updateDetailFilter)

        self.actionCut.setVisible(False)
        self.actionPaste.setVisible(False)
        self.actionCopy.setVisible(False)

    def closeEvent(self, event):
        u"""
        Guardar el tamaño, la posición en la pantalla y la posición de
         la barra de tareas
        Preguntar si realmente se desea cerrar la pestaña cuando
         se esta en modo edición
        """
        if not self.status:
            if (
                not QMessageBox.question(
                    self, qApp.organizationName(), u"¿Está seguro que desea salir?", QMessageBox.Yes | QMessageBox.No
                )
                == QMessageBox.Yes
            ):
                event.ignore()

        # Guardar el tamaño y la posición
        settings = QSettings()
        settings.setValue(self.windowTitle() + "/Geometry", self.saveGeometry())

        if not self.own_toolbar:
            self.parent().mdiArea().parent().parent().removeToolBar(self.toolBar)

    def editCell(self):
        """
        Editar la celda actualmente seleccionada de self.tableedit
        """
        self.tabledetails.edit(self.tabledetails.selectionModel().currentIndex())

    @pyqtSlot(QDateTime)
    @if_edit_model
    def on_dtPicker_dateTimeChanged(self, datetime):
        """
        Cambiar el tipo de cambio del modelo de edición si cambia la fecha
        @param datetime: La fecha contenida en self.dtPicker
        @type datetime: QDateTime
        """
        query = QSqlQuery()
        try:
            if not self.database.isOpen():
                if not self.database.open():
                    raise Exception(
                        "No se pudo conectar a la base de " + "datos para recuperar los tipos " + "de cambio"
                    )

            q = """
                SELECT idtc, tasa
                FROM tiposcambio
                WHERE fecha = %s
                LIMIT 1
            """ % datetime.toString(
                "yyyyMMdd"
            )

            if not query.exec_(q):

                raise UserWarning("No se pudieron recuperar los tipos de " + "cambio")
            if not query.size() == 1:
                logging.critical(u"La consulta para obtener tipos de " + "cambio no devolvio exactamente un valor")
                raise UserWarning(u"Hubo un error al obtener los tipos " + "de cambio")

            query.first()
            self.editmodel.exchangeRateId = query.value(0).toInt()[0]
            self.editmodel.exchangeRate = Decimal(query.value(1).toString())

            # self.editmodel.setData( self.editmodel.index( 0, 0 ), self.editmodel.index( 0, 0 ).data() )

            self.editmodel.datetime = datetime
        except UserWarning as inst:
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            self.dtPicker.setDateTime(self.editmodel.datetime)
            logging.error(inst)
            logging.error(query.lastError().text())
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), u"Hubo un error al obtener los tipos de" + " cambio")
            logging.critical(query.lastError().text())
            logging.critical(inst)
            self.dtPicker.setDateTime(self.editmodel.datetime)

    def navigate(self, to):
        """
        Esta funcion se encarga de navegar entro los distintos documentos
        @param to: es una string que puede tomar los valores 'next' 'previous'
         'first' 'last'
        """
        if self.mapper.currentIndex != -1:
            row = self.mapper.currentIndex()
            if to == "next":
                row += 1
                if row >= self.navproxymodel.rowCount():
                    row = self.navproxymodel.rowCount() - 1
                self.mapper.setCurrentIndex(row)
            elif to == "previous":
                if row <= 1:
                    row = 0
                else:
                    row = row - 1
                self.mapper.setCurrentIndex(row)
            elif to == "first":
                self.mapper.toFirst()
            elif to == "last":
                self.mapper.toLast()
        else:
            self.mapper.toLast()()

        if self.tabledetails != None:
            self.tabledetails.resizeColumnsToContents()
            self.tabledetails.horizontalHeader().setStretchLastSection(True)
        self.tablenavigation.selectRow(self.mapper.currentIndex())

    def updateDetailFilter(self, _index):
        """
        Esta función se debe implementar en los formularios para que al 
        navegar se actualize el filtro de la tabla detalles
        @param index: Este es el indice del mapper en el que actualmente 
        se encuentra navegando
        @type index: int 
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha " + "sido implementada")
        raise NotImplementedError()

    def loadModels(self):
        """
        Esta función se ejecuta en el constructor del formulario mediante
        un QTimer, carga los formularios por primera vez
        """
        self.updateModels()

        self.navigate("last")
        self.status = True

    def _setStatus(self, stat):
        """
        @param stat:  False = editando, True = navegando
        @type stat: bool
        """
        self._status = stat
        self.setControls(self._status)

    def _getStatus(self):
        """
        esta propiedad cambia entre navegar y editar
        """
        return self._status

    status = property(_getStatus, _setStatus)

    @pyqtSlot(unicode)
    def on_txtSearch_textChanged(self, searchstring):
        """
        Cambiar el filtro para el navigation model
        @param searchstring: Es el contenido por el cual se va a 
        filtrar el modelo de navegación
        @type searchstring: string
        """
        self.navproxymodel.setFilterFixedString(searchstring)

    @pyqtSlot(QModelIndex)
    def on_tablenavigation_doubleClicked(self, index):
        """
        Al hacer doble click en la tabla de navegación el se cambia a la
        pestaña detalles mostrando el documento seleccionado
        @param index: El indice de la tabla en la que se dio doble click
        @type index: QModelIndex 
        """
        self.mapper.setCurrentIndex(index.row())
        self.tabWidget.setCurrentIndex(0)

    @pyqtSlot(QModelIndex)
    def on_tablenavigation_clicked(self, index):
        self.mapper.setCurrentIndex(index.row())

    def save(self, ask=True):
        """
        Guardar el documento actual
        @param ask: Si se deberia o no preguntar al usuario si 
            esta seguro antes de proceder
        @type ask: bool
        """
        if (
            ask == False
            or QMessageBox.question(
                self, qApp.organizationName(), u"¿Esta seguro que desea guardar?", QMessageBox.Yes | QMessageBox.No
            )
            == QMessageBox.Yes
        ):
            if self.editmodel.valid:
                if self.editmodel.save():
                    QMessageBox.information(self, qApp.organizationName(), u"El documento se ha guardado con éxito")
                    self.editmodel = None
                    self.updateModels()
                    self.navigate("last")
                    self.status = True
                else:
                    QMessageBox.critical(self, qApp.organizationName(), "Ha ocurrido un error al guardar el documento")

            else:
                try:
                    QMessageBox.warning(self, qApp.organizationName(), self.editmodel.validError)
                except AttributeError:
                    QMessageBox.warning(
                        self,
                        qApp.organizationName(),
                        u"El documento no puede guardarse" + " ya que la información no esta" + " completa",
                    )

    def setControls(self, unused_status):
        """
        Habilitar o deshabilitar los controles según status
        @param status: 
        @type status: bool
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    def addLine(self):
        """
        añadir una linea a table edit, solo se llama directamente 
        en una ocasion, al comenzar la edicion de un documento
        """
        row = self.editmodel.rowCount()
        self.editmodel.insertRows(row)

    def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered"):
        """
        Crear un objeto acción
        @param text: El texto de la acción
        @type text: string

        @param slot: El slot que se ejecutara cuando se dispare esta acción
        @type slot: callable

        @param shortcut: El acceso directo que tiene asignada esta acción
        @type shortcut: QKeySequence

        @param icon: El icono de esta acción
        @type icon: string

        @param tip: El tooltip que tendra esta acción
        @type tip: string

        @param checkable: Si esta acción es checkable o no
        @type checkable: bool

        @param signal: La señal en la que esta acción ejecutara el slot
        @type signal: string

        @rtype: QAction
        """
        action = QAction(text, self)
        if icon is not None:
            if type(icon) == QIcon:
                action.setIcon(icon)
            else:
                action.setIcon(QIcon(icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            getattr(action, signal).connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def newDocument(self):
        """
        Empezar la edición de un nuevo documento
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    def cancel(self):
        """
        Cancelar la edición del nuevo documento
        """
        QMessageBox.information(self, qApp.organizationName(), u"Esta parte del sistema no ha sido implementada")
        raise NotImplementedError()

    @property
    def printIdentifier(self):
        """
        La identificación de este documento para reporte,
         normalmente sera el iddocumento o el ndocimpreso
        @rtype:string
        """
        raise NotImplementedError(u"printIdentifier debe implementarse para " + "poder imprimir")

    def preview(self):
        """
        Muestra el dialogo de vista previa de impresión
        """
        try:
            printer = QPrinter()
            printer.setOrientation(self.orientation)
            printer.setPageSize(self.pageSize)
            web = self.web + self.printIdentifier
            report = reports.frmReportes(web, printer, self)
            report.exec_()
        except NotImplementedError as inst:
            QMessageBox.information(
                self, qApp.organizationName(), u"No se ha implementado la función de impresión para este modulo"
            )
            logging.error(unicode(inst))
        except UserWarning as inst:
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
            logging.error(unicode(inst))
        except Exception as inst:
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un error al intentar mostrar su reporte")
            logging.critical(unicode(inst))

    def printDocument(self):
        """
        Imprime el documento actual
        """
        try:

            base = reports.Reports.url

            if base == "":
                raise UserWarning(u"No existe una configuración para el " + "servidor de reportes")

            self.printer.setOrientation(self.orientation)
            self.printer.setPageSize(self.pageSize)

            web = base + self.web + self.printIdentifier + "&uname=" + self.user.user + "&hash=" + self.user.hash
            self.loaded = False

            self.webview.load(QUrl(web))

            self.webview.loadFinished[bool].connect(self.on_webview_loadFinished)
            self.webview.loadProgress[int].connect(self.on_webview_loadProgress)
        except NotImplementedError as inst:
            logging.error(unicode(inst))
            QMessageBox.information(
                self, qApp.organizationName(), u"La función de impresión no se ha " + "implementado para este modulo"
            )
        except UserWarning as inst:
            logging.error(unicode(inst))
            QMessageBox.critical(self, qApp.organizationName(), unicode(inst))
        except Exception as inst:
            logging.critical(unicode(inst))
            QMessageBox.critical(self, qApp.organizationName(), "Hubo un problema al intentar imprimir" + " su reporte")

    def on_webview_loadProgress(self, progress):
        """
        Muestra el progreso de la carga del reporte en un progressBar
        """
        self.printProgressBar.setValue(progress)

    def on_webview_loadFinished(self, status):
        if self.printProgressBar.isVisible():
            self.printProgressBar.hide()
        if not status:
            QMessageBox.critical(self, qApp.organizationName(), "El reporte no se pudo cargar")
            logging.error("No se pudo cargar el reporte")

        self.loaded = True

        printdialog = QPrintDialog(self.printer, self)
        if printdialog.exec_() == QDialog.Accepted:
            self.webview.print_(self.printer)

        del self.webview

    def deleteRow(self):
        """
        Funcion usada para borrar lineas de la tabla
        """
        index = self.tabledetails.currentIndex()

        if not index.isValid():
            return
        row = index.row()

        self.editmodel.removeRows(row, 1)
        self.updateLabels()

    def updateLabels(self):
        """
        Este metodo se llama para actualizar las etiquetas de totales en el
        formulario
        """
        raise NotImplementedError()

    def createActions(self):
        """
        Crea las acciones predefinidas del sistema
        """
        self.actionNew = self.createAction(
            text="Nuevo",
            tip="Crear un nuevo documento",
            icon=QIcon.fromTheme("document-new", QIcon(":/icons/res/document-new.png")),
            shortcut="Ctrl+n",
            slot=self.newDocument,
        )
        self.actionPreview = self.createAction(
            text="Previsualizar",
            tip=u"Vista de impresión del documento",
            icon=QIcon.fromTheme("document-preview", QIcon(":/icons/res/document-preview.png")),
            shortcut="Ctrl+p",
            slot=self.preview,
        )
        self.actionPrint = self.createAction(
            text="Imprimir",
            tip="Imprimir el documento",
            icon=QIcon.fromTheme("document-print", QIcon(":/icons/res/document-print.png")),
            slot=self.printDocument,
        )
        self.actionSave = self.createAction(
            text="Guardar",
            tip="Guardar el documento",
            icon=QIcon.fromTheme("document-save", QIcon(":/icons/res/document-save.png")),
            shortcut="Ctrl+g",
            slot=self.save,
        )
        self.actionCancel = self.createAction(
            text="Cancelar",
            tip=u"Cancelar la creación del nuevo documento",
            icon=QIcon.fromTheme("dialog-cancel", QIcon(":/icons/res/dialog-cancel.png")),
            shortcut="Esc",
            slot=self.cancel,
        )

        # edicion, TODO: QUE FUNCIONEN ESTAS ACCIONES
        self.actionCopy = self.createAction(
            text="Copiar", icon=QIcon.fromTheme("edit-copy", QIcon(":/icons/res/edit-copy.png")), shortcut="Ctrl+c"
        )
        self.actionCut = self.createAction(
            text="Cortar", icon=QIcon.fromTheme("edit-cut", QIcon(":/icons/res/edit-cut.png")), shortcut="Ctrl+x"
        )
        self.actionPaste = self.createAction(text="Pegar", icon=":/icons/res/edit-paste.png", shortcut="Ctrl+v")

        # navegación
        self.actionGoFirst = self.createAction(
            text="Primer documento",
            tip="Ir al primer documento",
            icon=QIcon.fromTheme("go-first", QIcon(":/icons/res/go-first.png")),
            slot=functools.partial(self.navigate, "first"),
        )
        self.actionGoPrevious = self.createAction(
            text="Documento anterior",
            tip="Ir al documento anterior",
            icon=QIcon.fromTheme("go-previous", QIcon(":/icons/res/go-previous.png")),
            slot=functools.partial(self.navigate, "previous"),
        )
        self.actionGoLast = self.createAction(
            text="Ultimo documento",
            tip="Ir al ultimo documento",
            icon=QIcon.fromTheme("go-last", QIcon(":/icons/res/go-last.png")),
            slot=functools.partial(self.navigate, "last"),
        )
        self.actionGoNext = self.createAction(
            text="Documento siguiente",
            tip="Ir al siguiente documento",
            icon=QIcon.fromTheme("go-next", QIcon(":/icons/res/go-next.png")),
            slot=functools.partial(self.navigate, "next"),
        )

        self.actionDeleteRow = self.createAction(
            text="Borrar la fila",
            icon=QIcon.fromTheme("edit-delete", QIcon(":/icons/res/edit-delete.png")),
            slot=self.deleteRow,
        )

        self.addActionsToToolBar()

    def addActionsToToolBar(self):
        """
        Añade las acciones predefinidas a la barra de tareas
        """
        self.toolBar.addActions(
            [self.actionNew, self.actionPreview, self.actionPrint, self.actionSave, self.actionCancel]
        )
        self.toolBar.addSeparator()

        self.toolBar.addActions(
            [self.actionGoFirst, self.actionGoPrevious, self.actionGoLast, self.actionGoNext, self.actionGoLast]
        )

    @pyqtSlot()
    @if_edit_model
    def on_txtObservations_textChanged(self):
        """
        Asignar las observaciones al editmodel
        """
        self.editmodel.observations = self.txtObservations.toPlainText().strip()
Esempio n. 31
0
class RdpolyRecordEditor(object):
    """
    Handles forms and database connections for editing RAMP features.
    """
    dlg = None
    rdpoly_model = None
    rdpoly_mapper = None
    mcl_model = None
    mcl_mapper = None

    def __init__(self, db, selector_tool, iface):
        self.db = db
        self.selector_tool = selector_tool
        self.iface = iface
        self.prepare_dialog()
        self.connect_signals()

    def prepare_dialog(self):
        """
        Prepare MCL edit dialog including setting comobox entries and
        validation.
        :return: RampMclEditorDlg
        """
        self.dlg = RampRdpolyEditorDlg()
        self.dlg.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.dlg.move(5, 5)
        self.set_combobox_items()
        self.set_dialog_validators()

    def set_combobox_items(self):
        """
        Populate the items in the comboboxes.
        """
        self.dlg.ui.elementComboBox.addItems([''] + ELEMENT_VALUES)
        self.dlg.ui.hierarchyComboBox.addItems([''] + HIERARCHY_VALUES)
        self.dlg.ui.offsetComboBox.addItems([''] + OFFSET_VALUES)

    def set_dialog_validators(self):
        """
        Add validators to the free-text fields of the dialog.
        """
        self.dlg.ui.numberLineEdit.setValidator(
            QRegExpValidator(QRegExp(r"\d{0,3}")))

    def connect_signals(self):
        """
        Connect GUI signals and slots.  Extends parent class function
        """
        # GUI controls
        self.selector_tool.selected_id.connect(self.select_record)
        save_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Save)
        cancel_button = self.dlg.ui.buttonBox.button(QDialogButtonBox.Cancel)
        save_button.clicked.connect(self.save_record)
        cancel_button.clicked.connect(self.close_tool)
        # reject() is called if user presses escape
        self.dlg.rejected.connect(self.close_tool)

        # Auto updates on combined ref line edit
        self.dlg.ui.numberLineEdit.textChanged.connect(
            self.update_combined_ref)
        self.dlg.ui.elementComboBox.currentIndexChanged.connect(
            self.update_combined_ref)
        self.dlg.ui.elementComboBox.currentIndexChanged.connect(
            self.set_length_readonly_state)
        self.dlg.ui.hierarchyComboBox.currentIndexChanged.connect(
            self.update_combined_ref)
        self.dlg.ui.offsetComboBox.currentIndexChanged.connect(
            self.update_combined_ref)

    def select_record(self, rd_pol_id):
        """
        Update the GUI to populate with data from the chosen record.  Show if
        not already visible.
        :param rd_pol_id: int, emitted by selector_tool
        """
        try:
            self.setup_models_and_mappers(rd_pol_id)
        except rn_except.RampNoLinkedPolyPopupError:
            return

        self.set_length_readonly_state()

        if not self.dlg.isVisible():
            # Emit the index changed symbol so update_combined_ref() is triggered,
            # ensuring combined ref box is populated on initial load
            self.dlg.ui.elementComboBox.currentIndexChanged.emit(
                self.dlg.ui.elementComboBox.currentIndex())
            self.dlg.show()

    def close_tool(self):
        """
        Close the dialog, reverting unsaved changes.
        """
        self.mcl_mapper.revert()
        self.rdpoly_mapper.revert()
        self.dlg.hide()

    def save_record(self):
        """
        Save changes to the record, then close dialog.
        """
        self.mcl_mapper.submit()
        self.rdpoly_mapper.submit()
        self.update_label_fields()
        self.update_ref_3()
        self.iface.mapCanvas().refresh()
        self.dlg.hide()

    def setup_models_and_mappers(self, rd_pol_id):
        """
        Load the table data for selected record into a model and map to widgets.
        """
        self.setup_rdpoly_model_and_mapper(rd_pol_id)
        mcl_ref = self.get_mcl_ref_from_rd_pol_id(rd_pol_id)
        self.setup_mcl_model_and_mapper(mcl_ref)

    def get_mcl_ref_from_rd_pol_id(self, rd_pol_id):
        """
        Query database to get mcl_ref associated with given polygon
        :param rd_pol_id: str, id number
        :return mcl_ref: str, id number
        """
        sql = """
            SELECT mcl_cref FROM rdpoly
            WHERE rd_pol_id = {}""".format(rd_pol_id)
        query = QSqlQuery(sql, self.db)

        if not query.first():
            msg = "No MCLs are linked to polygon {}".format(rd_pol_id)
            raise rn_except.RampNoLinkedPolyPopupError(msg)

        mcl_ref = query.record().value('mcl_cref')
        if isinstance(mcl_ref, QPyNullVariant):
            msg = "No MCLs are linked to polygon {}".format(rd_pol_id)
            raise rn_except.RampNoLinkedPolyPopupError(msg)

        return str(mcl_ref)

    def set_length_readonly_state(self):
        """
        Make the length lineedit writeable for non-MCL fields
        """
        element_value = self.dlg.ui.elementComboBox.currentText()
        delegate = self.rdpoly_mapper.itemDelegate()
        element_key = get_key(delegate.element_codes, element_value)

        if element_key in ('CGWAY', 'FPATH'):
            self.dlg.ui.lengthLineEdit.setReadOnly(True)
            self.dlg.ui.lengthLineEdit.setStyleSheet("""
                border-width: 0.5px;
                border-style: solid;
                border-radius: 2px;
                border-color: rgb(100, 100, 100);
                background-color: rgb(213, 234, 234);""")
        else:
            self.dlg.ui.lengthLineEdit.setReadOnly(False)
            self.dlg.ui.lengthLineEdit.setStyleSheet("")

    def update_label_fields(self):
        """
        Update the label columns of the rdpoly table based on new values
        """
        element = self.rdpoly_data(ELEMENT)
        side = self.rdpoly_data(OFFSET)
        number = self.rdpoly_data(DESC_3)
        if isinstance(number, QPyNullVariant) or number in (0, ''):
            label = "/{}".format(element)
            label1 = "/{}/{}".format(element, side)
        else:
            label = "/{}/{}".format(element, number)
            label1 = "/{}/{}/{}".format(element, side, number)

        self.rdpoly_model.setData(self.rdpoly_model.index(0, LABEL), label)
        self.rdpoly_model.setData(self.rdpoly_model.index(0, LABEL1), label1)
        self.rdpoly_model.submit()

    def update_ref_3(self):
        """
        Update the ref_3 column of rdpoly with value from desc_3.
        """
        number = self.rdpoly_data(DESC_3)
        self.rdpoly_model.setData(self.rdpoly_model.index(0, REF_3), number)
        self.rdpoly_model.submit()

    def setup_rdpoly_model_and_mapper(self, rd_pol_id):
        """
        Load the data for the Polygon portion of the form
        :param rd_pol_id: str rd_pol_id
        :return:
        """
        # Set up model
        self.rdpoly_model = QSqlTableModel(db=self.db)
        self.rdpoly_model.setTable('rdpoly')
        self.rdpoly_model.setFilter("rd_pol_id = {}".format(int(rd_pol_id)))
        self.rdpoly_model.select()
        if self.rdpoly_model.rowCount() != 1:
            msg = "Table rdpoly query for rd_pol_id = {} returned {} rows".format(
                rd_pol_id, self.rdpoly_model.rowCount())
            raise rn_except.RdpolyFormBadRdpolyRefError(msg)

        # Set up rdpoly_mapper
        self.rdpoly_mapper = QDataWidgetMapper()
        self.rdpoly_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.rdpoly_mapper.setModel(self.rdpoly_model)
        self.rdpoly_mapper.addMapping(self.dlg.ui.rdpolyLineEdit, RD_POL_ID)
        self.rdpoly_mapper.addMapping(self.dlg.ui.numberLineEdit, DESC_3)
        self.rdpoly_mapper.addMapping(self.dlg.ui.elementComboBox, ELEMENT)
        self.rdpoly_mapper.addMapping(self.dlg.ui.hierarchyComboBox, HIERARCHY)
        self.rdpoly_mapper.addMapping(self.dlg.ui.offsetComboBox, OFFSET)
        self.rdpoly_mapper.setItemDelegate(RdpolyEditorDelegate(self.dlg))
        self.rdpoly_mapper.toFirst()

    def setup_mcl_model_and_mapper(self, mcl_ref):
        """
        Load the data for the MCL portion of the form
        :param mcl_ref: str mcl_ref
        :return:
        """
        # Set up model
        self.mcl_model = QSqlTableModel(db=self.db)
        self.mcl_model.setTable('mcl')
        self.mcl_model.setFilter("mcl_ref = {}".format(int(mcl_ref)))
        self.mcl_model.select()
        if self.mcl_model.rowCount() != 1:
            msg = "MCL query for mcl_ref = {} returned {} rows".format(
                mcl_ref, self.mcl_model.rowCount())
            raise rn_except.RdpolyFormBadMclRefError(msg)

        # Set up mcl_mapper
        self.mcl_mapper = QDataWidgetMapper()
        self.mcl_mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mcl_mapper.setModel(self.mcl_model)
        self.mcl_mapper.addMapping(self.dlg.ui.mclLineEdit, MCL_REF)
        self.mcl_mapper.addMapping(self.dlg.ui.usrnLineEdit, USRN)
        self.mcl_mapper.addMapping(self.dlg.ui.lorDescPlainTextEdit, LOR_DESC)
        self.mcl_mapper.addMapping(self.dlg.ui.laneNumberLineEdit, LANE_NUMBER)
        self.mcl_mapper.addMapping(self.dlg.ui.speedLineEdit, SPEED_LIMIT)
        self.mcl_mapper.toFirst()

    def update_combined_ref(self):
        """
        Update combinedRefLineEdit with value derived from other fields.
        """
        if self.mcl_model is None:
            # This happens if signal calls function before model created
            return

        # Get strings from MCLs
        mcl_ref1 = self.mcl_data(LOR_REF_1)
        mcl_ref2 = self.mcl_data(LOR_REF_2)

        # Get strings from rdpoly
        delegate = self.rdpoly_mapper.itemDelegate()
        element_value = self.dlg.ui.elementComboBox.currentText()
        element_key = get_key(delegate.element_codes, element_value)
        offset_value = self.dlg.ui.offsetComboBox.currentText()
        offset_key = get_key(delegate.offset_codes, offset_value)
        number = self.dlg.ui.numberLineEdit.text()

        new_text = "{}/{}/{}/{}/{}".format(mcl_ref1, mcl_ref2, element_key,
                                           offset_key, number)
        self.dlg.ui.combinedRefLineEdit.setText(new_text)

    def rdpoly_data(self, column):
        return self.rdpoly_model.data(self.rdpoly_model.index(0, column))

    def mcl_data(self, column):
        return self.mcl_model.data(self.mcl_model.index(0, column))
Esempio n. 32
0
class TalkEditorApp(FreeseerApp):
    '''Freeseer talk database editor main gui class'''
    def __init__(self, config, db):
        FreeseerApp.__init__(self)

        self.config = config
        self.db = db

        icon = QIcon()
        icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)
        self.resize(960, 600)

        #
        # Setup Layout
        #
        self.mainWidget = QWidget()
        self.mainLayout = QVBoxLayout()
        self.mainWidget.setLayout(self.mainLayout)
        self.setCentralWidget(self.mainWidget)
        self.mainLayout.setAlignment(Qt.AlignTop)

        # Add custom widgets
        self.commandButtons = CommandButtons()
        self.tableView = QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.talkDetailsWidget = TalkDetailsWidget()
        self.importTalksWidget = ImportTalksWidget()
        self.newTalkWidget = NewTalkWidget()
        self.mainLayout.addWidget(self.importTalksWidget)
        #self.mainLayout.addLayout(self.titleLayout)
        self.mainLayout.addWidget(self.commandButtons)
        self.mainLayout.addWidget(self.tableView)
        self.mainLayout.addWidget(self.talkDetailsWidget)
        self.mainLayout.addWidget(self.importTalksWidget)
        # --- End Layout

        # Initialize geometry, to be used for restoring window positioning.
        self.geometry = None

        #
        # Setup Menubar
        #
        self.actionExportCsv = QAction(self)
        self.actionExportCsv.setObjectName('actionExportCsv')
        self.actionRemoveAll = QAction(self)
        self.actionRemoveAll.setObjectName('actionRemoveAll')

        # Actions
        self.menuFile.insertAction(self.actionExit, self.actionExportCsv)
        self.menuFile.insertAction(self.actionExit, self.actionRemoveAll)
        # --- End Menubar

        #
        # TableView Connections
        #
        self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected)
        self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected)

        # Import Widget
        self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import)
        self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks)
        self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget)
        self.importTalksWidget.setHidden(True)
        self.connect(self.importTalksWidget.csvFileSelectButton, SIGNAL('clicked()'), self.csv_file_select)
        self.connect(self.importTalksWidget.csvLineEdit, SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.importTalksWidget.rssLineEdit, SIGNAL('returnPressed()'),
            self.importTalksWidget.importButton.click)
        self.connect(self.actionExportCsv, SIGNAL('triggered()'), self.export_talks_to_csv)
        self.connect(self.actionRemoveAll, SIGNAL('triggered()'), self.confirm_reset)

        # Command Buttons
        self.connect(self.commandButtons.addButton, SIGNAL('clicked()'), self.show_new_talk_popup)
        self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk)
        self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset)
        self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget)
        self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv)
        self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks)

        # Talk Details Buttons
        self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.update_talk)

        # Talk Details Widget
        self.connect(self.talkDetailsWidget.titleLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.presenterLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.categoryLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.eventLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.roomLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.descriptionTextEdit, SIGNAL('modificationChanged(bool)'), self.enable_save)
        self.connect(self.talkDetailsWidget.dateEdit, SIGNAL('dateChanged(const QDate)'), self.enable_save)
        self.connect(self.talkDetailsWidget.startTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save)
        self.connect(self.talkDetailsWidget.endTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save)

        # New Talk Widget
        self.newTalkWidget.connect(self.newTalkWidget.addButton, SIGNAL('clicked()'), self.add_talk)
        self.newTalkWidget.connect(self.newTalkWidget.cancelButton, SIGNAL('clicked()'), self.newTalkWidget.reject)

        # Load default language
        actions = self.menuLanguage.actions()
        for action in actions:
            if action.data().toString() == self.config.default_language:
                action.setChecked(True)
                self.translate(action)
                break

        # Load Talk Database
        self.load_presentations_model()

        # Setup Autocompletion
        self.update_autocomplete_fields()

        self.talkDetailsWidget.saveButton.setEnabled(False)

        # Select first item
        #self.tableView.setCurrentIndex(self.proxy.index(0,0))
        #self.talk_selected(self.proxy.index(0,0))

    #
    # Translation
    #
    def retranslate(self):
        self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor"))

        #
        # Reusable Strings
        #
        self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database")
        self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp",
                                                               "Are you sure you want to clear the DB?")
        self.confirmTalkDetailsClearTitleString = self.app.translate("TalkEditorApp", "Unsaved Data")
        self.confirmTalkDetailsClearQuestionString = self.app.translate("TalkEditorApp",
                                                                        "Unsaved talk details will be lost. Continue?")
        # --- End Reusable Strings

        #
        # Menubar
        #
        self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV"))
        self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks"))

        # --- End Menubar

        #
        # TalkDetailsWidget
        #
        self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title"))
        self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter"))
        self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category"))
        self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event"))
        self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room"))
        self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date"))
        self.talkDetailsWidget.startTimeLabel.setText(self.app.translate("TalkEditorApp", "Start Time"))
        self.talkDetailsWidget.endTimeLabel.setText(self.app.translate("TalkEditorApp", "End Time"))
        # --- End TalkDetailsWidget

        #
        # Import Talks Widget Translations
        #
        self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL"))
        self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File"))
        self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        # --- End Talks Widget Translations

        #
        # Command Button Translations\
        #
        self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import"))
        self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export"))
        self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add New Talk"))
        self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove"))
        self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All"))
        # --- End Command Butotn Translations

        #
        # Search Widget Translations
        #
        self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search"))
        # --- End Command Button Translations

    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8)
        self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        #self.speakerList = QStringList(self.db.get_speaker_list())
        #self.categoryList = QStringList(self.db.get_category_list())
        #self.eventList = QStringList(self.db.get_event_list())
        #self.roomList = QStringList(self.db.get_room_list())

        #Disble input
        self.talkDetailsWidget.disable_input_fields()

    def search_talks(self):
        # The default value is 0. If the value is -1, the keys will be read from all columns.
        self.proxy.setFilterKeyColumn(-1)
        self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text())

    def talk_selected(self, model):
        self.mapper.setCurrentIndex(model.row())
        self.talkDetailsWidget.enable_input_fields()
        self.talkDetailsWidget.saveButton.setEnabled(False)

    def toggle_import(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.importTalksWidget.csvLineEdit.setEnabled(True)
            self.importTalksWidget.csvFileSelectButton.setEnabled(True)
            self.importTalksWidget.rssLineEdit.setEnabled(False)
        else:
            self.importTalksWidget.csvLineEdit.setEnabled(False)
            self.importTalksWidget.csvFileSelectButton.setEnabled(False)
            self.importTalksWidget.rssLineEdit.setEnabled(True)

    def show_import_talks_widget(self):
        self.commandButtons.setHidden(True)
        self.tableView.setHidden(True)
        self.talkDetailsWidget.setHidden(True)
        self.importTalksWidget.setHidden(False)

    def hide_import_talks_widget(self):
        self.commandButtons.setHidden(False)
        self.tableView.setHidden(False)
        self.talkDetailsWidget.setHidden(False)
        self.importTalksWidget.setHidden(True)

    def add_talk(self):
        """Adds a new talk to the database using data from the NewTalkWidget input fields"""
        presentation = self.create_presentation(self.newTalkWidget.talkDetailsWidget)

        if presentation:
            self.db.insert_presentation(presentation)
            self.newTalkWidget.accept()  # Close the dialog

    def update_talk(self):
        """Updates the currently selected talk using data from the TalkEditorApp input fields"""
        selected_talk = self.tableView.currentIndex()
        if selected_talk.row() >= 0:  # The tableView index begins at 0 and is -1 by default
            talk_id = selected_talk.sibling(selected_talk.row(), 0).data().toString()
            presentation = self.create_presentation(self.talkDetailsWidget)

            if presentation:
                self.db.update_presentation(talk_id, presentation)
                self.apply_changes(selected_talk)
                self.talkDetailsWidget.saveButton.setEnabled(False)

    def create_presentation(self, talkDetailsWidget):
        """Creates and returns an instance of Presentation using data from the input fields"""
        date = talkDetailsWidget.dateEdit.date()
        startTime = talkDetailsWidget.startTimeEdit.time()
        endTime = talkDetailsWidget.endTimeEdit.time()

        title = unicode(talkDetailsWidget.titleLineEdit.text()).strip()
        if title:
            return Presentation(
                unicode(talkDetailsWidget.titleLineEdit.text()).strip(),
                unicode(talkDetailsWidget.presenterLineEdit.text()).strip(),
                unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(),
                unicode(talkDetailsWidget.categoryLineEdit.text()).strip(),
                unicode(talkDetailsWidget.eventLineEdit.text()).strip(),
                unicode(talkDetailsWidget.roomLineEdit.text()).strip(),
                unicode(date.toString(Qt.ISODate)),
                unicode(startTime.toString(Qt.ISODate)),
                unicode(endTime.toString(Qt.ISODate)))

    def show_new_talk_popup(self):
        """Displays a modal dialog with a talk details view

        When Add is selected, a new talk is added to the database using the input field data.
        When Cancel is selected, no talk is added.
        """
        log.info('Opening Add Talk window...')
        self.clear_new_talk_fields()
        self.remove_new_talk_placeholder_text()
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus()
        if self.newTalkWidget.exec_() == 1:
            self.apply_changes()
            self.talkDetailsWidget.disable_input_fields()
        else:
            log.info('No talk added...')

    def apply_changes(self, updated_talk=None):
        """Repopulates the model to display the effective changes

        Updates the autocomplete fields.
        Displays the updated model in the table view, and selects the newly updated/added talk.
        """
        self.presentationModel.select()
        self.select_talk(updated_talk)
        self.update_autocomplete_fields()

    def select_talk(self, talk=None):
        """Selects the given talk in the table view

        If no talk is given, the last row in the table view is selected.
        """
        if talk:
            row = talk.row()
            column = talk.column()
        else:
            row = self.presentationModel.rowCount() - 1  # Select last row
            column = 0

        self.tableView.selectRow(row)
        self.tableView.setCurrentIndex(self.proxy.index(row, column))
        self.talk_selected(self.proxy.index(row, column))

    def remove_talk(self):
        try:
            rows_selected = self.tableView.selectionModel().selectedRows()
        except:
            return

        # Reversed because rows in list change position once row is removed
        for row in reversed(rows_selected):
            self.presentationModel.removeRow(row.row())

    def load_talk(self):
        try:
            self.tableView.currentIndex().row()
        except:
            return

        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.presentationModel.select()

    def reset(self):
        self.db.clear_database()
        self.presentationModel.select()

    def confirm_reset(self):
        """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database.
        If Yes call the reset() function"""
        confirm = QMessageBox.question(self,
                                       self.confirmDBClearTitleString,
                                       self.confirmDBClearQuestionString,
                                       QMessageBox.Yes |
                                       QMessageBox.No,
                                       QMessageBox.No)

        if confirm == QMessageBox.Yes:
            self.reset()

    def add_talks_from_rss(self):
        rss_url = unicode(self.importTalksWidget.rssLineEdit.text())
        if rss_url:
            self.db.add_talks_from_rss(rss_url)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please enter a RSS URL")
            error.exec_()

    def closeEvent(self, event):
        log.info('Exiting talk database editor...')
        self.geometry = self.saveGeometry()
        event.accept()

    def csv_file_select(self):
        fname = QFileDialog.getOpenFileName(
            self, 'Select file', "", "*.csv")
        if fname:
            self.importTalksWidget.csvLineEdit.setText(fname)

    def add_talks_from_csv(self):
        fname = self.importTalksWidget.csvLineEdit.text()

        if fname:
            self.db.add_talks_from_csv(fname)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please select a file")
            error.exec_()

    def import_talks(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.add_talks_from_csv()
        else:
            self.add_talks_from_rss()

        self.update_autocomplete_fields()

    def export_talks_to_csv(self):
        fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv")
        if fname:
            self.db.export_talks_to_csv(fname)

    def update_autocomplete_fields(self):
        self.titleList = QStringList(self.db.get_string_list("Title"))
        self.speakerList = QStringList(self.db.get_string_list("Speaker"))
        self.categoryList = QStringList(self.db.get_string_list("Category"))
        self.eventList = QStringList(self.db.get_string_list("Event"))
        self.roomList = QStringList(self.db.get_string_list("Room"))

        self.titleCompleter = QCompleter(self.titleList)
        self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.speakerCompleter = QCompleter(self.speakerList)
        self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.categoryCompleter = QCompleter(self.categoryList)
        self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.eventCompleter = QCompleter(self.eventList)
        self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.roomCompleter = QCompleter(self.roomList)
        self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive)

        self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter)
        self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter)
        self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter)
        self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter)
        self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter)

    def are_fields_enabled(self):
        return (self.talkDetailsWidget.titleLineEdit.isEnabled() and
                self.talkDetailsWidget.presenterLineEdit.isEnabled() and
                self.talkDetailsWidget.categoryLineEdit.isEnabled() and
                self.talkDetailsWidget.eventLineEdit.isEnabled() and
                self.talkDetailsWidget.roomLineEdit.isEnabled() and
                self.talkDetailsWidget.dateEdit.isEnabled() and
                self.talkDetailsWidget.startTimeEdit.isEnabled() and
                self.talkDetailsWidget.endTimeEdit.isEnabled())

    def unsaved_details_exist(self):
        """Checks if changes have been made to new/existing talk details

        Looks for text in the input fields and check the enabled state of the Save Talk button
        If the Save Talk button is enabled, the input fields contain modified values
        """
        return (self.talkDetailsWidget.saveButton.isEnabled() and
                (self.talkDetailsWidget.titleLineEdit.text() or
                self.talkDetailsWidget.presenterLineEdit.text() or
                self.talkDetailsWidget.categoryLineEdit.text() or
                self.talkDetailsWidget.descriptionTextEdit.toPlainText()))

    def enable_save(self):
        self.talkDetailsWidget.saveButton.setEnabled(True)

    def clear_new_talk_fields(self):
        """Removes existing data from all NewTalkWidget fields except event, room, date and time"""
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear()
        self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear()
        self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear()
        self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear()

    def remove_new_talk_placeholder_text(self):
        """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget"""
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText("")
        self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText("")
        self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText("")
        self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText("")
        self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText("")
Esempio n. 33
0
class QMapManager(QDialog):
    def __init__(self, config, parent=None):
        QDialog.__init__(self, parent)
        curdir = os.path.abspath(os.path.dirname(__file__))
        PyQt4.uic.loadUi(os.path.join(curdir, 'manager.ui'), self)
        self.model = QStandardItemModel()
        self.projectsmodel = QStandardItemModel()
        self.projectlist.setModel(self.projectsmodel)
        self.clientlist.setModel(self.model)
        self.clientlist.selectionModel().selectionChanged.connect(self.update)
        self.installbutton.pressed.connect(self.installToClient)
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.model)
        self.mapper.addMapping(self.installpath, 1)
        self.config = config
        self.populateProjects()
        self.populateClients()

    def installToClient(self):
        index = self.clientlist.selectionModel().currentIndex()
        item = self.model.itemFromIndex(index)
        print "Deploying to " + item.text()
        build.deployTargetByName(item.text())

    def update(self, selected, deselected):
        index = selected.indexes()[0]
        self.mapper.setCurrentModelIndex(index)
        item = self.model.itemFromIndex(index)
        settings = item.data()

        for row in xrange(0, self.projectsmodel.rowCount()):
            index = self.projectsmodel.index(row, 0)
            item = self.projectsmodel.itemFromIndex(index)
            item.setCheckState(Qt.Unchecked)

        projects = settings['projects']

        for project in projects:
            if project == "All":
                i = 0
                while self.projectsmodel.item(i):
                    item = self.projectsmodel.item(i)
                    item.setCheckState(Qt.Checked)
                    i += 1
                break

            projectitem = self.projectsmodel.findItems(project)[0]
            projectitem.setCheckState(Qt.Checked)

    def populateClients(self):
        row = 0
        for client, settings in self.config['clients'].iteritems():
            name = QStandardItem(client)
            name.setData(settings)
            path = QStandardItem(settings['path'])
            self.model.insertRow(row, [name, path])
            row += 1

    def populateProjects(self):
        row = 0
        for project in getProjects():
            projectitem = QStandardItem(project.name)
            projectitem.setCheckable(True)
            self.projectsmodel.insertRow(row, projectitem)
            row += 1
Esempio n. 34
0
class TalkEditorApp(FreeseerApp):
    '''Freeseer talk database editor main gui class'''
    def __init__(self, config, db):
        super(TalkEditorApp, self).__init__(config)

        self.db = db

        icon = QIcon()
        icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)
        self.resize(960, 600)

        #
        # Setup Layout
        #
        self.mainWidget = QWidget()
        self.mainLayout = QVBoxLayout()
        self.mainWidget.setLayout(self.mainLayout)
        self.setCentralWidget(self.mainWidget)
        self.mainLayout.setAlignment(Qt.AlignTop)

        # Add custom widgets
        self.commandButtons = CommandButtons()
        self.tableView = QTableView()
        self.tableView.setSortingEnabled(True)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.talkDetailsWidget = TalkDetailsWidget()
        self.importTalksWidget = ImportTalksWidget()
        self.newTalkWidget = NewTalkWidget()
        self.mainLayout.addWidget(self.importTalksWidget)
        #self.mainLayout.addLayout(self.titleLayout)
        self.mainLayout.addWidget(self.commandButtons)
        self.mainLayout.addWidget(self.tableView)
        self.mainLayout.addWidget(self.talkDetailsWidget)
        self.mainLayout.addWidget(self.importTalksWidget)
        # --- End Layout

        # Keep track of index of the most recently selected talk
        self.currentTalkIndex = QPersistentModelIndex()

        # Prompt user to "Continue Editing", "Discard Changes" or "Save Changes"
        self.savePromptBox = QMessageBox()
        self.savePromptBox.setWindowTitle("Unsaved Changes Exist")
        self.savePromptBox.setIcon(QMessageBox.Information)
        self.savePromptBox.setText(
            "The talk you were editing has unsaved changes.")
        self.continueButton = self.savePromptBox.addButton(
            "Continue Editing", QMessageBox.RejectRole)
        self.discardButton = self.savePromptBox.addButton(
            "Discard Changes", QMessageBox.DestructiveRole)
        self.saveButton = self.savePromptBox.addButton("Save Changes",
                                                       QMessageBox.AcceptRole)
        self.savePromptBox.setDefaultButton(self.saveButton)

        # Initialize geometry, to be used for restoring window positioning.
        self.geometry = None

        #
        # Setup Menubar
        #
        self.actionExportCsv = QAction(self)
        self.actionExportCsv.setObjectName('actionExportCsv')
        self.actionRemoveAll = QAction(self)
        self.actionRemoveAll.setObjectName('actionRemoveAll')

        # Actions
        self.menuFile.insertAction(self.actionExit, self.actionExportCsv)
        self.menuFile.insertAction(self.actionExit, self.actionRemoveAll)
        # --- End Menubar

        #
        # TableView Connections
        #
        self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'),
                     self.click_talk)
        self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'),
                     self.click_talk)
        self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'),
                     self.click_talk)

        # Import Widget
        self.connect(self.importTalksWidget.csvRadioButton,
                     SIGNAL('toggled(bool)'), self.toggle_import)
        self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'),
                     self.import_talks)
        self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'),
                     self.hide_import_talks_widget)
        self.importTalksWidget.setHidden(True)
        self.connect(self.importTalksWidget.csvFileSelectButton,
                     SIGNAL('clicked()'), self.csv_file_select)
        self.connect(self.importTalksWidget.csvLineEdit,
                     SIGNAL('returnPressed()'),
                     self.importTalksWidget.importButton.click)
        self.connect(self.importTalksWidget.rssLineEdit,
                     SIGNAL('returnPressed()'),
                     self.importTalksWidget.importButton.click)
        self.connect(self.actionExportCsv, SIGNAL('triggered()'),
                     self.export_talks_to_csv)
        self.connect(self.actionRemoveAll, SIGNAL('triggered()'),
                     self.confirm_reset)

        # Command Buttons
        self.connect(self.commandButtons.addButton, SIGNAL('clicked()'),
                     self.click_add_button)
        self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'),
                     self.remove_talk)
        self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'),
                     self.confirm_reset)
        self.connect(self.commandButtons.importButton, SIGNAL('clicked()'),
                     self.show_import_talks_widget)
        self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'),
                     self.export_talks_to_csv)
        self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'),
                     self.search_talks)
        self.connect(self.commandButtons.searchLineEdit,
                     SIGNAL('textEdited(QString)'), self.search_talks)
        self.connect(self.commandButtons.searchLineEdit,
                     SIGNAL('returnPressed()'), self.search_talks)

        # Talk Details Buttons
        self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'),
                     self.update_talk)

        # Talk Details Widget
        self.connect(self.talkDetailsWidget.titleLineEdit,
                     SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.presenterLineEdit,
                     SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.categoryLineEdit,
                     SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.eventLineEdit,
                     SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.roomLineEdit,
                     SIGNAL('textEdited(const QString)'), self.enable_save)
        self.connect(self.talkDetailsWidget.descriptionTextEdit,
                     SIGNAL('modificationChanged(bool)'), self.enable_save)
        self.connect(self.talkDetailsWidget.dateEdit,
                     SIGNAL('dateChanged(const QDate)'), self.enable_save)
        self.connect(self.talkDetailsWidget.startTimeEdit,
                     SIGNAL('timeChanged(const QTime)'), self.enable_save)
        self.connect(self.talkDetailsWidget.endTimeEdit,
                     SIGNAL('timeChanged(const QTime)'), self.enable_save)

        # New Talk Widget
        self.newTalkWidget.connect(self.newTalkWidget.addButton,
                                   SIGNAL('clicked()'), self.add_talk)
        self.newTalkWidget.connect(self.newTalkWidget.cancelButton,
                                   SIGNAL('clicked()'),
                                   self.newTalkWidget.reject)

        # Load default language
        actions = self.menuLanguage.actions()
        for action in actions:
            if action.data().toString() == self.config.default_language:
                action.setChecked(True)
                self.translate(action)
                break

        # Load Talk Database
        self.load_presentations_model()

        # Setup Autocompletion
        self.update_autocomplete_fields()

        self.talkDetailsWidget.saveButton.setEnabled(False)

        # Select first item
        #self.tableView.setCurrentIndex(self.proxy.index(0,0))
        #self.talk_selected(self.proxy.index(0,0))

    #
    # Translation
    #
    def retranslate(self):
        self.setWindowTitle(
            self.app.translate("TalkEditorApp", "Freeseer Talk Editor"))

        #
        # Reusable Strings
        #
        self.confirmDBClearTitleString = self.app.translate(
            "TalkEditorApp", "Remove All Talks from Database")
        self.confirmDBClearQuestionString = self.app.translate(
            "TalkEditorApp", "Are you sure you want to clear the DB?")
        self.confirmTalkDetailsClearTitleString = self.app.translate(
            "TalkEditorApp", "Unsaved Data")
        self.confirmTalkDetailsClearQuestionString = self.app.translate(
            "TalkEditorApp", "Unsaved talk details will be lost. Continue?")
        # --- End Reusable Strings

        #
        # Menubar
        #
        self.actionExportCsv.setText(
            self.app.translate("TalkEditorApp", "&Export to CSV"))
        self.actionRemoveAll.setText(
            self.app.translate("TalkEditorApp", "&Remove All Talks"))

        # --- End Menubar

        #
        # TalkDetailsWidget
        #
        self.talkDetailsWidget.titleLabel.setText(
            self.app.translate("TalkEditorApp", "Title"))
        self.talkDetailsWidget.presenterLabel.setText(
            self.app.translate("TalkEditorApp", "Presenter"))
        self.talkDetailsWidget.categoryLabel.setText(
            self.app.translate("TalkEditorApp", "Category"))
        self.talkDetailsWidget.eventLabel.setText(
            self.app.translate("TalkEditorApp", "Event"))
        self.talkDetailsWidget.roomLabel.setText(
            self.app.translate("TalkEditorApp", "Room"))
        self.talkDetailsWidget.dateLabel.setText(
            self.app.translate("TalkEditorApp", "Date"))
        self.talkDetailsWidget.startTimeLabel.setText(
            self.app.translate("TalkEditorApp", "Start Time"))
        self.talkDetailsWidget.endTimeLabel.setText(
            self.app.translate("TalkEditorApp", "End Time"))
        # --- End TalkDetailsWidget

        #
        # Import Talks Widget Translations
        #
        self.importTalksWidget.rssRadioButton.setText(
            self.app.translate("TalkEditorApp", "RSS URL"))
        self.importTalksWidget.csvRadioButton.setText(
            self.app.translate("TalkEditorApp", "CSV File"))
        self.importTalksWidget.importButton.setText(
            self.app.translate("TalkEditorApp", "Import"))
        # --- End Talks Widget Translations

        #
        # Command Button Translations\
        #
        self.commandButtons.importButton.setText(
            self.app.translate("TalkEditorApp", "Import"))
        self.commandButtons.exportButton.setText(
            self.app.translate("TalkEditorApp", "Export"))
        self.commandButtons.addButton.setText(
            self.app.translate("TalkEditorApp", "Add New Talk"))
        self.commandButtons.removeButton.setText(
            self.app.translate("TalkEditorApp", "Remove"))
        self.commandButtons.removeAllButton.setText(
            self.app.translate("TalkEditorApp", "Remove All"))
        # --- End Command Butotn Translations

        #
        # Search Widget Translations
        #
        self.commandButtons.searchButton.setText(
            self.app.translate("TalkEditorApp", "Search"))
        # --- End Command Button Translations

    def load_presentations_model(self):
        # Load Presentation Model
        self.presentationModel = self.db.get_presentations_model()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.presentationModel)
        self.tableView.setModel(self.proxy)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)

        # Fill table whitespace.
        self.tableView.horizontalHeader().setStretchLastSection(False)
        self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)

        # Hide the ID field
        self.tableView.setColumnHidden(0, True)

        # Map data to widgets
        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1)
        self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2)
        self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4)
        self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5)
        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3)
        self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7)
        self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8)
        self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9)

        # Load StringLists
        self.titleList = QStringList(self.db.get_string_list("Title"))
        #self.speakerList = QStringList(self.db.get_speaker_list())
        #self.categoryList = QStringList(self.db.get_category_list())
        #self.eventList = QStringList(self.db.get_event_list())
        #self.roomList = QStringList(self.db.get_room_list())

        #Disble input
        self.talkDetailsWidget.disable_input_fields()

    def search_talks(self):
        # The default value is 0. If the value is -1, the keys will be read from all columns.
        self.proxy.setFilterKeyColumn(-1)
        self.proxy.setFilterFixedString(
            self.commandButtons.searchLineEdit.text())

    def show_save_prompt(self):
        """Prompts the user to save or discard changes, or continue editing."""
        self.savePromptBox.exec_()
        self.savePromptBox.setDefaultButton(self.saveButton)
        return self.savePromptBox.clickedButton()

    def click_talk(self, model):
        """Warns user if there are unsaved changes, and selects talk clicked by the user."""
        log.info("Selecting row %d", model.row())
        modelRow = model.row()
        if self.unsaved_details_exist():
            log.info("Unsaved changes exist in row %d",
                     self.currentTalkIndex.row())
            confirm = self.show_save_prompt()
            if confirm == self.saveButton:
                log.info("Saving changes in row %d...",
                         self.currentTalkIndex.row())
                self.tableView.selectRow(self.currentTalkIndex.row())
                self.update_talk()
                newModel = self.tableView.currentIndex().sibling(modelRow, 0)
                self.select_talk(newModel)
            elif confirm == self.discardButton:
                log.info("Discarding changes in row %d...",
                         self.currentTalkIndex.row())
                self.talk_selected(model)
            else:
                log.info("Continue editing row %d",
                         self.currentTalkIndex.row())
                self.tableView.selectRow(self.currentTalkIndex.row())
        else:
            self.talk_selected(model)

    def click_add_button(self):
        """Warns user if there are unsaved changes, and shows the New Talk window."""
        if self.unsaved_details_exist():
            log.info("Unsaved changes exist in row %d",
                     self.currentTalkIndex.row())
            confirm = self.show_save_prompt()
            if confirm == self.saveButton:
                log.info("Saving changes in row %d...",
                         self.currentTalkIndex.row())
                self.update_talk()
                self.show_new_talk_popup()
            elif confirm == self.discardButton:
                log.info("Discarding changes in row %d...",
                         self.currentTalkIndex.row())
                # Ensure that changes are discarded
                self.talk_selected(self.currentTalkIndex)
                self.show_new_talk_popup()
            else:
                log.info("Continue editing row %d",
                         self.currentTalkIndex.row())
        else:
            self.show_new_talk_popup()

    def talk_selected(self, model):
        self.mapper.setCurrentIndex(model.row())
        self.talkDetailsWidget.enable_input_fields()
        self.talkDetailsWidget.saveButton.setEnabled(False)
        self.currentTalkIndex = QPersistentModelIndex(model)

    def toggle_import(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.importTalksWidget.csvLineEdit.setEnabled(True)
            self.importTalksWidget.csvFileSelectButton.setEnabled(True)
            self.importTalksWidget.rssLineEdit.setEnabled(False)
        else:
            self.importTalksWidget.csvLineEdit.setEnabled(False)
            self.importTalksWidget.csvFileSelectButton.setEnabled(False)
            self.importTalksWidget.rssLineEdit.setEnabled(True)

    def show_import_talks_widget(self):
        self.commandButtons.setHidden(True)
        self.tableView.setHidden(True)
        self.talkDetailsWidget.setHidden(True)
        self.importTalksWidget.setHidden(False)

    def hide_import_talks_widget(self):
        self.commandButtons.setHidden(False)
        self.tableView.setHidden(False)
        self.talkDetailsWidget.setHidden(False)
        self.importTalksWidget.setHidden(True)

    def add_talk(self):
        """Adds a new talk to the database using data from the NewTalkWidget input fields"""
        presentation = self.create_presentation(
            self.newTalkWidget.talkDetailsWidget)

        if presentation:
            self.db.insert_presentation(presentation)
            self.newTalkWidget.accept()  # Close the dialog

    def update_talk(self):
        """Updates the currently selected talk using data from the TalkEditorApp input fields"""
        selected_talk = self.tableView.currentIndex()
        if selected_talk.row(
        ) >= 0:  # The tableView index begins at 0 and is -1 by default
            talk_id = selected_talk.sibling(selected_talk.row(),
                                            0).data().toString()
            presentation = self.create_presentation(self.talkDetailsWidget)

            if presentation:
                self.db.update_presentation(talk_id, presentation)
                self.apply_changes(selected_talk)
                self.talkDetailsWidget.saveButton.setEnabled(False)

    def create_presentation(self, talkDetailsWidget):
        """Creates and returns an instance of Presentation using data from the input fields"""
        date = talkDetailsWidget.dateEdit.date()
        startTime = talkDetailsWidget.startTimeEdit.time()
        endTime = talkDetailsWidget.endTimeEdit.time()

        title = unicode(talkDetailsWidget.titleLineEdit.text()).strip()
        if title:
            return Presentation(
                unicode(talkDetailsWidget.titleLineEdit.text()).strip(),
                unicode(talkDetailsWidget.presenterLineEdit.text()).strip(),
                unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()).
                strip(),
                unicode(talkDetailsWidget.categoryLineEdit.text()).strip(),
                unicode(talkDetailsWidget.eventLineEdit.text()).strip(),
                unicode(talkDetailsWidget.roomLineEdit.text()).strip(),
                unicode(date.toString(Qt.ISODate)),
                unicode(startTime.toString(Qt.ISODate)),
                unicode(endTime.toString(Qt.ISODate)))

    def show_new_talk_popup(self):
        """Displays a modal dialog with a talk details view

        When Add is selected, a new talk is added to the database using the input field data.
        When Cancel is selected, no talk is added.
        """
        log.info('Opening Add Talk window...')
        self.clear_new_talk_fields()
        self.remove_new_talk_placeholder_text()
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus()
        if self.newTalkWidget.exec_() == 1:
            self.apply_changes()
            self.talkDetailsWidget.disable_input_fields()
        else:
            log.info('No talk added...')

    def apply_changes(self, updated_talk=None):
        """Repopulates the model to display the effective changes

        Updates the autocomplete fields.
        Displays the updated model in the table view, and selects the newly updated/added talk.
        """
        self.presentationModel.select()
        self.select_talk(updated_talk)
        self.update_autocomplete_fields()

    def select_talk(self, talk=None):
        """Selects the given talk in the table view

        If no talk is given, the last row in the table view is selected.
        """
        if talk:
            row = talk.row()
            column = talk.column()
        else:
            row = self.presentationModel.rowCount() - 1  # Select last row
            column = 0

        self.tableView.selectRow(row)
        self.tableView.setCurrentIndex(self.proxy.index(row, column))
        self.talk_selected(self.proxy.index(row, column))

    def remove_talk(self):
        try:
            rows_selected = self.tableView.selectionModel().selectedRows()
        except:
            return

        # Reversed because rows in list change position once row is removed
        for row in reversed(rows_selected):
            self.presentationModel.removeRow(row.row())
        self.talkDetailsWidget.clear_input_fields()
        self.talkDetailsWidget.disable_input_fields()

    def load_talk(self):
        try:
            self.tableView.currentIndex().row()
        except:
            return

        self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6)
        self.presentationModel.select()

    def reset(self):
        self.db.clear_database()
        self.presentationModel.select()
        self.talkDetailsWidget.clear_input_fields()
        self.talkDetailsWidget.disable_input_fields()

    def confirm_reset(self):
        """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database.
        If Yes call the reset() function"""
        confirm = QMessageBox.question(self, self.confirmDBClearTitleString,
                                       self.confirmDBClearQuestionString,
                                       QMessageBox.Yes | QMessageBox.No,
                                       QMessageBox.No)

        if confirm == QMessageBox.Yes:
            self.reset()

    def add_talks_from_rss(self):
        rss_url = unicode(self.importTalksWidget.rssLineEdit.text())
        if rss_url:
            self.db.add_talks_from_rss(rss_url)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please enter a RSS URL")
            error.exec_()

    def closeEvent(self, event):
        if self.unsaved_details_exist():
            log.info("Unsaved changes exist in row %d",
                     self.currentTalkIndex.row())
            confirm = self.show_save_prompt()
            if confirm == self.saveButton:
                log.info("Saving changes in row %d...",
                         self.currentTalkIndex.row())
                self.update_talk()
                log.info('Exiting talk database editor...')
                self.geometry = self.saveGeometry()
                event.accept()
            elif confirm == self.discardButton:
                log.info("Discarding changes in row %d...",
                         self.currentTalkIndex.row())
                # Ensure that changes are discarded
                self.talk_selected(self.currentTalkIndex)
                log.info('Exiting talk database editor...')
                self.geometry = self.saveGeometry()
                event.accept()
            else:
                log.info("Continue editing row %d",
                         self.currentTalkIndex.row())
                event.ignore()
        else:
            log.info('Exiting talk database editor...')
            self.geometry = self.saveGeometry()
            event.accept()

    def csv_file_select(self):
        fname = QFileDialog.getOpenFileName(self, 'Select file', "", "*.csv")
        if fname:
            self.importTalksWidget.csvLineEdit.setText(fname)

    def add_talks_from_csv(self):
        fname = self.importTalksWidget.csvLineEdit.text()

        if fname:
            self.db.add_talks_from_csv(fname)
            self.presentationModel.select()
            self.hide_import_talks_widget()
        else:
            error = QMessageBox()
            error.setText("Please select a file")
            error.exec_()

    def import_talks(self):
        if self.importTalksWidget.csvRadioButton.isChecked():
            self.add_talks_from_csv()
        else:
            self.add_talks_from_rss()

        self.update_autocomplete_fields()

    def export_talks_to_csv(self):
        fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv")
        if fname:
            self.db.export_talks_to_csv(fname)

    def update_autocomplete_fields(self):
        self.titleList = QStringList(self.db.get_string_list("Title"))
        self.speakerList = QStringList(self.db.get_string_list("Speaker"))
        self.categoryList = QStringList(self.db.get_string_list("Category"))
        self.eventList = QStringList(self.db.get_string_list("Event"))
        self.roomList = QStringList(self.db.get_string_list("Room"))

        self.titleCompleter = QCompleter(self.titleList)
        self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.speakerCompleter = QCompleter(self.speakerList)
        self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.categoryCompleter = QCompleter(self.categoryList)
        self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.eventCompleter = QCompleter(self.eventList)
        self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive)
        self.roomCompleter = QCompleter(self.roomList)
        self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive)

        self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter)
        self.talkDetailsWidget.presenterLineEdit.setCompleter(
            self.speakerCompleter)
        self.talkDetailsWidget.categoryLineEdit.setCompleter(
            self.categoryCompleter)
        self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter)
        self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter)

    def are_fields_enabled(self):
        return (self.talkDetailsWidget.titleLineEdit.isEnabled()
                and self.talkDetailsWidget.presenterLineEdit.isEnabled()
                and self.talkDetailsWidget.categoryLineEdit.isEnabled()
                and self.talkDetailsWidget.eventLineEdit.isEnabled()
                and self.talkDetailsWidget.roomLineEdit.isEnabled()
                and self.talkDetailsWidget.dateEdit.isEnabled()
                and self.talkDetailsWidget.startTimeEdit.isEnabled()
                and self.talkDetailsWidget.endTimeEdit.isEnabled())

    def unsaved_details_exist(self):
        """Checks if changes have been made to new/existing talk details

        Looks for text in the input fields and check the enabled state of the Save Talk button
        If the Save Talk button is enabled, the input fields contain modified values
        """
        return (self.talkDetailsWidget.saveButton.isEnabled() and
                (self.talkDetailsWidget.titleLineEdit.text()
                 or self.talkDetailsWidget.presenterLineEdit.text()
                 or self.talkDetailsWidget.categoryLineEdit.text()
                 or self.talkDetailsWidget.descriptionTextEdit.toPlainText()))

    def enable_save(self):
        self.talkDetailsWidget.saveButton.setEnabled(True)

    def clear_new_talk_fields(self):
        """Removes existing data from all NewTalkWidget fields except event, room, date and time"""
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear()
        self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear()
        self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear()
        self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear()

    def remove_new_talk_placeholder_text(self):
        """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget"""
        self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText(
            "")
        self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText(
            "")
        self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText(
            "")
        self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText(
            "")
        self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText(
            "")
Esempio n. 35
0
class StreetBrowser:
    def __init__(self, iface, street_browser, model, db, params):
        # Local ref to street browsers dock and iface
        self.street_browser = street_browser
        self.iface = iface
        self.model = model
        self.db = db
        self.params = params
        self.fltr_street_rcd_dlg = FilterStreetRecordsDlg()
        # Connect db
        self.mapper = None
        self.proxy = None
        self.setup_proxy_and_mapper()
        self.show_street = None
        # Display first record on load
        self.mapper.toFirst()
        # Create instance of editing class
        self.modify = EditRecord(self.iface, self.street_browser, self.model,
                                 self.mapper, self.db, self.params)
        self.modify.edit_signals.currentIndexSet.connect(self.disable_close)
        self.add = AddRecord(self.iface, self.street_browser, self.model,
                             self.mapper, self.db, self.params)
        self.close = CloseRecord(self.iface, self.street_browser, self.model,
                                 self.mapper, self.db, self.params)
        # Create instance of filter pop class
        self.pop_filter_table = PopulateFilterTableView(
            self, self.fltr_street_rcd_dlg, self.db, self.model)
        self.canvas_functs = ZoomSelectCanvas(self.iface, self.street_browser,
                                              self.db)
        self.srwr = ScottishRoadWorksRegister(self.street_browser, self.db,
                                              self.iface, self.params)
        self.srwr.tab_idx_changed(0)
        self.connect_model_navigation()

    def setup_proxy_and_mapper(self):
        """
        Map data fields to widgets in street browser and create proxy for filtering
        """
        self.mapper = QDataWidgetMapper()
        self.proxy = QSortFilterProxyModel()
        self.proxy.setSourceModel(self.model)
        self.proxy.setDynamicSortFilter(True)
        self.mapper.setModel(self.proxy)
        self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
        # Set custom delegate for mapping to date widgets
        self.mapper.setItemDelegate(DateMapperCustomDelegate([6, 7, 8, 18]))
        self.mapper.currentIndexChanged.connect(self.mapper_idx_changed)
        self.map_widgets(self.mapper)

    def view_record(self):
        """
        Changes current displayed record to one from xref table
        """
        try:
            indexes = self.street_browser.ui.crossReferenceTableView.selectedIndexes(
            )
            view_usrn = indexes[0].data()
            row_count = self.model.rowCount()
            counter = 0
            match = False
            while counter <= row_count and not match:
                idx = self.model.index(counter, 1)
                usrn = idx.data()
                counter += 1
                if view_usrn == usrn:
                    match = True
                    self.mapper.setCurrentIndex(idx.row())
        except IndexError:
            pass

    def mapper_idx_changed(self):
        """
        Remove abandoned 'show' geom and populate x-ref table
        """
        if str(self.street_browser.ui.showPushButton.text()).lower() == 'hide':
            self.show_street.remove()
            self.street_browser.ui.showPushButton.setText('Show')
        usrn = self.street_browser.ui.usrnLineEdit.text()
        xref = CrossRefTable(self.db, self.street_browser)
        xref.populate_cross_ref(usrn)
        self.populate_linked_esu_list()
        self.srwr_tab_repopulate()
        self.disable_close(usrn)

    def populate_linked_esu_list(self):
        """
        Populate the linked ESU list in the street browser
        """
        self.street_browser.ui.linkEsuListWidget.clear()
        # Add new linked esu's
        self.gn_fnc = ZoomSelectCanvas(self.iface, self.street_browser,
                                       self.db)
        esu_list = self.gn_fnc.query_esu(
            self.street_browser.ui.usrnLineEdit.text())
        for esu_id in esu_list:
            QListWidgetItem(str(esu_id),
                            self.street_browser.ui.linkEsuListWidget)

    def set_buttons_initial_state(self, role):
        """
        checks the role of the user and enables/disables buttons accordingly
        if usrn button is already disabled it leaves it alone because usrn
        is linked to other categories
        :param role: user role
        :return: void
        """
        if role == 'admin' or role == 'editor':
            state = True
        else:
            state = False
        self.street_browser.ui.modifyPushButton.setEnabled(state)
        self.street_browser.ui.addPushButton.setEnabled(state)
        if self.street_browser.ui.closeOpPushButton.isEnabled():
            self.street_browser.ui.closeOpPushButton.setEnabled(state)

    def connect_model_navigation(self):
        """
        Connect record navigation buttons to widgetmapper functions
        """
        self.street_browser.ui.firstPushButton.clicked.connect(
            self.mapper.toFirst)
        self.street_browser.ui.lastPushButton.clicked.connect(
            self.mapper.toLast)
        self.street_browser.ui.previousPushButton.clicked.connect(
            self.mapper.toPrevious)
        self.street_browser.ui.nextPushButton.clicked.connect(
            self.mapper.toNext)
        # Connect filter btn to filter dlg
        self.street_browser.ui.filterPushButton.clicked.connect(
            self.filter_street_records)
        # Connect close button and map button
        kwargs = {'zoom_to': True, 'select': True, 'close': False}
        self.street_browser.ui.mapPushButton.clicked.connect(
            lambda: self.canvas_functs.zoom_to_record(**kwargs))
        self.street_browser.ui.viewPushButton.clicked.connect(self.view_record)
        self.street_browser.ui.showPushButton.clicked.connect(
            self.show_street_coordinates)
        # Connect modify button
        self.street_browser.ui.modifyPushButton.clicked.connect(
            self.modify_record)
        self.street_browser.ui.addPushButton.clicked.connect(self.add_record)
        self.street_browser.ui.closeOpPushButton.clicked.connect(
            self.close_record)
        # Connect SRWR tab
        self.street_browser.ui.srwrPushButton.clicked.connect(self.enable_srwr)
        # connect the default close button
        self.street_browser.signals.closed_sb.connect(self.remove_coords)

    def srwr_tab_repopulate(self):
        """
        Repopulate SRWR tab if appropriate
        """
        if self.street_browser.ui.srwrRecordsGroupBox.isVisible():
            cur_tab = self.street_browser.ui.srwrTabWidget.currentIndex()
            if not self.srwr:
                self.srwr = ScottishRoadWorksRegister(self.street_browser,
                                                      self.db, self.iface,
                                                      self.params)
            self.srwr.tab_idx_changed(cur_tab)

    def filter_street_records(self):
        self.fltr_street_rcd_dlg.exec_(
        )  # DO NOT USE .show() FOR CHILD PROCESSES!

    def enable_srwr(self):
        """
        Toggles visibility of SRWR Records group
        """
        if self.street_browser.ui.srwrRecordsGroupBox.isVisible():
            self.street_browser.ui.srwrRecordsGroupBox.setVisible(False)
            self.street_browser.ui.srwrPushButton.setText("Show SRWR Details")
        else:
            self.street_browser.ui.srwrRecordsGroupBox.setVisible(True)
            self.street_browser.ui.srwrPushButton.setText("Hide SRWR Details")
            if not self.srwr:
                # Mimic tab change to populate the default tab
                self.srwr = ScottishRoadWorksRegister(self.street_browser,
                                                      self.db, self.iface,
                                                      self.params)
            self.srwr.tab_idx_changed(0)

    def show_street_coordinates(self):
        if str(self.street_browser.ui.showPushButton.text()).lower() == "show":
            startx = self.street_browser.ui.startXLineEdit.text()
            endx = self.street_browser.ui.endXLineEdit.text()
            starty = self.street_browser.ui.startYLineEdit.text()
            endy = self.street_browser.ui.endYLineEdit.text()
            coords = ((startx, starty), (endx, endy))
            if coords[0][0] and coords[1][0]:
                self.show_street = ShowStreetCoordinates(self.iface)
                self.show_street.show(coords)
                self.street_browser.ui.showPushButton.setText('Hide')
        else:
            self.show_street.remove()
            self.street_browser.ui.showPushButton.setText('Show')

    def modify_record(self):
        """
        Modify a an existing street record
        """
        if not self.is_layer_editing():
            self.modify.modify_record()

    def add_record(self):
        """
        Add a new new record
        """
        if not self.is_layer_editing():
            self.add.add()

    def close_record(self):
        """
        Close an existing street record
        """
        if not self.is_layer_editing():
            self.close.close()

    def is_layer_editing(self):
        """
        Checks if either the rd poly layer or esu layer are currently in editing state.
        :return: True if editing
        """
        esu_layer = QgsMapLayerRegistry.instance().mapLayersByName(
            'ESU Graphic')[0]
        rdpoly_layer = QgsMapLayerRegistry.instance().mapLayersByName(
            'Road Polygons')[0]
        if esu_layer.isEditable() or rdpoly_layer.isEditable():
            no_add_esu_layer_msg_box = QMessageBox(
                QMessageBox.Warning, '',
                'Cannot modify street record while editing layers',
                QMessageBox.Ok, None)
            no_add_esu_layer_msg_box.setWindowFlags(Qt.CustomizeWindowHint
                                                    | Qt.WindowTitleHint)
            no_add_esu_layer_msg_box.exec_()
            return True
        else:
            return False

    def goto_record(self, index):
        """
        Navigate to a specific index in the model
        :param index: model idx
        """
        self.mapper.setCurrentIndex(index)

    def remove_coords(self):
        """
        remove the start/end coords from the canvas when the street browser is closed
        from the default button
        """
        if self.show_street:
            self.show_street.remove()
        if self.street_browser.ui.showPushButton.text() == "Hide":
            self.street_browser.ui.showPushButton.setText("Show")

    def map_widgets(self, mapper):
        """
        Map widgets to columns
        :param mapper: Data widget mapper
        """
        mapper.addMapping(self.street_browser.ui.classLineEdit,
                          19)  # street_class
        mapper.addMapping(self.street_browser.ui.versionLineEdit,
                          2)  # version_no
        mapper.addMapping(self.street_browser.ui.typeLineEdit,
                          4)  # street_ref_type
        mapper.addMapping(self.street_browser.ui.descriptionTextEdit,
                          5)  # description
        mapper.addMapping(self.street_browser.ui.localityLineEdit,
                          20)  # loc_ref
        mapper.addMapping(self.street_browser.ui.townLineEdit, 22)  # town_ref
        mapper.addMapping(self.street_browser.ui.countyLineEdit,
                          21)  # county_ref
        mapper.addMapping(self.street_browser.ui.authorityLineEdit,
                          9)  # authority
        mapper.addMapping(self.street_browser.ui.byLineEdit, 23)  # updated_by
        mapper.addMapping(self.street_browser.ui.updateDateLineEdit,
                          7)  # update_date
        mapper.addMapping(self.street_browser.ui.startDateLineEdit,
                          8)  # start_date
        mapper.addMapping(self.street_browser.ui.entryDateLineEdit,
                          6)  # entry_date
        mapper.addMapping(self.street_browser.ui.startXLineEdit,
                          11)  # start_xref
        mapper.addMapping(self.street_browser.ui.startYLineEdit,
                          12)  # start_yref
        mapper.addMapping(self.street_browser.ui.tolLineEdit, 15)  # tolerance
        mapper.addMapping(self.street_browser.ui.endXLineEdit, 13)  # end_xref
        mapper.addMapping(self.street_browser.ui.endYLineEdit, 14)  # end_yref
        mapper.addMapping(self.street_browser.ui.stateLineEdit,
                          17)  # street_state
        mapper.addMapping(self.street_browser.ui.stateDateLineEdit,
                          18)  # street_date
        mapper.addMapping(self.street_browser.ui.usrnLineEdit, 1)  # USRN

    @pyqtSlot(str)
    def disable_close(self, usrn):
        """
        disables the delete button
        in case a street is linked to other categories
        :param usrn : [str] the usrn of the current record in widget mapper
        """
        usrn_num_str = "SELECT (SELECT COUNT (usrn) FROM tblSPEC_DES WHERE usrn = {} AND currency_flag = 0) + " \
                       "(SELECT COUNT (usrn) FROM tblMAINT WHERE usrn = {} AND currency_flag = 0) + " \
                       "(SELECT COUNT (usrn) FROM tblREINS_CAT WHERE usrn = {} AND currency_flag = 0) AS NoUSRN"\
                       .format(usrn, usrn, usrn)
        usrn_num_query = QSqlQuery(usrn_num_str, self.db)
        usrn_num_query.first()
        linked_usrn_num = usrn_num_query.value(0)
        if linked_usrn_num > 0 or self.params['role'] == 'readonly':
            self.street_browser.ui.closeOpPushButton.setEnabled(False)
        else:
            self.street_browser.ui.closeOpPushButton.setEnabled(True)