Example #1
0
class DlgSelectInvoice( QDialog ):
    def __init__( self, parent = None ):
        super( DlgSelectInvoice, self ).__init__( parent )
        self.billsmodel = QSqlQueryModel()
        query = """
        SELECT * FROM (
            SELECT
                factura.iddocumento,
                CONCAT_WS(' ', tdc.descripcion, factura.ndocimpreso) AS 'Numero de Factura',
                factura.fechacreacion AS 'Fecha',
                p.nombre AS 'Cliente',
                -SUM(axd.unidades) -
            IFNULL((
                SELECT
                SUM(axddev.unidades)
                FROM documentos devoluciones
                JOIN docpadrehijos dpddev ON devoluciones.iddocumento = dpddev.idhijo
                JOIN articulosxdocumento axddev ON axddev.iddocumento = devoluciones.iddocumento
                WHERE devoluciones.idtipodoc = %d AND dpddev.idpadre = factura.iddocumento
                GROUP BY dpddev.idpadre
            ),0) as unittotal,
                p.idpersona,
                ca.valorcosto,
                ca.idcostoagregado,
                tc.tasa,
                tc.idtc,
                b.nombrebodega AS 'Bodega',
                b.idbodega
            FROM documentos factura
            JOIN bodegas b ON factura.idbodega = b.idbodega
            JOIN tiposdoc tdc ON tdc.idtipodoc = factura.idtipodoc
            JOIN articulosxdocumento axd ON axd.iddocumento = factura.iddocumento AND factura.idtipodoc = %d
            JOIN tiposcambio tc ON tc.idtc = factura.idtipocambio
            JOIN personasxdocumento pxd ON pxd.iddocumento = factura.iddocumento
            JOIN personas p ON pxd.idpersona = p.idpersona AND p.tipopersona=%d
            LEFT JOIN costosxdocumento cxd ON cxd.iddocumento = factura.iddocumento
            LEFT JOIN costosagregados ca ON cxd.idcostoagregado = ca.idcostoagregado
            JOIN (
                SELECT
                dpdk.idpadre
                FROM documentos kardex
                JOIN docpadrehijos dpdk ON kardex.iddocumento = dpdk.idhijo
                WHERE kardex.idtipodoc = %d
            ) as kardex ON kardex.idpadre = factura.iddocumento
            GROUP BY factura.iddocumento
            ) as tbl
            WHERE unittotal > 0
        """ % ( constantes.IDNC, constantes.IDFACTURA, constantes.CLIENTE, constantes.IDKARDEX )

        self.billsmodel.setQuery( query )



        self.setWindowTitle( "Seleccione la factura para la devolucion" )
        self.filtermodel = QSortFilterProxyModel()
        self.filtermodel.setSourceModel( self.billsmodel )
        self.filtermodel.setFilterCaseSensitivity( Qt.CaseInsensitive )
        self.filtermodel.setFilterKeyColumn( -1 )

        iddoc, _ndocimpreso, _fechacreacion, _nombre, total, idpersona, valorcosto, idcosto, tasacambio, idcambio, _nombrebodega, idbodega = range( 12 )
        self.tblBills = QTableView()
        self.tblBills.setSelectionMode( QAbstractItemView.SingleSelection )
        self.tblBills.setSelectionBehavior( QAbstractItemView.SelectRows )
        self.tblBills.selectRow( 0 )
        self.tblBills.setModel( self.filtermodel )

        self.tblBills.setColumnHidden( iddoc, True )
        self.tblBills.setColumnHidden( idpersona, True )
        self.tblBills.setColumnHidden( total, True )
        self.tblBills.setColumnHidden( valorcosto, True )
        self.tblBills.setColumnHidden( idcosto, True )
        self.tblBills.setColumnHidden( idcambio, True )
        self.tblBills.setColumnHidden( tasacambio, True )
        self.tblBills.setColumnHidden( idbodega, True )

        self.tblBills.horizontalHeader().setStretchLastSection( True )

        self.tblBills.resizeColumnsToContents()
        buttonbox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel )

        self.txtSearch = QLineEdit()
        formlayout = QFormLayout()

        formlayout.addRow( "&Buscar", self.txtSearch )

        layout = QVBoxLayout()

        layout.addWidget( self.tblBills )
        layout.addLayout( formlayout )
        layout.addWidget( buttonbox )
        self.setLayout( layout )

        self.setMinimumWidth( 400 )
        buttonbox.accepted.connect( self.accept )
        buttonbox.rejected.connect( self.reject )
        self.txtSearch.textChanged[unicode].connect( self.updateFilter )
#FIXME: Que pasa cuando no hay facturas?
#    def exec_( self ):
#        if self.billsmodel.rowCount() == 0:
#            QMessageBox.critical( None,
#            self.trUtf8( "Llantera Esquipulas: Inventario" ),
#            self.trUtf8( """No hay facturas a las cuales hacer devoluciones""" ),
#            QMessageBox.StandardButtons( \
#                QMessageBox.Ok ) )
#            self.reject()
#        else:
#            QDialog.exec_( self )




    def updateFilter( self, str ):

        self.filtermodel.setFilterWildcard( str )
Example #2
0
    class VizRank(OWWidget):
        name = "Rank projections (Scatter Plot)"

        def __init__(self, parent_widget):
            super().__init__()
            self.parent_widget = parent_widget
            self.want_control_area = False
            self.running = False
            self.progress = None
            self.k = 10

            self.projectionTable = QTableView()
            self.mainArea.layout().addWidget(self.projectionTable)
            self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
            self.projectionTable.setSelectionMode(QTableView.SingleSelection)
            self.projectionTable.setSortingEnabled(True)
            self.projectionTableModel = QStandardItemModel(self)
            self.projectionTable.setModel(self.projectionTableModel)
            self.projectionTable.selectionModel().selectionChanged.connect(
                self.on_selection_changed)

            self.button = gui.button(self.mainArea, self, "Start evaluation",
                                     callback=self.toggle, default=True)
            self.resize(380, 512)
            self._initialize()

        def _initialize(self):
            self.running = False
            self.projectionTableModel.clear()
            self.projectionTableModel.setHorizontalHeaderLabels(
                ["Score", "Feature 1", "Feature 2"])
            self.projectionTable.setColumnWidth(0, 60)
            self.projectionTable.setColumnWidth(1, 120)
            self.projectionTable.setColumnWidth(2, 120)
            self.button.setText("Start evaluation")
            self.button.setEnabled(False)
            self.pause = False
            self.data = None
            self.attrs = []
            self.scores = []
            self.i, self.j = 0, 0
            if self.progress:
                self.progress.finish()
            self.progress = None


            self.information(0)
            if self.parent_widget.data:
                if not self.parent_widget.data.domain.class_var:
                    self.information(
                        0, "Data with a class variable is required.")
                    return
                if len(self.parent_widget.data.domain.attributes) < 2:
                    self.information(
                        0, 'At least 2 unique features are needed.')
                    return
                self.button.setEnabled(True)

        def on_selection_changed(self, selected, deselected):
            """Called when the ranks view selection changes."""
            a1 = selected.indexes()[1].data()
            a2 = selected.indexes()[2].data()
            self.parent_widget.update_attr(attributes=(a1, a2))

        def toggle(self):
            self.running ^= 1
            if self.running:
                self.button.setText("Pause")
                self.run()
            else:
                self.button.setText("Continue")
                self.button.setEnabled(False)

        def run(self):
            graph = self.parent_widget.graph
            y_full = self.parent_widget.data.Y
            norm = 1 / (len(y_full) * self.k)
            if not self.attrs:
                self.attrs = self.score_heuristic()
            if not self.progress:
                self.progress = gui.ProgressBar(
                    self, len(self.attrs) * (len(self.attrs) - 1) / 2)
            for i in range(self.i, len(self.attrs)):
                ind1 = graph.attribute_name_index[self.attrs[i]]
                for j in range(self.j, i):
                    if not self.running:
                        self.i, self.j = i, j
                        if not self.projectionTable.selectedIndexes():
                            self.projectionTable.selectRow(0)
                        self.button.setEnabled(True)
                        return
                    ind2 = graph.attribute_name_index[self.attrs[j]]
                    X = graph.scaled_data[[ind1, ind2], :]
                    valid = graph.get_valid_list([ind1, ind2])
                    X = X[:, valid].T
                    y = y_full[valid]
                    knn = NearestNeighbors(n_neighbors=self.k).fit(X)
                    ind = knn.kneighbors(return_distance=False)
                    score = norm * np.sum(y[ind] == y.reshape(-1, 1))
                    pos = bisect_left(self.scores, score)
                    self.projectionTableModel.insertRow(
                        len(self.scores) - pos,
                        [QStandardItem("{:.4f}".format(score)),
                         QStandardItem(self.attrs[j]),
                         QStandardItem(self.attrs[i])])
                    self.scores.insert(pos, score)
                    self.progress.advance()
                self.j = 0
            self.progress.finish()
            if not self.projectionTable.selectedIndexes():
                self.projectionTable.selectRow(0)
            self.button.setText("Finished")
            self.button.setEnabled(False)

        def score_heuristic(self):
            X = self.parent_widget.graph.scaled_data.T
            Y = self.parent_widget.data.Y
            dom = Orange.data.Domain([ContinuousVariable(str(i))
                                      for i in range(X.shape[1])],
                                     self.parent_widget.data.domain.class_vars)
            data = Orange.data.Table(dom, X, Y)
            weights = ReliefF(n_iterations=100, k_nearest=self.k)(data)
            attrs = sorted(
                zip(weights,
                    (x.name for x in self.parent_widget.data.domain.attributes)
                    ),
                reverse=True)
            return [a for _, a in attrs]
Example #3
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(
            "")
Example #4
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("")
Example #5
0
class dlgSelectDoc( QDialog ):
    def __init__( self, tiposdoc, parent = None ):
        super( dlgSelectDoc, self ).__init__( parent )
        self.setupUi()

        self.model = QSqlQueryModel()
        query = u"""
        SELECT 
            d.iddocumento, 
            CONCAT_WS(' ', tdc.descripcion, d.ndocimpreso) as 'Documento',
            b.nombrebodega as 'Bodega',        
            d.fechacreacion as 'Fecha',
            b.idbodega,
            d.observacion
        FROM documentos d
        JOIN tiposdoc tdc ON tdc.idtipodoc = d.idtipodoc
        JOIN bodegas b ON b.idbodega = d.idbodega
        LEFT JOIN docpadrehijos dpd ON dpd.idpadre = d.iddocumento
        LEFT JOIN documentos h ON h.iddocumento = dpd.idhijo AND h.idtipodoc = %d
        WHERE d.idtipodoc IN (%s) AND d.idestado = %d
        GROUP BY d.iddocumento
        HAVING SUM(h.idtipodoc) IS NULL
        """ % ( constantes.IDKARDEX , tiposdoc, constantes.CONFIRMADO )
        self.model.setQuery( query )




        self.setWindowTitle( u"Seleccione el documento con los artĆ­culos" )
        self.filtermodel = QSortFilterProxyModel()
        self.filtermodel.setSourceModel( self.model )
        self.filtermodel.setFilterCaseSensitivity( Qt.CaseInsensitive )
        self.filtermodel.setFilterKeyColumn( -1 )

        self.tblBills.setModel( self.filtermodel )

#        self.tblBills.horizontalHeader().setStretchLastSection( True )

        iddoc, _ndocimpreso, _bodega, _fecha, idbodega, observacion = range( 6 )
        self.tblBills.setColumnHidden( iddoc, True )
        self.tblBills.setColumnHidden( idbodega, True )
        self.tblBills.setColumnHidden( observacion, True )
        self.tblBills.resizeColumnsToContents()

        self.buttonbox.accepted.connect( self.accept )
        self.buttonbox.rejected.connect( self.reject )
        self.txt_search.textChanged[unicode].connect( self.update_filter )

    def setupUi( self ):
        self.tblBills = QTableView()
        self.tblBills.setSelectionMode( QAbstractItemView.SingleSelection )
        self.tblBills.setSelectionBehavior( QAbstractItemView.SelectRows )
        self.tblBills.selectRow( 0 )

        self.buttonbox = QDialogButtonBox( QDialogButtonBox.Ok |
                                           QDialogButtonBox.Cancel )

        self.txt_search = QLineEdit()
        formlayout = QFormLayout()

        formlayout.addRow( "&Buscar", self.txt_search )

        layout = QVBoxLayout()

        layout.addWidget( self.tblBills )
        layout.addLayout( formlayout )
        layout.addWidget( self.buttonbox )
        self.setLayout( layout )

        self.setMinimumWidth( 450 )

    def update_filter( self, text ):
        self.filtermodel.setFilterWildcard( text )
Example #6
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)
Example #7
0
    class VizRank(OWWidget):
        name = "Rank projections (Scatter Plot)"

        want_control_area = False

        def __init__(self, parent_widget):
            super().__init__()
            self.parent_widget = parent_widget
            self.running = False
            self.progress = None
            self.k = 10

            self.projectionTable = QTableView()
            self.mainArea.layout().addWidget(self.projectionTable)
            self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
            self.projectionTable.setSelectionMode(QTableView.SingleSelection)
            self.projectionTable.setSortingEnabled(True)
            self.projectionTableModel = QStandardItemModel(self)
            self.projectionTable.setModel(self.projectionTableModel)
            self.projectionTable.selectionModel().selectionChanged.connect(
                self.on_selection_changed)

            self.button = gui.button(self.mainArea,
                                     self,
                                     "Start evaluation",
                                     callback=self.toggle,
                                     default=True)
            self.resize(380, 512)
            self._initialize()

        def _initialize(self):
            self.running = False
            self.projectionTableModel.clear()
            self.projectionTableModel.setHorizontalHeaderLabels(
                ["Score", "Feature 1", "Feature 2"])
            self.projectionTable.setColumnWidth(0, 60)
            self.projectionTable.setColumnWidth(1, 120)
            self.projectionTable.setColumnWidth(2, 120)
            self.button.setText("Start evaluation")
            self.button.setEnabled(False)
            self.pause = False
            self.data = None
            self.attrs = []
            self.scores = []
            self.i, self.j = 0, 0
            if self.progress:
                self.progress.finish()
            self.progress = None

            self.information(0)
            if self.parent_widget.data:
                if not self.parent_widget.data.domain.class_var:
                    self.information(
                        0, "Data with a class variable is required.")
                    return
                if len(self.parent_widget.data.domain.attributes) < 2:
                    self.information(0,
                                     'At least 2 unique features are needed.')
                    return
                if len(self.parent_widget.data) < 2:
                    self.information(0, 'At least 2 instances are needed.')
                    return
                self.button.setEnabled(True)

        def on_selection_changed(self, selected, deselected):
            """Called when the ranks view selection changes."""
            a1 = selected.indexes()[1].data()
            a2 = selected.indexes()[2].data()
            self.parent_widget.update_attr(attributes=(a1, a2))

        def toggle(self):
            self.running ^= 1
            if self.running:
                self.button.setText("Pause")
                self.run()
            else:
                self.button.setText("Continue")
                self.button.setEnabled(False)

        def run(self):
            graph = self.parent_widget.graph
            y_full = self.parent_widget.data.Y
            if not self.attrs:
                self.attrs = self.score_heuristic()
            if not self.progress:
                self.progress = gui.ProgressBar(
                    self,
                    len(self.attrs) * (len(self.attrs) - 1) / 2)
            for i in range(self.i, len(self.attrs)):
                ind1 = graph.attribute_name_index[self.attrs[i]]
                for j in range(self.j, i):
                    if not self.running:
                        self.i, self.j = i, j
                        if not self.projectionTable.selectedIndexes():
                            self.projectionTable.selectRow(0)
                        self.button.setEnabled(True)
                        return
                    ind2 = graph.attribute_name_index[self.attrs[j]]
                    X = graph.scaled_data[[ind1, ind2], :]
                    valid = graph.get_valid_list([ind1, ind2])
                    X = X[:, valid].T
                    if X.shape[0] < self.k:
                        self.progress.advance()
                        continue
                    y = y_full[valid]
                    n_neighbors = min(self.k, len(X) - 1)
                    knn = NearestNeighbors(n_neighbors=n_neighbors).fit(X)
                    ind = knn.kneighbors(return_distance=False)
                    if self.parent_widget.data.domain.has_discrete_class:
                        score = np.sum(y[ind] == y.reshape(-1, 1)) / (
                            len(y_full) * n_neighbors)
                    else:
                        score = r2_score(y, np.mean(
                            y[ind], axis=1)) * (len(y) / len(y_full))
                    pos = bisect_left(self.scores, score)
                    self.projectionTableModel.insertRow(
                        len(self.scores) - pos, [
                            QStandardItem("{:.4f}".format(score)),
                            QStandardItem(self.attrs[j]),
                            QStandardItem(self.attrs[i])
                        ])
                    self.scores.insert(pos, score)
                    self.progress.advance()
                self.j = 0
            self.progress.finish()
            if not self.projectionTable.selectedIndexes():
                self.projectionTable.selectRow(0)
            self.button.setText("Finished")
            self.button.setEnabled(False)

        def score_heuristic(self):
            X = self.parent_widget.graph.scaled_data.T
            Y = self.parent_widget.data.Y
            dom = Domain(
                [ContinuousVariable(str(i)) for i in range(X.shape[1])],
                self.parent_widget.data.domain.class_vars)
            data = Table(dom, X, Y)
            relief = ReliefF if isinstance(dom.class_var,
                                           DiscreteVariable) else RReliefF
            weights = relief(n_iterations=100, k_nearest=self.k)(data)
            attrs = sorted(zip(
                weights,
                (x.name for x in self.parent_widget.data.domain.attributes)),
                           reverse=True)
            return [a for _, a in attrs]
Example #8
0
class ListView(QStackedWidget):
    PAGE_EMPTY    = 0 
    PAGE_LISTVIEW = 1

    def __init__(self, parent = None):
        
        super(ListView, self).__init__(parent=parent)
        
        self.emptyMessage = QLabel("no elements defined yet")
        self.emptyMessage.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter )
        self.emptyMessage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.addWidget(self.emptyMessage)
        
        self._table = QTableView()
        self.addWidget(self._table)
        self._table.clicked.connect(self.tableViewCellClicked)
        self._table.doubleClicked.connect(self.tableViewCellDoubleClicked)
        self._table.verticalHeader().sectionMoved.connect(self.rowMovedTest)
        self._table.setShowGrid(False)
    
    def resetEmptyMessage(self,pystring):
        self.emptyMessage.setText(QString(pystring))

    def tableViewCellClicked(self, modelIndex):
        '''
        Reimplemt this function to get interaction when double click
        :param modelIndex:
        '''
        
#         if (modelIndex.column() == self.model.ColumnID.Delete and
#             not self._table.model().flags(modelIndex) == Qt.NoItemFlags):
#             self._table.model().removeRow(modelIndex.row())
#     
    def tableViewCellDoubleClicked(self, modelIndex):
        '''
        Reimplement this function to get interaction when single click
        :param modelIndex:
        '''
#         if modelIndex.column() == self.model.ColumnID.Color:
#             self._colorDialog.setBrushColor(self._table.model()[modelIndex.row()].brushColor())
#             self._colorDialog.setPmapColor (self._table.model()[modelIndex.row()].pmapColor())
#             self._colorDialog.exec_()
#             #print "brush color = {}".format(self._colorDialog.brushColor().name())
#             #print "pmap color  = {}".format(self._colorDialog.pmapColor().name())
#             self._table.model().setData(modelIndex, (self._colorDialog.brushColor(),
#                                               self._colorDialog.pmapColor ()))

    def rowMovedTest(self, logicalIndex, oldVisualIndex, newVisualIndex):
        logger.debug( "{} {} {}".format(logicalIndex, oldVisualIndex, newVisualIndex) )

    def _setListViewLook(self):
        table = self._table
        #table.setDragEnabled(True)
        table.setAcceptDrops(True)
        table.setFocusPolicy(Qt.NoFocus)
        table.setShowGrid(False)
        table.horizontalHeader().hide()
        table.verticalHeader().hide()
        #table.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)
        table.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
        
        
        table.setSelectionMode(QAbstractItemView.SingleSelection)
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
     
    def selectRow(self, *args, **kwargs):
        self._table.selectRow(*args, **kwargs)
        
    def _onRowsChanged(self, parent, start, end):
        model = self._table.model()
        if model and model.rowCount() > 0:
            self.setCurrentIndex(self.PAGE_LISTVIEW)
        else:
            self.setCurrentIndex(self.PAGE_EMPTY)
        if self.parent()!=None: self.parent().updateGeometry()

    def setModel(self, model):
        QTableView.setModel(self._table, model)
        self._table.setSelectionModel(model._selectionModel)
        
        if model.rowCount() > 0:
            self.setCurrentIndex(self.PAGE_LISTVIEW)
        else:
            self.setCurrentIndex(self.PAGE_EMPTY)
            
        model.rowsInserted.connect(self._onRowsChanged)
        model.rowsRemoved.connect(self._onRowsChanged)
        self.model=model
        
        self._setListViewLook()
        


    @property
    def allowDelete(self):
        return not self._table.isColumnHidden(self.model.ColumnID.Delete)

    @allowDelete.setter
    def allowDelete(self, allow):
        self._table.setColumnHidden(self.model.ColumnID.Delete, not allow)

    def minimumSizeHint(self):
        #http://www.qtcentre.org/threads/14764-QTableView-sizeHint%28%29-issues
        t = self._table
        vHeader = t.verticalHeader()
        hHeader = t.horizontalHeader()
        doubleFrame = 2 * t.frameWidth()
        w = hHeader.length() + vHeader.width() + doubleFrame;
     
        contentH = 0
        if self._table.model(): 
            for i in range(self._table.model().rowCount()):
                contentH += self._table.rowHeight(i)
        contentH = max(90, contentH) 
        
        h = hHeader.height() + contentH + doubleFrame;
        from PyQt4.QtCore import QSize
        return QSize(w,h)

    def sizeHint(self):
        return self.minimumSizeHint()
    
    def shrinkToMinimum(self):
        """
        shrink the view around the 
        labels which are currently there
        """
        t = self._table
        hHeader = t.horizontalHeader()
        doubleFrame = 2 * t.frameWidth()     
        contentH = 0
        if self._table.model(): 
            for i in range(self._table.model().rowCount()):
                contentH += self._table.rowHeight(i)
        h =  contentH+2
        self.setFixedHeight(h)
        
Example #9
0
class ListView(QStackedWidget):
    PAGE_EMPTY    = 0 
    PAGE_LISTVIEW = 1

    def __init__(self, parent = None):
        
        super(ListView, self).__init__(parent=parent)
        
        self.emptyMessage = QLabel("no elements defined yet")
        self.emptyMessage.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter )
        self.emptyMessage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.addWidget(self.emptyMessage)
        
        self._table = QTableView()
        self.addWidget(self._table)
        self._table.clicked.connect(self.tableViewCellClicked)
        self._table.doubleClicked.connect(self.tableViewCellDoubleClicked)
        self._table.verticalHeader().sectionMoved.connect(self.rowMovedTest)
        self._table.setShowGrid(False)
    
    def resetEmptyMessage(self,pystring):
        self.emptyMessage.setText(QString(pystring))

    def tableViewCellClicked(self, modelIndex):
        '''
        Reimplemt this function to get interaction when double click
        :param modelIndex:
        '''
        
#         if (modelIndex.column() == self.model.ColumnID.Delete and
#             not self._table.model().flags(modelIndex) == Qt.NoItemFlags):
#             self._table.model().removeRow(modelIndex.row())
#     
    def tableViewCellDoubleClicked(self, modelIndex):
        '''
        Reimplement this function to get interaction when single click
        :param modelIndex:
        '''
#         if modelIndex.column() == self.model.ColumnID.Color:
#             self._colorDialog.setBrushColor(self._table.model()[modelIndex.row()].brushColor())
#             self._colorDialog.setPmapColor (self._table.model()[modelIndex.row()].pmapColor())
#             self._colorDialog.exec_()
#             #print "brush color = {}".format(self._colorDialog.brushColor().name())
#             #print "pmap color  = {}".format(self._colorDialog.pmapColor().name())
#             self._table.model().setData(modelIndex, (self._colorDialog.brushColor(),
#                                               self._colorDialog.pmapColor ()))

    def rowMovedTest(self, logicalIndex, oldVisualIndex, newVisualIndex):
        print "{} {} {}".format(logicalIndex, oldVisualIndex, newVisualIndex)

    def _setListViewLook(self):
        table = self._table
        #table.setDragEnabled(True)
        table.setAcceptDrops(True)
        table.setFocusPolicy(Qt.NoFocus)
        table.setShowGrid(False)
        table.horizontalHeader().hide()
        table.verticalHeader().hide()
        #table.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)
        table.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
        
        
        table.setSelectionMode(QAbstractItemView.SingleSelection)
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
     
    def selectRow(self, *args, **kwargs):
        self._table.selectRow(*args, **kwargs)
        
    def _onRowsChanged(self, parent, start, end):
        model = self._table.model()
        if model and model.rowCount() > 0:
            self.setCurrentIndex(self.PAGE_LISTVIEW)
        else:
            self.setCurrentIndex(self.PAGE_EMPTY)
        if self.parent()!=None: self.parent().updateGeometry()

    def setModel(self, model):
        QTableView.setModel(self._table, model)
        self._table.setSelectionModel(model._selectionModel)
        
        if model.rowCount() > 0:
            self.setCurrentIndex(self.PAGE_LISTVIEW)
        else:
            self.setCurrentIndex(self.PAGE_EMPTY)
            
        model.rowsInserted.connect(self._onRowsChanged)
        model.rowsRemoved.connect(self._onRowsChanged)
        self.model=model
        
        self._setListViewLook()
        


    @property
    def allowDelete(self):
        return not self._table.isColumnHidden(self.model.ColumnID.Delete)

    @allowDelete.setter
    def allowDelete(self, allow):
        self._table.setColumnHidden(self.model.ColumnID.Delete, not allow)

    def minimumSizeHint(self):
        #http://www.qtcentre.org/threads/14764-QTableView-sizeHint%28%29-issues
        t = self._table
        vHeader = t.verticalHeader()
        hHeader = t.horizontalHeader()
        doubleFrame = 2 * t.frameWidth()
        w = hHeader.length() + vHeader.width() + doubleFrame;
     
        contentH = 0
        if self._table.model(): 
            for i in range(self._table.model().rowCount()):
                contentH += self._table.rowHeight(i)
        contentH = max(90, contentH) 
        
        h = hHeader.height() + contentH + doubleFrame;
        from PyQt4.QtCore import QSize
        return QSize(w,h)

    def sizeHint(self):
        return self.minimumSizeHint()
    
    def shrinkToMinimum(self):
        """
        shrink the view around the 
        labels which are currently there
        """
        t = self._table
        hHeader = t.horizontalHeader()
        doubleFrame = 2 * t.frameWidth()     
        contentH = 0
        if self._table.model(): 
            for i in range(self._table.model().rowCount()):
                contentH += self._table.rowHeight(i)
        h =  contentH+2
        self.setFixedHeight(h)
        
Example #10
0
class dlgSelectCuenta( QDialog ):

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

        self.ctaBancomodel = QSqlQueryModel()
        self.ctaBancomodel.setQuery( """
        SELECT
            b.descripcion as Banco,
            cb.ctabancaria as 'No. Cuenta',
            tm.simbolo as Moneda,
            c.codigo as 'Codigo Contable',
            c.idcuenta as Id,
            c.descripcion as 'Cuenta Contable',
            IF(
                con.fecha IS NULL,
                LAST_DAY(MIN(d.fechacreacion)),
                (MAX(con.fecha) + INTERVAL 1 MONTH))
                AS conciliar

        FROM cuentasbancarias cb
        JOIN bancos b ON cb.idbanco=b.idbanco
        JOIN cuentascontables c ON c.idcuenta=cb.idcuentacontable
        JOIN tiposmoneda tm ON tm.idtipomoneda=cb.idtipomoneda
        LEFT JOIN conciliaciones con ON con.idcuentabancaria=cb.idcuentacontable
        LEFT JOIN cuentasxdocumento cd ON cd.idcuenta=c.idcuenta
        LEFT JOIN documentos d ON cd.iddocumento = d.iddocumento
        WHERE d.iddocumento IS NOT NULL
        GROUP BY c.idcuenta
         ;
        """ )
#        
#        if self.ctaBancomodel.rowCount() == 0 :
#            QMessageBox.critical(self,"Cuentas Bancarias","No existe ninguna cuenta bancaria")
#            self.destroy()


        self.setWindowTitle( u"Elija fecha y cuenta bancaria para la conciliaciĆ³n" )
        self.filtermodel = QSortFilterProxyModel()
        self.filtermodel.setSourceModel( self.ctaBancomodel )
        self.filtermodel.setFilterCaseSensitivity( Qt.CaseInsensitive )
        self.filtermodel.setFilterKeyColumn( -1 )

        self.tblCuenta = QTableView()
        self.tblCuenta.setSelectionMode( QAbstractItemView.SingleSelection )
        self.tblCuenta.setSelectionBehavior( QAbstractItemView.SelectRows )

        self.tblCuenta.setModel( self.filtermodel )
        buttonbox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel )

        self.txtSearch = QLineEdit()
        formlayout = QFormLayout()

        formlayout.addRow( "&Buscar", self.txtSearch )



        self.dtPicker = QDateTimeEdit()
        self.dtPicker.setReadOnly( True )
#        self.dtPicker.setCalendarPopup(True)                                       
        self.dtPicker.setAlignment( Qt.AlignHCenter )
        self.dtPicker.setDisplayFormat( "MMMM 'd'el yyyy" )
#        self.dtPicker.setMinimumDate(QDate(2009,1,1))
        fecha = QDate.currentDate()
        self.dtPicker.setDate( QDate( fecha.year(), fecha.month(), fecha.daysInMonth() ) )

        fechalayout = QFormLayout()
        fechalayout.addRow( "&Fecha", self.dtPicker )

        layout = QVBoxLayout()


        layout.addLayout( fechalayout )
        layout.addWidget( self.tblCuenta )
        layout.addLayout( formlayout )
        layout.addWidget( buttonbox )
        self.setLayout( layout )

        self.setMinimumWidth( 400 )

        buttonbox.accepted.connect( self.aceptar )
        buttonbox.rejected.connect( self.reject )
        self.txtSearch.textChanged[unicode].connect( self.updateFilter )
        self.tblCuenta.selectionModel().currentChanged[QModelIndex, QModelIndex].connect( self.on_tblCuenta_currentChanged )

        self.setModal( True )
        self.setWindowFlags( Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint | Qt.WindowTitleHint )
        self.show()
        self.tblCuenta.setFocus()
        self.tblCuenta.selectRow( 0 )
        self.tblCuenta.setColumnHidden( 4, True )
        self.tblCuenta.setColumnHidden( 5, True )
        self.tblCuenta.setColumnHidden( 6, True )
        self.tblCuenta.horizontalHeader().setStretchLastSection( True )
        self.tblCuenta.resizeColumnsToContents()

    @property
    def data( self ):
        data = {}
        fila = self.tblCuenta.selectionModel().currentIndex().row()
        fecha = self.dtPicker.date()

        data['banco'] = self.filtermodel.index( fila, 0 ).data().toString()
        data['id_cuenta_contable'] = self.filtermodel.index( fila, 4 ).data().toInt()[0]
        data['codigo_cuenta_contable'] = self.filtermodel.index( fila, 3 ).data().toString()
        data['cuenta_bancaria'] = self.filtermodel.index( fila, 5 ).data().toString()
        data['fecha'] = QDate( fecha.year(), fecha.month(), fecha.daysInMonth() )
        data['moneda'] = self.filtermodel.index( fila, 2 ).data().toString()


        if not QSqlDatabase.database().isOpen() and not QSqlDatabase.open():
            raise Exception( QSqlDatabase.lastError() )

        query = QSqlQuery()
        if not query.exec_( "CALL spSaldoCuenta( %d, %s )" % ( 
                data['id_cuenta_contable'],
                QDate( data['fecha'].year(), data['fecha'].month(), data['fecha'].daysInMonth() ).toString( "yyyyMMdd" )
            )
        ):
            raise Exception( query.lastError().text() )

        query.first()

        data['saldo_inicial_libro'] = Decimal( query.value( 0 ).toString() )



        return data

    def aceptar( self ):
        fecha = QDate.currentDate()
        fecha = QDate( fecha.year(), fecha.month(), fecha.daysInMonth() )
        if self.dtPicker.date() > fecha:
            QMessageBox.information( None, "Cuentas Bancarias", "La cuenta seleccionada ya fue conciliada" )
        else:
            return self.accept()


    def exec_( self ):
        if self.ctaBancomodel.rowCount() == 0:
            QMessageBox.critical( self.padre, "Cuentas Bancarias",
                "No existe ninguna cuenta bancaria con movimientos en este mes" )
            return self.reject()
        else:
            return QDialog.exec_( self )

    def updateFilter( self, str ):
        self.filtermodel.setFilterWildcard( str )

#    @pyqtSlot( "QModelIndex" )
#    def on_tblCuenta_clicked(self, index):
    def on_tblCuenta_currentChanged( self, _current, _previous ):
        fila = self.tblCuenta.selectionModel().currentIndex().row()
        fecha = self.filtermodel.index( fila, 6 ).data().toDate()
        if fecha.toString() != "":
            self.dtPicker.setDate( fecha )
        else:
            fecha = QDate.currentDate()
class MainWindow(QMainWindow):
    """
        Initialization
    """
    def __init__(self, rulesModel, logoFnam, *args):
        QMainWindow.__init__(self, *args)
        
        self.rulesModel = rulesModel
        
        self.rulesModel.dataChanged.connect(self._statusRefresh)
        
        self.cancelled = True   # for to handle win close box the same as Cancel button
        
        self.mainHSplit = QSplitter(self)   # data | buttons
        self.mainHSplit.setChildrenCollapsible(False)
        self.setCentralWidget(self.mainHSplit)

        self.mainVSplit = QSplitter(Qt.Vertical)
        self.mainVSplit.setChildrenCollapsible(False)
        self.mainHSplit.addWidget(self.mainVSplit)
        
        self._drawRules()
        self.mainVSplit.addWidget(self.rulesView)
        self.condActSplit = QSplitter()
        self.condActSplit.setChildrenCollapsible(False)
        self._drawCondAct()
        self.mainVSplit.addWidget(self.condActSplit)
        # let rules view resize vertically two times faster than cond/action view
        self.rulesView.setSizeIncrement(self.rulesView.sizeIncrement().width(), 
                                        2 * self.condView.sizeIncrement().height())
        
        self._drawButtons(logoFnam)
        self.setStatusBar(QStatusBar())
        self.condView.horizontalHeader().setCascadingSectionResizes(True)
        self.rulesView.selectRow(0)
                                
    def _drawRules(self):
        self.rulesView = QTableView()
        self.rulesView.setModel(self.rulesModel)
        self.rulesView.setEditTriggers(QAbstractItemView.AllEditTriggers)
        self.rulesView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.rulesView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.rulesView.horizontalHeader().setStretchLastSection(True)
        self.rulesView.resizeColumnsToContents()
        #self.rulesView.verticalHeader().setMovable(True)  # row remapping - see QHeaderView.logicalIndex()
        #self.rulesView.verticalHeader().setCascadingSectionResizes(True)  # takes space from next row
        self.rulesView.selectionModel().currentRowChanged.connect(self._ruleRowChanged)
        self.rulesView.verticalHeader().sectionResized[int,int,int].connect(self._ruleRowHeightChanged)
        
    def _drawCondAct(self):
        if getattr(self, 'condGB', None):
            m_settings.setValue('spl_condAct', self.condActSplit.saveState())
            self.condGB.deleteLater() # or .destroy()
            del self.condGB
            self.actionGB.deleteLater()
            del self.actionGB
            
        row = self._ruleCurrRow()
        rcount = self.rulesModel.rowCount()
        
        self.condGB = QGroupBox(self.tr('Conditions'))
        self.condView = QTableView()
        conds = self.rulesModel.ruleConditions(row) if row in range(rcount) \
                else []
        self.condModel = ConditionsModel(conds, self.rulesModel)
        self.condModel.dataChanged.connect(self._codeFragChanged)
        self.condView.setModel(self.condModel)
        self.condTypeDelegate = ComboBoxDelegate(Condition._types._typeCaptions)
        self.condView.setItemDelegateForColumn(0, self.condTypeDelegate)
        self.condView.setEditTriggers(QAbstractItemView.AllEditTriggers)
        self.condView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.condView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.condView.horizontalHeader().setStretchLastSection(True)
        self.condView.resizeColumnsToContents()
        self.condView.selectionModel().currentRowChanged.connect(self._statusRefresh)
        vbox = QVBoxLayout()
        vbox.addWidget(self.condView)
        self.condGB.setLayout(vbox)
        self.condActSplit.addWidget(self.condGB)
        
        self.actionGB = QGroupBox(self.tr('Actions'))
        self.actionView = QTableView()   # parent = self.actionGB)
        actions = self.rulesModel.ruleActions(row) if row in range(rcount) \
                else []
        self.actionModel = ActionsModel(actions, self.rulesModel)
        self.actionModel.dataChanged.connect(self._codeFragChanged)
        self.actionView.setModel(self.actionModel)
        self.actionTypeDelegate = ComboBoxDelegate(Action._types._typeCaptions)
        self.actionView.setItemDelegateForColumn(0, self.actionTypeDelegate)
        self.actionView.setEditTriggers(QAbstractItemView.AllEditTriggers)
        self.actionView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.actionView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.actionView.horizontalHeader().setStretchLastSection(True)
        self.actionView.resizeColumnsToContents()
        self.actionView.selectionModel().currentRowChanged.connect(self._statusRefresh)
        vbox = QVBoxLayout()
        vbox.addWidget(self.actionView)
        self.actionGB.setLayout(vbox)
        self.condActSplit.addWidget(self.actionGB)
        
        self.condActSplit.restoreState(m_settings.value('spl_condAct').toByteArray())

        
    def _drawButton(self, vbox, caption, slot, ena = False):
        but = QPushButton(self.tr(caption))
        but.setEnabled(ena)
        but.clicked.connect(getattr(self, slot))
        vbox.addWidget(but)     # add to VBoxLayout
        return but
    
    def _drawButtons(self, logoFnam):
        gbox = QGroupBox()
        spol = QSizePolicy()
        spol.horizontalPolicy = QSizePolicy.Maximum
        gbox.setSizePolicy(spol)
        vbox = QVBoxLayout()
        
        if os.path.isfile(logoFnam):
            img = QPixmap(logoFnam)    #.scaled(64, 64)
            lblLogo = QLabel()
            lblLogo.setPixmap(img)
            lblLogo.setAlignment(Qt.AlignTop | Qt.AlignRight)
            vbox.addWidget(lblLogo)
            #vbox.addSpacing(3) 
        
        self.butSave = self._drawButton(vbox, "M&odify", 'closeSave')
        font = QFont()
        font.setBold(True)
        self.butSave.setFont(font)
        self.butCancel = self._drawButton(vbox, "Cancel", 'closeCancel', True)
        vbox.addSpacing(36)
        self.butAddRule = self._drawButton(vbox, "Add Rule", 'addRule', True)
        self.butCopyRule = self._drawButton(vbox, "Copy Rule", 'copyRule')
        self.butDelRule = self._drawButton(vbox, "Delete Rule", 'delRule')
        self.butMoveRuleUp = self._drawButton(vbox, "Move Rule Up", 'moveRuleUp')
        self.butMoveRuleDn = self._drawButton(vbox, "Move Rule Down", 'moveRuleDown')
        vbox.addSpacing(24)
        self.butAddCond = self._drawButton(vbox, "Add Condition", 'addCond')
        self.butDelCond = self._drawButton(vbox, "Delete Condition", 'delCond')
        vbox.addSpacing(15)
        self.butAddAction = self._drawButton(vbox, "Add Action", 'addAction')
        self.butDelAction = self._drawButton(vbox, "Delete Action", 'delAction')
        
        gbox.setLayout(vbox)
        self.mainHSplit.addWidget(gbox) 
    
    """
        Internal Bindings Signal Receivers
    """
    # main win close events
    # .. (cancel closing with event.ignore(); QMainWindow calls event.accept())       
    @pyqtSlot(QCloseEvent)
    def closeEvent(self, event):
        self._saveAppState()
        # save rules if not empty and user clicked Modified/Save button
        if self.rulesModel.rowCount() > 0 and not self.cancelled:
            text = self.rulesModel.getRawRules().validate()
            if text:
                self.cancelled = True
                QMessageBox.information(self, APP_TITLE, 
                                        self.tr("Validation failed because of:<p><p>") + text)
                event.ignore()
                return              #  RETURN - cancel app closing ######
            self.rulesModel.saveScript()
        # accept window closing
        QMainWindow.closeEvent(self, event)
        # quit application
        m_app.quit()
    @pyqtSlot()
    def _statusRefresh(self):       # dis/enable buttons, display view selections
        ruleRow = self._ruleCurrRow()
        condRow = self._condCurrRow()
        actionRow = self._actionCurrRow()
        self.butSave.setEnabled(self.rulesModel.isModified())
        ruleCnt = self.rulesModel.rowCount()
        self.butCopyRule.setEnabled(ruleRow >= 0)
        self.butDelRule.setEnabled(ruleRow >= 0)
        self.butMoveRuleUp.setEnabled(ruleRow > 0)
        self.butMoveRuleDn.setEnabled(ruleRow >= 0 and ruleRow + 1 < ruleCnt)
        self.butAddCond.setEnabled(ruleRow >= 0)
        self.butDelCond.setEnabled(condRow >= 0)  
        self.butAddAction.setEnabled(ruleRow >= 0)
        self.butDelAction.setEnabled(actionRow >= 0)
        # display currently selected list rows in the status bar - if empty
        if ruleRow >= 0 and False:    # replace False with ~self.statusBar().isEmpty()?!?!?
            text = str(self.tr("Selected Rule: {ruleI}"))\
                .format(ruleI = ruleRow + 1)
            if condRow >= 0:
                text += "      " \
                    + str(self.tr("Selected Condition: {typeI}"))\
                    .format(typeI = condRow + 1)
            if actionRow >= 0:
                text += "      " \
                    + str(self.tr("Selected Action: {typeI}"))\
                    .format(typeI = actionRow + 1)
            self.statusBar().showMessage(text, 3000)
    @pyqtSlot(int,int,int)
    def _ruleRowHeightChanged(self, section, oldsize, newsize):
        hdr = self.rulesView.verticalHeader()
        for row in range(hdr.count()):
            if row != section:
                hdr.resizeSection(row, newsize)
    @pyqtSlot()
    def _ruleRowChanged(self):
        self._drawCondAct()
        self._statusRefresh()
    @pyqtSlot()
    def _codeFragChanged(self):     # refresh the rules list columns Conditions and Actions
        row = self._ruleCurrRow()
        leftColIndex = self.rulesModel.index(row, 2, QModelIndex())
        rightColIndex = self.rulesModel.index(row, 3, QModelIndex())
        self.rulesView.dataChanged(leftColIndex, rightColIndex)
        self._statusRefresh()
        
    """
        User Action Signal Receivers
    """
    @pyqtSlot()
    def closeSave(self):
        self.cancelled = False
        self.close()
    @pyqtSlot()
    def closeCancel(self):
        self.cancelled = True
        self.close()
    @pyqtSlot()
    def addRule(self):
        row = self._ruleCurrRow()
        self.rulesModel.insertRow(row)
        self.rulesView.selectRow(row)
        self._statusRefresh()
    @pyqtSlot()
    def copyRule(self):
        row = self._ruleCurrRow()
        self.rulesModel.setSourceRowForNextAdd(row)
        self.rulesModel.insertRow(row)
        self.rulesView.selectRow(row)
        self._statusRefresh()
    @pyqtSlot()
    def delRule(self):
        self.rulesModel.removeRow(self._ruleCurrRow())
        self._statusRefresh()
    @pyqtSlot()
    def moveRuleUp(self):
        row = self._ruleCurrRow()
        self.rulesModel.moveRule(row, -1)
        self._statusRefresh()
    @pyqtSlot()
    def moveRuleDown(self):
        row = self._ruleCurrRow()
        self.rulesModel.moveRule(row)
        self._statusRefresh()
    @pyqtSlot()
    def addCond(self):
        cnt = self.condModel.rowCount()
        self.condModel.insertRow(cnt)
        self.condView.selectRow(cnt)
        self._statusRefresh()
    @pyqtSlot()
    def delCond(self):
        self.condModel.removeRow(self._condCurrRow())
        self._statusRefresh()
    @pyqtSlot()
    def addAction(self):
        cnt = self.actionModel.rowCount()
        self.actionModel.insertRow(cnt)
        self.actionView.selectRow(cnt)
        self._statusRefresh()
    @pyqtSlot()
    def delAction(self):
        self.actionModel.removeRow(self._actionCurrRow())
        self._statusRefresh()
    
    """
        Helping Methods
    """
    def _ruleCurrRow(self):
        #idxs = self.rulesView.selectedIndexes()
        #return idxs[0].row() if idxs else -1
        return self.rulesView.currentIndex().row()
    def _condCurrRow(self):
        return self.condView.currentIndex().row()
    def _actionCurrRow(self):
        return self.actionView.currentIndex().row()
    
    # main win save/restore
    def _saveAppState(self):
        m_app.processEvents()
        # save win geometry and splitter positions
        _UI_SAVE(self, 'win_geometry')
        _UI_SAVE(self.mainHSplit, 'spl_mainH')
        _UI_SAVE(self.mainVSplit, 'spl_mainV')
        _UI_SAVE(self.condActSplit, 'spl_condAct')
        #_UI_SAVE(self.condView.horizontalHeader(), 'tvh_condHdr')
    def _restoreAppState(self):
        try:    # will fail on first app startup after installation
            # restore last win position, -size and 3 splitter positions
            _UI_RESTORE(self, 'win_geometry')
            _UI_RESTORE(self.mainHSplit, 'spl_mainH')
            _UI_RESTORE(self.mainVSplit, 'spl_mainV')
            _UI_RESTORE(self.condActSplit, 'spl_condAct')
            #_UI_RESTORE(self.condView.horizontalHeader(), 'tvh_condHdr')
        except: # first start
            screenWidth = QApplication.desktop().width()
            screenHeight = QApplication.desktop().height()
            self.setGeometry(screenWidth / 9, screenHeight / 12,
                            screenWidth / 1.26, screenHeight / 1.56)
Example #12
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()))