class PlayerList(QDialog): """QtSQL Model view of the players""" def __init__(self, parent): QDialog.__init__(self) self.parent = parent self.model = QSqlTableModel(self, DBHandle.default) self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.setTable("player") self.model.setSort(1, 0) self.model.setHeaderData(1, Qt.Horizontal, QVariant(m18nc("Player", "Name"))) self.model.setFilter('name not like "ROBOT %" and name not like "Robot %"') self.view = MJTableView(self) self.view.verticalHeader().show() self.view.setModel(self.model) self.view.hideColumn(0) self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.newButton = self.buttonBox.addButton(m18nc('define a new player', "&New"), QDialogButtonBox.ActionRole) self.newButton.setIcon(KIcon("document-new")) self.newButton.clicked.connect(self.slotInsert) self.deleteButton = self.buttonBox.addButton(m18n("&Delete"), QDialogButtonBox.ActionRole) self.deleteButton.setIcon(KIcon("edit-delete")) self.deleteButton.clicked.connect(self.delete) cmdLayout = QHBoxLayout() cmdLayout.addWidget(self.buttonBox) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(cmdLayout) self.setLayout(layout) self.setWindowTitle(m18n("Players") + ' - Kajongg') self.setObjectName('Players') def showEvent(self, dummyEvent): """adapt view to content""" if not self.model.select(): logError("PlayerList: select failed") sys.exit(1) self.view.initView() StateSaver(self, self.view.horizontalHeader()) if not self.view.isColumnHidden(2): # we loaded a kajonggrc written by an older kajongg version where this table # still had more columns. This should happen only once. self.view.hideColumn(2) self.view.hideColumn(3) def accept(self): """commit all modifications""" self.view.selectRow(0) # if ALT-O is entered while editing a new row, this is one way # to end editing and to pass the new value to the model if not self.model.submitAll(): Sorry(m18n('Cannot save this. Possibly the name already exists. <br><br>' \ 'Message from database:<br><br><message>%1</message>', self.model.lastError().text())) return QDialog.accept(self) def slotInsert(self): """insert a record""" self.model.insertRow(self.model.rowCount()) self.view.selectRow(self.model.rowCount()-1) def delete(self): """delete selected entries""" sel = self.view.selectionModel() maxDel = self.view.currentIndex().row() - 1 for idx in sel.selectedIndexes(): if idx.column() != 1: continue # sqlite3 does not enforce referential integrity. # we could add a trigger to sqlite3 but if it raises an exception # it will be thrown away silently. # if anybody knows how to propagate sqlite3 exceptions via QtSql # into python please tell me (wrohdewald) player = self.model.createIndex(idx.row(), 0).data().toInt()[0] # no query preparation, we don't expect lots of data if Query("select 1 from game where p0==%d or p1==%d or p2==%d or p3==%d" % \ (player, player, player, player)).records: Sorry(m18n('This player cannot be deleted. There are games associated with %1.', idx.data().toString())) else: self.model.removeRow(idx.row()) maxDel = max(maxDel, idx.row()) self.view.selectRow(maxDel+1) def keyPressEvent(self, event): """use insert/delete keys for insert/delete""" key = event.key() if key == Qt.Key_Insert: self.slotInsert() return QDialog.keyPressEvent(self, event)
class Games(QDialog): """a dialog for selecting a game""" def __init__(self, parent=None): super(Games, self).__init__(parent) self.selectedGame = None self.onlyPending = True self.setWindowTitle(m18nc('kajongg', 'Games') + ' - Kajongg') self.setObjectName('Games') self.resize(700, 400) self.model = GamesModel(self) if Debug.modelTest: self.modelTest = ModelTest(self.model, self) self.view = MJTableView(self) self.view.setModel(self.model) self.selection = QItemSelectionModel(self.model, self.view) self.view.setSelectionModel(self.selection) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSelectionMode(QAbstractItemView.SingleSelection) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel) self.newButton = self.buttonBox.addButton( m18nc('start a new game', "&New"), QDialogButtonBox.ActionRole) self.newButton.setIcon(KIcon("document-new")) self.newButton.clicked.connect(self.accept) self.loadButton = self.buttonBox.addButton(m18n("&Load"), QDialogButtonBox.AcceptRole) self.loadButton.clicked.connect(self.loadGame) self.loadButton.setIcon(KIcon("document-open")) self.deleteButton = self.buttonBox.addButton( m18n("&Delete"), QDialogButtonBox.ActionRole) self.deleteButton.setIcon(KIcon("edit-delete")) self.deleteButton.clicked.connect(self.delete) chkPending = QCheckBox(m18n("Show only pending games"), self) chkPending.setChecked(True) cmdLayout = QHBoxLayout() cmdLayout.addWidget(chkPending) cmdLayout.addWidget(self.buttonBox) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(cmdLayout) self.setLayout(layout) StateSaver(self) self.selection.selectionChanged.connect(self.selectionChanged) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.view.doubleClicked.connect(self.loadGame) chkPending.stateChanged.connect(self.pendingOrNot) def showEvent(self, dummyEvent): """only now get the data set. Not doing this in__init__ would eventually make it easier to subclass from some generic TableEditor class""" self.setQuery() self.view.initView() self.selectionChanged() def keyPressEvent(self, event): """use insert/delete keys for insert/delete""" key = event.key() if key == Qt.Key_Insert: self.newEntry() return if key == Qt.Key_Delete: self.delete() event.ignore() return QDialog.keyPressEvent(self, event) def selectionChanged(self): """update button states according to selection""" selectedRows = len(self.selection.selectedRows()) self.loadButton.setEnabled(selectedRows == 1) self.deleteButton.setEnabled(selectedRows >= 1) def setQuery(self): """define the query depending on self.OnlyPending""" query = "select g.id, g.starttime, " \ "p0.name||'///'||p1.name||'///'||p2.name||'///'||p3.name " \ "from game g, player p0," \ "player p1, player p2, player p3 " \ "where seed is null" \ " and p0.id=g.p0 and p1.id=g.p1 " \ " and p2.id=g.p2 and p3.id=g.p3 " \ "%s" \ "and exists(select 1 from score where game=g.id)" % \ ("and g.endtime is null " if self.onlyPending else "") self.model.setQuery(query, DBHandle.default) self.model.setHeaderData(1, Qt.Horizontal, QVariant(m18n("Started"))) self.model.setHeaderData(2, Qt.Horizontal, QVariant(m18n("Players"))) self.view.hideColumn(0) def __idxForGame(self, game): """returns the model index for game""" for row in range(self.model.rowCount()): if self.model.record(row).field(0).value().toInt()[0] == game: return self.model.index(row, 0) return self.model.index(0, 0) def pendingOrNot(self, chosen): """do we want to see all games or only pending games?""" if self.onlyPending != chosen: self.onlyPending = chosen idx = self.view.currentIndex() selectedGame = self.model.record(idx.row()).value(0).toInt()[0] self.setQuery() idx = self.__idxForGame(selectedGame) self.view.selectRow(idx.row()) self.view.setFocus() def loadGame(self): """load a game""" selnum = len(self.selection.selectedRows()) if selnum != 1: # should never happen logException('loadGame: %d rows selected' % selnum) idx = self.view.currentIndex() self.selectedGame = self.model.record(idx.row()).value(0).toInt()[0] self.buttonBox.accepted.emit() def delete(self): """delete a game""" def answered(result, games): """question answered, result is True or False""" if result: cmdList = [] for game in games: cmdList.append("DELETE FROM score WHERE game = %d" % game) cmdList.append("DELETE FROM game WHERE id = %d" % game) Query(cmdList) self.setQuery() # just reload entire table deleteGames = list(x.data().toInt()[0] for x in self.view.selectionModel().selectedRows(0)) if len(deleteGames) == 0: # should never happen logException('delete: 0 rows selected') WarningYesNo( m18n("Do you really want to delete <numid>%1</numid> games?<br>" \ "This will be final, you cannot cancel it with the cancel button", len(deleteGames))).addCallback(answered, deleteGames)
class PlayerList(QDialog): """QtSQL Model view of the players""" def __init__(self, parent): QDialog.__init__(self) self.parent = parent self.model = QSqlTableModel(self, DBHandle.default) self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.setTable("player") self.model.setSort(1, 0) self.model.setHeaderData(1, Qt.Horizontal, QVariant(m18nc("Player", "Name"))) self.model.setFilter( 'name not like "ROBOT %" and name not like "Robot %"') self.view = MJTableView(self) self.view.verticalHeader().show() self.view.setModel(self.model) self.view.hideColumn(0) self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.newButton = self.buttonBox.addButton( m18nc('define a new player', "&New"), QDialogButtonBox.ActionRole) self.newButton.setIcon(KIcon("document-new")) self.newButton.clicked.connect(self.slotInsert) self.deleteButton = self.buttonBox.addButton( m18n("&Delete"), QDialogButtonBox.ActionRole) self.deleteButton.setIcon(KIcon("edit-delete")) self.deleteButton.clicked.connect(self.delete) cmdLayout = QHBoxLayout() cmdLayout.addWidget(self.buttonBox) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(cmdLayout) self.setLayout(layout) self.setWindowTitle(m18n("Players") + ' - Kajongg') self.setObjectName('Players') def showEvent(self, dummyEvent): """adapt view to content""" if not self.model.select(): logError("PlayerList: select failed") sys.exit(1) self.view.initView() StateSaver(self, self.view.horizontalHeader()) if not self.view.isColumnHidden(2): # we loaded a kajonggrc written by an older kajongg version where this table # still had more columns. This should happen only once. self.view.hideColumn(2) self.view.hideColumn(3) def accept(self): """commit all modifications""" self.view.selectRow( 0) # if ALT-O is entered while editing a new row, this is one way # to end editing and to pass the new value to the model if not self.model.submitAll(): Sorry(m18n('Cannot save this. Possibly the name already exists. <br><br>' \ 'Message from database:<br><br><message>%1</message>', self.model.lastError().text())) return QDialog.accept(self) def slotInsert(self): """insert a record""" self.model.insertRow(self.model.rowCount()) self.view.selectRow(self.model.rowCount() - 1) def delete(self): """delete selected entries""" sel = self.view.selectionModel() maxDel = self.view.currentIndex().row() - 1 for idx in sel.selectedIndexes(): if idx.column() != 1: continue # sqlite3 does not enforce referential integrity. # we could add a trigger to sqlite3 but if it raises an exception # it will be thrown away silently. # if anybody knows how to propagate sqlite3 exceptions via QtSql # into python please tell me (wrohdewald) player = self.model.createIndex(idx.row(), 0).data().toInt()[0] # no query preparation, we don't expect lots of data if Query("select 1 from game where p0==%d or p1==%d or p2==%d or p3==%d" % \ (player, player, player, player)).records: Sorry( m18n( 'This player cannot be deleted. There are games associated with %1.', idx.data().toString())) else: self.model.removeRow(idx.row()) maxDel = max(maxDel, idx.row()) self.view.selectRow(maxDel + 1) def keyPressEvent(self, event): """use insert/delete keys for insert/delete""" key = event.key() if key == Qt.Key_Insert: self.slotInsert() return QDialog.keyPressEvent(self, event)