def refresh(self, game): """refresh for new values""" self.game = game lines = [] if self.game is None: lines.append(m18n('There is no active game')) else: i18nName = m18n(self.game.ruleset.name) lines.append(m18n('Ruleset: %1', i18nName)) lines.append('') for player in self.game.players: pLines = [] if player.hand and player.hand.tileNames: total = player.hand.total() if total: pLines = ['%s: %s' % (player.localName, total)] for line in player.hand.explain(): pLines.append('- ' + line) elif player.handTotal: pLines.append(m18n('Manual score for %1: %2 points', player.localName, player.handTotal)) if pLines: pLines.append('') lines.extend(pLines) if 'xxx'.join(lines) != 'xxx'.join(unicode(x) for x in self.model.stringList()): # QStringListModel does not optimize identical lists away, so we do self.model.setStringList(lines)
def __init__(self, url, username, password): MustChooseDialog.__init__(self, None) self.setWindowTitle(m18n('Create User Account') + ' - Kajongg') self.buttonBox = KDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) vbox = QVBoxLayout(self) grid = QFormLayout() self.lbServer = QLabel() self.lbServer.setText(url) grid.addRow(m18n('Game server:'), self.lbServer) self.lbUser = QLabel() grid.addRow(m18n('Username:'******'Password:'******'Repeat password:'), self.edPassword2) vbox.addLayout(grid) vbox.addWidget(self.buttonBox) pol = QSizePolicy() pol.setHorizontalPolicy(QSizePolicy.Expanding) self.lbUser.setSizePolicy(pol) self.edPassword.textChanged.connect(self.passwordChanged) self.edPassword2.textChanged.connect(self.passwordChanged) StateSaver(self) self.username = username self.password = password self.passwordChanged() self.edPassword2.setFocus()
def loadRules(self): ClassicalChinese.loadRules(self) # the squirming snake is only covered by standard mahjongg rule if tiles are ordered self.mjRules.add(Rule('Squirming Snake', 'FSquirmingSnake', limits=1, description=m18n('All tiles of same color. Pung or Kong of 1 and 9, pair of 2, 5 or 8 and two ' 'Chows of the remaining values'))) self.handRules.add(Rule('Little Three Dragons', 'FLittleThreeDragons', doubles=1, description=m18n('2 Pungs or Kongs of dragons and 1 pair of dragons'))) self.handRules.add(Rule('Big Three Dragons', 'FBigThreeDragons', doubles=2, description=m18n('3 Pungs or Kongs of dragons'))) self.handRules.add(Rule('Little Four Joys', 'FLittleFourJoys', doubles=1, description=m18n('3 Pungs or Kongs of winds and 1 pair of winds'))) self.handRules.add(Rule('Big Four Joys', 'FBigFourJoys', doubles=2, description=m18n('4 Pungs or Kongs of winds'))) self.winnerRules['Only Honors'].doubles = 2 self.penaltyRules.add(Rule('False Naming of Discard, Claimed for Chow', points = -50)) self.penaltyRules.add(Rule('False Naming of Discard, Claimed for Pung/Kong', points = -100)) self.penaltyRules.add(Rule('False Declaration of Mah Jongg by One Player', 'Oabsolute payees=3', points = -300)) self.penaltyRules.add(Rule('False Declaration of Mah Jongg by Two Players', 'Oabsolute payers=2 payees=2', points = -300)) self.penaltyRules.add(Rule('False Declaration of Mah Jongg by Three Players', 'Oabsolute payers=3', points = -300)) self.penaltyRules.add(Rule('False Naming of Discard, Claimed for Mah Jongg', 'Oabsolute payees=3', points = -300))
def setupUi(self): """create all Ui elements but do not fill them""" buttonBox = KDialogButtonBox(self) buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # Ubuntu 11.10 unity is a bit strange - without this, it sets focus on # the cancel button (which it shows on the left). I found no obvious # way to use setDefault and setAutoDefault for fixing this. buttonBox.button(QDialogButtonBox.Ok).setFocus(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) vbox = QVBoxLayout(self) self.grid = QFormLayout() self.cbServer = QComboBox() self.cbServer.setEditable(True) self.grid.addRow(m18n('Game server:'), self.cbServer) self.cbUser = QComboBox() self.cbUser.setEditable(True) self.grid.addRow(m18n('Username:'******'Password:'******'kajongg', 'Ruleset:'), self.cbRuleset) vbox.addLayout(self.grid) vbox.addWidget(buttonBox) pol = QSizePolicy() pol.setHorizontalPolicy(QSizePolicy.Expanding) self.cbUser.setSizePolicy(pol)
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 showMoveHelper(self, visible=True): """show help text In empty HandBoards""" if visible: if not self.__moveHelper: splitter = QGraphicsRectItem(self) hbCenter = self.rect().center() splitter.setRect(hbCenter.x() * 0.5, hbCenter.y(), hbCenter.x() * 1, 1) helpItems = [splitter] for name, yFactor in [(m18n('Move Exposed Tiles Here'), 0.5), (m18n('Move Concealed Tiles Here'), 1.5)]: helper = QGraphicsSimpleTextItem(name, self) helper.setScale(3) nameRect = QRectF() nameRect.setSize(helper.mapToParent(helper.boundingRect()).boundingRect().size()) center = QPointF(hbCenter) center.setY(center.y() * yFactor) helper.setPos(center - nameRect.center()) if self.sceneRotation() == 180: rotateCenter(helper, 180) helpItems.append(helper) self.__moveHelper = self.scene().createItemGroup(helpItems) self.__moveHelper.setVisible(True) else: if self.__moveHelper: self.__moveHelper.setVisible(False)
def __init__(self, url, username, password): MustChooseDialog.__init__(self, None) self.setWindowTitle(m18n('Create User Account') + ' - Kajongg') self.buttonBox = KDialogButtonBox(self) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) vbox = QVBoxLayout(self) grid = QFormLayout() self.lbServer = QLabel() self.lbServer.setText(url) grid.addRow(m18n('Game server:'), self.lbServer) self.lbUser = QLabel() grid.addRow(m18n('Username:'******'Password:'******'Repeat password:'), self.edPassword2) vbox.addLayout(grid) vbox.addWidget(self.buttonBox) pol = QSizePolicy() pol.setHorizontalPolicy(QSizePolicy.Expanding) self.lbUser.setSizePolicy(pol) self.edPassword.textChanged.connect(self.passwordChanged) self.edPassword2.textChanged.connect(self.passwordChanged) StateSaver(self) self.username = username self.password = password self.passwordChanged() self.edPassword2.setFocus()
def requestAvatarId(self, cred): # pylint: disable=R0201 """get user id from database""" args = cred.username.split(SERVERMARK) if len(args) > 1: if args[0] == 'adduser': cred.username = args[1] password = args[2] with Transaction(): query = Query('insert into player(name,password) values(?,?)', list([cred.username.decode('utf-8'), password.decode('utf-8')])) if not query.success: if query.msg.startswith('ERROR: constraint failed') \ or 'not unique' in query.msg: template = m18nE('User %1 already exists') logInfo(m18n(template, cred.username)) query.msg = srvMessage(template, cred.username) else: logInfo(query.msg) return fail(credError.UnauthorizedLogin(query.msg)) elif args[1] == 'deluser': pass query = Query('select id, password from player where name=?', list([cred.username.decode('utf-8')])) if not len(query.records): template = 'Wrong username: %1' logInfo(m18n(template, cred.username)) return fail(credError.UnauthorizedLogin(srvMessage(template, cred.username))) userid, password = query.records[0] # checkPassword uses md5 which cannot handle unicode strings (python 2.7) defer1 = maybeDeferred(cred.checkPassword, password.encode('utf-8')) defer1.addCallback(DBPasswordChecker._checkedPassword, userid) return defer1
def setupUi(self): """create all Ui elements but do not fill them""" buttonBox = KDialogButtonBox(self) buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) # Ubuntu 11.10 unity is a bit strange - without this, it sets focus on # the cancel button (which it shows on the left). I found no obvious # way to use setDefault and setAutoDefault for fixing this. buttonBox.button(QDialogButtonBox.Ok).setFocus(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) vbox = QVBoxLayout(self) self.grid = QFormLayout() self.cbServer = QComboBox() self.cbServer.setEditable(True) self.grid.addRow(m18n('Game server:'), self.cbServer) self.cbUser = QComboBox() self.cbUser.setEditable(True) self.grid.addRow(m18n('Username:'******'Password:'******'kajongg', 'Ruleset:'), self.cbRuleset) vbox.addLayout(self.grid) vbox.addWidget(buttonBox) pol = QSizePolicy() pol.setHorizontalPolicy(QSizePolicy.Expanding) self.cbUser.setSizePolicy(pol)
def toolTip(self, button, dummyTile): """decorate the action button which will send this message""" maySay = button.client.sayable[self] if not maySay: return '', False, '' myself = button.client.game.myself txt = [] warn = False if myself.originalCall and myself.mayWin: warn = True txt.append(m18n('saying %1 violates Original Call', self.i18nName)) dangerousMelds = button.client.maybeDangerous(self) if dangerousMelds: lastDiscardName = Meld.tileName(button.client.game.lastDiscard.element) warn = True if Debug.dangerousGame and len(dangerousMelds) != len(maySay): button.client.game.debug('only some claimable melds are dangerous: %s' % dangerousMelds) if len(dangerousMelds) == 1: txt.append(m18n( 'claiming %1 is dangerous because you will have to discard a dangerous tile', lastDiscardName)) else: for meld in dangerousMelds: txt.append(m18n( 'claiming %1 for %2 is dangerous because you will have to discard a dangerous tile', lastDiscardName, str(meld))) if not txt: txt = [m18n('You may say %1', self.i18nName)] return '<br><br>'.join(txt), warn, ''
def tooltip(self): """tooltip for rule: just the name of the ruleset""" ruleset = self.ruleset() if self.rawContent.description: return '<b>' + m18n(ruleset.name) + '</b><br><br>' + \ m18n(self.rawContent.description) else: return m18n(ruleset.name)
def loadRules(self): ClassicalChinese.loadRules(self) # the squirming snake is only covered by standard mahjongg rule if tiles are ordered self.mjRules.add( Rule( 'Squirming Snake', 'FSquirmingSnake', limits=1, description=m18n( 'All tiles of same color. Pung or Kong of 1 and 9, pair of 2, 5 or 8 and two ' 'Chows of the remaining values'))) self.handRules.add( Rule('Little Three Dragons', 'FLittleThreeDragons', doubles=1, description=m18n( '2 Pungs or Kongs of dragons and 1 pair of dragons'))) self.handRules.add( Rule('Big Three Dragons', 'FBigThreeDragons', doubles=2, description=m18n('3 Pungs or Kongs of dragons'))) self.handRules.add( Rule('Little Four Joys', 'FLittleFourJoys', doubles=1, description=m18n( '3 Pungs or Kongs of winds and 1 pair of winds'))) self.handRules.add( Rule('Big Four Joys', 'FBigFourJoys', doubles=2, description=m18n('4 Pungs or Kongs of winds'))) self.winnerRules['Only Honors'].doubles = 2 self.penaltyRules.add( Rule('False Naming of Discard, Claimed for Chow', points=-50)) self.penaltyRules.add( Rule('False Naming of Discard, Claimed for Pung/Kong', points=-100)) self.penaltyRules.add( Rule('False Declaration of Mah Jongg by One Player', 'Oabsolute payees=3', points=-300)) self.penaltyRules.add( Rule('False Declaration of Mah Jongg by Two Players', 'Oabsolute payers=2 payees=2', points=-300)) self.penaltyRules.add( Rule('False Declaration of Mah Jongg by Three Players', 'Oabsolute payers=3', points=-300)) self.penaltyRules.add( Rule('False Naming of Discard, Claimed for Mah Jongg', 'Oabsolute payees=3', points=-300))
def __init__(self, swappers): QMessageBox.__init__(self) self.setWindowTitle(m18n("Swap Seats") + ' - Kajongg') self.setText(m18n("By the rules, %1 and %2 should now exchange their seats. ", swappers[0].name, swappers[1].name)) self.yesAnswer = QPushButton(m18n("&Exchange")) self.addButton(self.yesAnswer, QMessageBox.YesRole) self.noAnswer = QPushButton(m18n("&Keep seat")) self.addButton(self.noAnswer, QMessageBox.NoRole)
def __init__(self, swappers): QMessageBox.__init__(self) self.setWindowTitle(m18n("Swap Seats") + ' - Kajongg') self.setText( m18n("By the rules, %1 and %2 should now exchange their seats. ", swappers[0].name, swappers[1].name)) self.yesAnswer = QPushButton(m18n("&Exchange")) self.addButton(self.yesAnswer, QMessageBox.YesRole) self.noAnswer = QPushButton(m18n("&Keep seat")) self.addButton(self.noAnswer, QMessageBox.NoRole)
def __init__(self, parent, name): super(ConfigDialog, self).__init__(parent, QString(name), Preferences) self.pages = [ self.addPage(PlayConfigTab(self), m18nc('kajongg','Play'), "arrow-right"), self.addPage(TilesetSelector(self), m18n("Tiles"), "games-config-tiles"), self.addPage(BackgroundSelector(self), m18n("Backgrounds"), "games-config-background")] StateSaver(self)
def __init__(self, parent, name): super(ConfigDialog, self).__init__(parent, QString(name), Preferences) self.pages = [ self.addPage(PlayConfigTab(self), m18nc('kajongg', 'Play'), "arrow-right"), self.addPage(TilesetSelector(self), m18n("Tiles"), "games-config-tiles"), self.addPage(BackgroundSelector(self), m18n("Backgrounds"), "games-config-background") ] StateSaver(self)
def __init__(self, client): super(TableList, self).__init__(None) self.autoStarted = False self.client = client self.setObjectName('TableList') self.resize(700, 400) self.view = MJTableView(self) self.differ = None self.debugModelTest = None self.requestedNewTable = False self.view.setItemDelegateForColumn(2, RichTextColumnDelegate(self.view)) buttonBox = QDialogButtonBox(self) self.newButton = buttonBox.addButton( m18nc('allocate a new table', "&New"), QDialogButtonBox.ActionRole) self.newButton.setIcon(KIcon("document-new")) self.newButton.setToolTip(m18n("Allocate a new table")) self.newButton.clicked.connect(self.client.newTable) self.joinButton = buttonBox.addButton(m18n("&Join"), QDialogButtonBox.AcceptRole) self.joinButton.clicked.connect(client.joinTable) self.joinButton.setIcon(KIcon("list-add-user")) self.joinButton.setToolTip(m18n("Join a table")) self.leaveButton = buttonBox.addButton(m18n("&Leave"), QDialogButtonBox.AcceptRole) self.leaveButton.clicked.connect(self.leaveTable) self.leaveButton.setIcon(KIcon("list-remove-user")) self.leaveButton.setToolTip(m18n("Leave a table")) self.compareButton = buttonBox.addButton( m18nc('Kajongg-Ruleset', 'Compare'), QDialogButtonBox.AcceptRole) self.compareButton.clicked.connect(self.compareRuleset) self.compareButton.setIcon(KIcon("preferences-plugin-script")) self.compareButton.setToolTip( m18n('Compare the rules of this table with my own rulesets')) self.chatButton = buttonBox.addButton(m18n('&Chat'), QDialogButtonBox.AcceptRole) self.chatButton.setIcon(KIcon("call-start")) self.chatButton.clicked.connect(self.chat) self.startButton = buttonBox.addButton(m18n('&Start'), QDialogButtonBox.AcceptRole) self.startButton.clicked.connect(self.startGame) self.startButton.setIcon(KIcon("arrow-right")) self.startButton.setToolTip( m18n( "Start playing on a table. Empty seats will be taken by robot players." )) cmdLayout = QHBoxLayout() cmdLayout.addWidget(buttonBox) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(cmdLayout) self.setLayout(layout) self.view.doubleClicked.connect(client.joinTable) StateSaver(self, self.view.horizontalHeader()) self.updateButtonsForTable(None)
def __init__(self, desktopFileName=None): if desktopFileName is None: desktopFileName = 'default' self.tileSize = None self.faceSize = None self.__renderer = None self.__shadowOffsets = None self.defineCatalog() self.path = locateTileset(desktopFileName + '.desktop') if self.path.isEmpty(): self.path = locateTileset('default.desktop') if self.path.isEmpty(): directories = '\n\n' +'\n'.join(str(x) for x in KGlobal.dirs().resourceDirs("kmahjonggtileset")) logException(TileException(m18n( \ 'cannot find any tileset in the following directories, is libkmahjongg installed?') + directories)) else: logWarning(m18n('cannot find tileset %1, using default', desktopFileName)) self.desktopFileName = 'default' else: self.desktopFileName = desktopFileName self.darkenerAlpha = 120 if self.desktopFileName == 'jade' else 50 tileconfig = KConfig(self.path, KConfig.SimpleConfig) group = KConfigGroup(tileconfig.group("KMahjonggTileset")) self.name = group.readEntry("Name", "unknown tileset").toString() # Returns translated data self.author = group.readEntry("Author", "unknown author").toString() self.description = group.readEntry("Description", "no description available").toString() self.authorEmail = group.readEntry("AuthorEmail", "no E-Mail address available").toString() #Version control tileversion, entryOK = group.readEntry("VersionFormat", QVariant(0)).toInt() #Format is increased when we have incompatible changes, meaning that # older clients are not able to use the remaining information safely if not entryOK or tileversion > TILESETVERSIONFORMAT: logException(TileException('tileversion file / program: %d/%d' % \ (tileversion, TILESETVERSIONFORMAT))) graphName = QString(group.readEntry("FileName")) self.__graphicspath = locateTileset(graphName) if self.__graphicspath.isEmpty(): logException(TileException('cannot find kmahjongglib/tilesets/%s for %s' % \ (graphName, self.desktopFileName ))) self.renderer() # now that we get the sizes from the svg, we need the renderer right away self.svgName = { 'wn': 'WIND_1', 'ws': 'WIND_2', 'we': 'WIND_3', 'ww': 'WIND_4', 'db': 'DRAGON_1', 'dg': 'DRAGON_2', 'dr': 'DRAGON_3'} for value in '123456789': self.svgName['s%s' % value] = 'ROD_%s' % value self.svgName['b%s' % value] = 'BAMBOO_%s' % value self.svgName['c%s' % value] = 'CHARACTER_%s' % value for idx, wind in enumerate('eswn'): self.svgName['f%s' % wind] = 'FLOWER_%d' % (idx + 1) self.svgName['y%s' % wind] = 'SEASON_%d' % (idx + 1)
def __init__(self, desktopFileName=None): if desktopFileName is None: desktopFileName = 'default' self.__svg = None self.__pmap = None QPixmapCache.setCacheLimit(20480) # the chinese landscape needs much self.defineCatalog() self.desktopFileName = desktopFileName self.path = locatebackground(desktopFileName + '.desktop') if self.path.isEmpty(): self.path = locatebackground('default.desktop') if self.path.isEmpty(): directories = '\n\n' + '\n'.join( str(x) for x in KGlobal.dirs().resourceDirs( "kmahjonggbackground")) logException(BackgroundException(m18n( \ 'cannot find any background in the following directories, is libkmahjongg installed?') + directories)) else: logWarning( m18n('cannot find background %1, using default', desktopFileName)) self.desktopFileName = 'default' config, group = konfigGroup(self.path, "KMahjonggBackground") assert config self.name = group.readEntry( "Name", "unknown background").toString() # Returns translated data #Version control backgroundversion, entryOK = group.readEntry("VersionFormat", QVariant(0)).toInt() #Format is increased when we have incompatible changes, meaning that # older clients are not able to use the remaining information safely if not entryOK or backgroundversion > BACKGROUNDVERSIONFORMAT: logException(BackgroundException('backgroundversion file / program: %d/%d' % \ (backgroundversion, BACKGROUNDVERSIONFORMAT))) self.tiled = group.readEntry('Tiled') == '1' if self.tiled: self.imageWidth, entryOk = group.readEntry('Width').toInt() if not entryOk: raise Exception('cannot scan Width from background file') self.imageHeight, entryOk = group.readEntry('Height').toInt() if not entryOk: raise Exception('cannot scan Height from background file') self.isPlain = bool(group.readEntry('Plain')) if not self.isPlain: graphName = QString(group.readEntry("FileName")) self.__graphicspath = locatebackground(graphName) if self.__graphicspath.isEmpty(): logException(BackgroundException( 'cannot find kmahjongglib/backgrounds/%s for %s' % \ (graphName, self.desktopFileName )))
def toolTip(self, button, tile): """decorate the action button which will send this message""" myself = button.client.game.myself isCalling = bool((myself.hand - tile.element).callingHands()) if not isCalling: txt = m18n('discarding %1 and declaring Original Call makes this hand unwinnable', Meld.tileName(tile.element)) return txt, True, txt else: return (m18n( 'Discard a tile, declaring Original Call meaning you need only one ' 'tile to complete the hand and will not alter the hand in any way (except bonus tiles)'), False, '')
def addParameterRules(self): """as the name says""" self.parameterRules.add( Rule('Points Needed for Mah Jongg', 'intminMJPoints||Omandatory', parameter=0)) self.parameterRules.add( Rule('Minimum number of doubles needed for Mah Jongg', 'intminMJDoubles||OMandatory', parameter=0)) self.parameterRules.add( Rule('Points for a Limit Hand', 'intlimit||Omandatory||Omin=1', parameter=500)) self.parameterRules.add( Rule('Play with the roof off', 'boolroofOff||Omandatory', parameter=False, description=m18n('Play with no upper scoring limit'))) self.parameterRules.add( Rule('Claim Timeout', 'intclaimTimeout||Omandatory', parameter=10)) self.parameterRules.add( Rule( 'Size of Kong Box', 'intkongBoxSize||Omandatory', parameter=16, description=m18n( 'The Kong Box is used for replacement tiles when declaring kongs' ))) self.parameterRules.add( Rule('Play with Bonus Tiles', 'boolwithBonusTiles||OMandatory', parameter=True, description=m18n('Bonus tiles increase the luck factor'))) self.parameterRules.add( Rule('Minimum number of rounds in game', 'intminRounds||OMandatory', parameter=4)) self.parameterRules.add( Rule('number of allowed chows', 'intmaxChows||Omandatory', parameter=4, description=m18n('The number of chows a player may build'))) self.parameterRules.add( Rule( 'must declare calling hand', 'boolmustDeclareCallingHand||Omandatory', parameter=False, description=m18n( 'Mah Jongg is only allowed after having declared to have a calling hand' )))
def _loginReallyFailed(self, failure): """login failed, not fixable by adding missing user""" msg = self._prettifyErrorMessage(failure) if failure.check(CancelledError): # show no warning, just leave return failure if 'Errno 5' in msg: # The server is running but something is wrong with it if self.useSocket and os.name != 'nt': if removeIfExists(socketName()): logInfo(m18n('removed stale socket <filename>%1</filename>', socketName())) msg += '\n\n\n' + m18n('Please try again') logWarning(msg) return failure
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 headerData(self, section, orientation, role): """tell the view about the wanted headers""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return QVariant(int(Qt.AlignLeft | Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation == Qt.Horizontal: if section == 0: return QVariant(m18nc("Kajongg", "Rule")) if section == 1: return QVariant(m18n(self.view.cbRuleset1.current.name)) if section == 2: return QVariant(m18n(self.view.cbRuleset2.current.name)) return QVariant()
def headerData(self, section, orientation, role): """tell the view about the wanted headers""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return QVariant(int(Qt.AlignLeft | Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation == Qt.Horizontal: if section == 0: return QVariant(m18nc('Kajongg', 'Rule')) if section == 1: return QVariant(m18n(self.view.cbRuleset1.current.name)) if section == 2: return QVariant(m18n(self.view.cbRuleset2.current.name)) return QVariant()
def __init__(self, client): super(TableList, self).__init__(None) self.autoStarted = False self.client = client self.setObjectName('TableList') self.resize(700, 400) self.view = MJTableView(self) self.differ = None self.debugModelTest = None self.__requestedNewTable = False self.view.setItemDelegateForColumn(2, RichTextColumnDelegate(self.view)) buttonBox = QDialogButtonBox(self) self.newButton = buttonBox.addButton(m18n("&New"), QDialogButtonBox.ActionRole) self.newButton.setIcon(KIcon("document-new")) self.newButton.setToolTip(m18n("Allocate a new table")) self.newButton.clicked.connect(self.newTable) self.joinButton = buttonBox.addButton(m18n("&Join"), QDialogButtonBox.AcceptRole) self.joinButton.clicked.connect(self.joinTable) self.joinButton.setIcon(KIcon("list-add-user")) self.joinButton.setToolTip(m18n("Join a table")) self.leaveButton = buttonBox.addButton(m18n("&Leave"), QDialogButtonBox.AcceptRole) self.leaveButton.clicked.connect(self.leaveTable) self.leaveButton.setIcon(KIcon("list-remove-user")) self.leaveButton.setToolTip(m18n("Leave a table")) self.compareButton = buttonBox.addButton(m18nc('Kajongg-Ruleset','Compare'), QDialogButtonBox.AcceptRole) self.compareButton.clicked.connect(self.compareRuleset) self.compareButton.setIcon(KIcon("preferences-plugin-script")) self.compareButton.setToolTip(m18n('Compare the rules of this table with my own rulesets')) self.chatButton = buttonBox.addButton(m18n('&Chat'), QDialogButtonBox.AcceptRole) self.chatButton.setIcon(KIcon("call-start")) self.chatButton.clicked.connect(self.chat) self.startButton = buttonBox.addButton(m18n('&Start'), QDialogButtonBox.AcceptRole) self.startButton.clicked.connect(self.startGame) self.startButton.setIcon(KIcon("arrow-right")) self.startButton.setToolTip(m18n("Start playing on a table. Empty seats will be taken by robot players.")) cmdLayout = QHBoxLayout() cmdLayout.addWidget(buttonBox) layout = QVBoxLayout() layout.addWidget(self.view) layout.addLayout(cmdLayout) self.setLayout(layout) self.view.doubleClicked.connect(self.joinTable) StateSaver(self, self.view.horizontalHeader()) self.updateButtonsForTable(None)
def __init__(self, game): """selection for this player, tiles are the still available tiles""" QDialog.__init__(self, None) self.setWindowTitle(m18n("Penalty") + ' - Kajongg') self.game = game grid = QGridLayout(self) lblOffense = QLabel(m18n('Offense:')) crimes = list([x for x in game.ruleset.penaltyRules if not ('absolute' in x.options and game.winner)]) self.cbCrime = ListComboBox(crimes) lblOffense.setBuddy(self.cbCrime) grid.addWidget(lblOffense, 0, 0) grid.addWidget(self.cbCrime, 0, 1, 1, 4) lblPenalty = QLabel(m18n('Total Penalty')) self.spPenalty = PenaltyBox(2) self.spPenalty.setRange(0, 9999) lblPenalty.setBuddy(self.spPenalty) self.lblUnits = QLabel(m18n('points')) grid.addWidget(lblPenalty, 1, 0) grid.addWidget(self.spPenalty, 1, 1) grid.addWidget(self.lblUnits, 1, 2) self.payers = [] self.payees = [] # a penalty can never involve the winner, neither as payer nor as payee for idx in range(3): self.payers.append(ListComboBox(game.losers())) self.payees.append(ListComboBox(game.losers())) for idx, payer in enumerate(self.payers): grid.addWidget(payer, 3+idx, 0) payer.lblPayment = QLabel() grid.addWidget(payer.lblPayment, 3+idx, 1) for idx, payee in enumerate(self.payees): grid.addWidget(payee, 3+idx, 3) payee.lblPayment = QLabel() grid.addWidget(payee.lblPayment, 3+idx, 4) grid.addWidget(QLabel(''), 6, 0) grid.setRowStretch(6, 10) for player in self.payers + self.payees: player.currentIndexChanged.connect(self.playerChanged) self.spPenalty.valueChanged.connect(self.penaltyChanged) self.cbCrime.currentIndexChanged.connect(self.crimeChanged) buttonBox = KDialogButtonBox(self) grid.addWidget(buttonBox, 7, 0, 1, 5) buttonBox.setStandardButtons(QDialogButtonBox.Cancel) buttonBox.rejected.connect(self.reject) self.btnExecute = buttonBox.addButton(m18n("&Execute"), QDialogButtonBox.AcceptRole, self, SLOT("accept()")) self.crimeChanged() StateSaver(self)
def headerData(self, section, orientation, role=Qt.DisplayRole): # pylint: disable=R0201 """show header""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: if section == 1: return QVariant(int(Qt.AlignRight)) else: return QVariant(int(Qt.AlignLeft)) if orientation != Qt.Horizontal: return QVariant(int(section+1)) if role != Qt.DisplayRole: return QVariant() result = '' if section < self.columnCount(): result = [m18n('Time'), m18n('Player'), m18n('Message')][section] return QVariant(result)
def _prettifyErrorMessage(self, failure): """instead of just failure.getErrorMessage(), return something more user friendly. That will be a localized error text, the original english text will be removed""" url = self.url message = failure.getErrorMessage() match = re.search(r".*gaierror\(-\d, '(.*)'.*", message) if not match: match = re.search(r".*ConnectError\('(.*)',\)", message) if not match: match = re.search(r".*ConnectionRefusedError\('(.*)',\)", message) if not match: match = re.search(r".*DNS lookup.*\[Errno -5\] (.*)", message) if match: url = url.split(':')[0] # remove the port # current twisted (version 12.3) returns different messages: if not match: match = re.search( r".*DNS lookup failed: address u'(.*)' not found.*", message) if match: return u'%s: %s' % (match.group( 1), m18n('DNS lookup failed, address not found')) if not match: match = re.search(r".*DNS lookup.*\[Errno 110\] (.*)", message) if not match: match = re.search(r".*while connecting: 113: (.*)", message) if match: message = match.group(1).decode('string-escape').decode( 'string-escape') return u'%s: %s' % (url, message.decode('utf-8'))
def data(self, index, role=Qt.DisplayRole): """score table""" result = QVariant() if role == Qt.TextAlignmentRole: if index.column() == 1: return QVariant(int(Qt.AlignRight)) else: return QVariant(int(Qt.AlignLeft)) if index.isValid() and (0 <= index.row() < len(self.chatLines)): chatLine = self.chatLines[index.row()] if role == Qt.DisplayRole and index.column() == 0: local = chatLine.localtimestamp() result = QVariant('%02d:%02d:%02d' % ( local.hour, local.minute, local.second)) elif role == Qt.DisplayRole and index.column() == 1: result = QVariant(chatLine.fromUser) elif role == Qt.DisplayRole and index.column() == 2: result = QVariant(m18n(chatLine.message)) elif role == Qt.ForegroundRole and index.column() == 2: palette = KApplication.palette() color = 'blue' if chatLine.isStatusMessage else palette.windowText() result = QVariant(QColor(color)) return result
def assertConnectivity(self, result): """make sure we have a running local server or network connectivity""" if self.useSocket or self.dlg.url in ('localhost', '127.0.0.1'): if not self.serverListening(): if os.name == 'nt': port = self.findFreePort() else: port = None self.startLocalServer(port) # give the server up to 5 seconds time to start for loop in range(50): if self.serverListening(): break time.sleep(0.1) elif which('qdbus'): # the state of QtDBus is unclear to me. # riverbank.computing says module dbus is deprecated # for Python 3. And Ubuntu has no package with # PyQt4.QtDBus. So we use good old subprocess. answer = subprocess.Popen(['qdbus', 'org.kde.kded', '/modules/networkstatus', 'org.kde.Solid.Networking.status'], stdout=subprocess.PIPE).communicate()[0].strip() if answer != '4': # pylint: disable=W0710 raise Failure(m18n('You have no network connectivity: %1', answer)) return result
def setupUi(self): """layout the window""" self.setWindowTitle(m18n('Customize rulesets') + ' - Kajongg') self.setObjectName('Rulesets') hlayout = QHBoxLayout(self) v1layout = QVBoxLayout() self.v1widget = QWidget() v1layout = QVBoxLayout(self.v1widget) v2layout = QVBoxLayout() hlayout.addWidget(self.v1widget) hlayout.addLayout(v2layout) for widget in [self.v1widget, hlayout, v1layout, v2layout]: widget.setContentsMargins(0, 0, 0, 0) hlayout.setStretchFactor(self.v1widget, 10) self.btnCopy = QPushButton() self.btnRemove = QPushButton() self.btnCompare = QPushButton() self.btnClose = QPushButton() self.rulesetView = RuleTreeView(m18nc('kajongg','Rule'), self.btnCopy, self.btnRemove, self.btnCompare) v1layout.addWidget(self.rulesetView) self.rulesetView.setWordWrap(True) self.rulesetView.setMouseTracking(True) spacerItem = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) v2layout.addWidget(self.btnCopy) v2layout.addWidget(self.btnRemove) v2layout.addWidget(self.btnCompare) self.btnCopy.clicked.connect(self.rulesetView.copyRow) self.btnRemove.clicked.connect(self.rulesetView.removeRow) self.btnCompare.clicked.connect(self.rulesetView.compareRow) self.btnClose.clicked.connect(self.hide) v2layout.addItem(spacerItem) v2layout.addWidget(self.btnClose) self.retranslateUi() StateSaver(self) self.show()
def _prettifyErrorMessage(self, failure): """instead of just failure.getErrorMessage(), return something more user friendly. That will be a localized error text, the original english text will be removed""" url = self.url message = failure.getErrorMessage() match = re.search(r".*gaierror\(-\d, '(.*)'.*", message) if not match: match = re.search(r".*ConnectError\('(.*)',\)", message) if not match: match = re.search(r".*ConnectionRefusedError\('(.*)',\)", message) if not match: match = re.search(r".*DNS lookup.*\[Errno -5\] (.*)", message) if match: url = url.split(':')[0] # remove the port # current twisted (version 12.3) returns different messages: if not match: match = re.search(r".*DNS lookup failed: address u'(.*)' not found.*", message) if match: return u'%s: %s' % (match.group(1), m18n('DNS lookup failed, address not found')) if not match: match = re.search(r".*DNS lookup.*\[Errno 110\] (.*)", message) if not match: match = re.search(r".*while connecting: 113: (.*)", message) if match: message = match.group(1).decode('string-escape').decode('string-escape') return u'%s: %s' % (url, message.decode('utf-8'))
def remote_tableRemoved(self, tableid, message, *args): """update table list""" Client.remote_tableRemoved(self, tableid, message, *args) self.__updateTableList() if message: if not self.name in args or not message.endswith('has logged out'): logWarning(m18n(message, *args))
def serverListening(self): """is somebody listening on that port?""" if self.useSocket and os.name != 'nt': sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.settimeout(1) try: sock.connect(socketName()) except socket.error as exception: if os.path.exists(socketName()): # try again, avoiding a race try: sock.connect(socketName()) except socket.error as exception: if removeIfExists(socketName()): logInfo( m18n( 'removed stale socket <filename>%1</filename>', socketName())) logInfo('socket error:%s' % str(exception)) return False else: return True else: return True else: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) try: sock.connect((self.dlg.host, self.dlg.port)) except socket.error: return False else: return True
def abort(self): """abort current game""" def gotAnswer(result, autoPlaying): """user answered""" if result: return self.abortGame() else: self.actionAutoPlay.setChecked(autoPlaying) return fail(Exception('no abort')) def gotError(result): """abortGame failed""" logDebug('abortGame error:%s/%s ' % (str(result), result.getErrorMessage())) if not self.game: self.startingGame = False return succeed(None) autoPlaying = self.actionAutoPlay.isChecked() self.actionAutoPlay.setChecked(False) if self.game.finished(): return self.abortGame() else: return QuestionYesNo( m18n("Do you really want to abort this game?"), always=True).addCallback(gotAnswer, autoPlaying).addErrback(gotError)
def __init__(self, game): SelectRuleset.__init__(self) self.game = game Players.load() self.setWindowTitle(m18n('Select four players') + ' - Kajongg') self.names = None self.nameWidgets = [] for idx, wind in enumerate(WINDS): cbName = QComboBox() cbName.manualSelect = False # increase width, we want to see the full window title cbName.setMinimumWidth(350) # is this good for all platforms? cbName.addItems(Players.humanNames.values()) self.grid.addWidget(cbName, idx + 1, 1) self.nameWidgets.append(cbName) self.grid.addWidget(WindLabel(wind), idx + 1, 0) cbName.currentIndexChanged.connect(self.slotValidate) query = Query( "select p0,p1,p2,p3 from game where seed is null and game.id = (select max(id) from game)" ) if len(query.records): for pidx, playerId in enumerate(query.records[0]): try: playerName = Players.humanNames[playerId] cbName = self.nameWidgets[pidx] playerIdx = cbName.findText(playerName) if playerIdx >= 0: cbName.setCurrentIndex(playerIdx) except KeyError: logError('database is inconsistent: player with id %d is in game but not in player' \ % playerId) self.slotValidate()
def serverListening(self): """is somebody listening on that port?""" if self.useSocket and os.name != 'nt': sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.settimeout(1) try: sock.connect(socketName()) except socket.error as exception: if os.path.exists(socketName()): # try again, avoiding a race try: sock.connect(socketName()) except socket.error as exception: if removeIfExists(socketName()): logInfo(m18n('removed stale socket <filename>%1</filename>', socketName())) logInfo('socket error:%s' % str(exception)) return False else: return True else: return True else: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1) try: sock.connect((self.dlg.host, self.dlg.port)) except socket.error: return False else: return True
def startLocalServer(self, port): """start a local server""" try: args = ['kajonggserver'] # the default if sys.argv[0].endswith('kajongg.py'): tryServer = sys.argv[0].replace('.py', 'server.py') if os.path.exists(tryServer): args = ['python', tryServer] if self.useSocket or os.name == 'nt': args.append('--local') if port: args.append('--port=%d' % port) if self.useSocket: args.append('--db=%slocal.db' % appdataDir()) if Debug.argString: args.append('--debug=%s' % Debug.argString) if Options.socket: args.append('--socket=%s' % Options.socket) process = subprocess.Popen(args, shell=os.name == 'nt') if Debug.connections: logDebug( m18n( 'started the local kajongg server: pid=<numid>%1</numid> %2', process.pid, ' '.join(args))) except OSError as exc: logException(exc)
def readyForGameStart(self, tableid, gameid, wantedGame, playerNames, shouldSave=True): """playerNames are in wind order ESWN""" def answered(result): """callback, called after the client player said yes or no""" self.beginQuestion = None if self.connection and result: # still connected and yes, we are Client.readyForGameStart(self, tableid, gameid, wantedGame, playerNames, shouldSave) return Message.OK else: return Message.NoGameStart def cancelled(dummy): """the user does not want to start now. Back to table list""" if Debug.table: logDebug('%s: Readyforgamestart returns Message.NoGameStart for table %s' % ( self.name, self._tableById(tableid))) self.table = None self.beginQuestion = None if self.tableList: self.__updateTableList() self.tableList.show() return Message.NoGameStart if sum(not x[1].startswith('Robot ') for x in playerNames) == 1: # we play against 3 robots and we already told the server to start: no need to ask again return Client.readyForGameStart(self, tableid, gameid, wantedGame, playerNames, shouldSave) assert not self.table assert self.tables self.table = self._tableById(tableid) if not self.table: raise pb.Error('client.readyForGameStart: tableid %d unknown' % tableid) msg = m18n("The game on table <numid>%1</numid> can begin. Are you ready to play now?", tableid) self.beginQuestion = QuestionYesNo(msg, modal=False, caption=self.name).addCallback( answered).addErrback(cancelled) return self.beginQuestion
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 notifyAction(self, client, move): if client.beginQuestion or client.game: Sorry(m18n('%1 is not ready to start the game', move.player.name)) if client.beginQuestion: client.beginQuestion.cancel() elif client.game: return client.game.close()
def __checkExistingConnections(self): """do we already have a connection to the wanted URL?""" for client in self.client.humanClients: if client.connection and client.connection.url == self.url: logWarning(m18n('You are already connected to server %1', self.url)) client.tableList.activateWindow() raise CancelledError
def validateParameter(self): """check for validity""" if 'min' in self.options: minValue = self.parType(self.options['min']) if self.parameter < minValue: return m18nc('wrong value for rule', '%1: %2 is too small, minimal value is %3', m18n(self.name), self.parameter, minValue)
def assertConnectivity(self, result): """make sure we have a running local server or network connectivity""" if self.useSocket or self.dlg.url in ('localhost', '127.0.0.1'): if not self.serverListening(): if os.name == 'nt': port = self.findFreePort() else: port = None self.startLocalServer(port) # give the server up to 5 seconds time to start for loop in range(50): if self.serverListening(): break time.sleep(0.1) elif which('qdbus'): # the state of QtDBus is unclear to me. # riverbank.computing says module dbus is deprecated # for Python 3. And Ubuntu has no package with # PyQt4.QtDBus. So we use good old subprocess. answer = subprocess.Popen( [ 'qdbus', 'org.kde.kded', '/modules/networkstatus', 'org.kde.Solid.Networking.status' ], stdout=subprocess.PIPE).communicate()[0].strip() if answer != '4': # pylint: disable=W0710 raise Failure( m18n('You have no network connectivity: %1', answer)) return result
def __saveScores(self): """save computed values to database, update score table and balance in status line""" if not self.__needSave(): return scoretime = datetime.datetime.now().replace(microsecond=0).isoformat() for player in self.players: if player.hand: manualrules = '||'.join(x.rule.name for x in player.hand.usedRules) else: manualrules = m18n('Score computed manually') Query("INSERT INTO SCORE " "(game,hand,data,manualrules,player,scoretime,won,prevailing,wind," "points,payments, balance,rotated,notrotated) " "VALUES(%d,%d,?,?,%d,'%s',%d,'%s','%s',%d,%d,%d,%d,%d)" % \ (self.gameid, self.handctr, player.nameid, scoretime, int(player == self.__winner), WINDS[self.roundsFinished % 4], player.wind, player.handTotal, player.payment, player.balance, self.rotated, self.notRotated), list([player.hand.string, manualrules])) if Debug.scores: self.debug('%s: handTotal=%s balance=%s %s' % ( player, player.handTotal, player.balance, 'won' if player == self.winner else '')) for usedRule in player.hand.usedRules: rule = usedRule.rule if rule.score.limits: tag = rule.function.__class__.__name__ if hasattr(rule.function, 'limitHand'): tag = rule.function.limitHand.__class__.__name__ self.addCsvTag(tag)
def __init__(self, game): SelectRuleset.__init__(self) self.game = game Players.load() self.setWindowTitle(m18n('Select four players') + ' - Kajongg') self.names = None self.nameWidgets = [] for idx, wind in enumerate(WINDS): cbName = QComboBox() cbName.manualSelect = False # increase width, we want to see the full window title cbName.setMinimumWidth(350) # is this good for all platforms? cbName.addItems(Players.humanNames.values()) self.grid.addWidget(cbName, idx+1, 1) self.nameWidgets.append(cbName) self.grid.addWidget(WindLabel(wind), idx+1, 0) cbName.currentIndexChanged.connect(self.slotValidate) query = Query("select p0,p1,p2,p3 from game where seed is null and game.id = (select max(id) from game)") if len(query.records): for pidx, playerId in enumerate(query.records[0]): try: playerName = Players.humanNames[playerId] cbName = self.nameWidgets[pidx] playerIdx = cbName.findText(playerName) if playerIdx >= 0: cbName.setCurrentIndex(playerIdx) except KeyError: logError('database is inconsistent: player with id %d is in game but not in player' \ % playerId) self.slotValidate()
def __init__(self, table=None, game=None): super(ChatWindow, self).__init__(None) self.table = table or game.client.table self.table.chatWindow = self title = m18n('Chat on table %1 at %2', self.table.tableid, self.table.client.connection.url) self.setObjectName('chatWindow') self.setWindowTitle(title + ' - kajongg') self.messageView = ChatView() self.messageView.setModel(ChatModel()) self.messageView.setFocusPolicy(Qt.NoFocus) self.messageView.setShowGrid(False) self.messageView.setWordWrap(False) self.messageView.setSelectionMode(QAbstractItemView.NoSelection) if Debug.modelTest: self.debugModelTest = ModelTest(self.messageView.model(), self.messageView) self.edit = QLineEdit() layout = QVBoxLayout() layout.addWidget(self.messageView) layout.addWidget(self.edit) self.setLayout(layout) self.edit.returnPressed.connect(self.sendLine) self.edit.setFocus() self.show() StateSaver(self)
def tableChanged(self, table): """update table list""" oldTable, newTable = Client.tableChanged(self, table) if oldTable and oldTable == self.table: # this happens if a table has more than one human player and # one of them leaves the table. In that case, the other players # need this code. self.table = newTable if len(newTable.playerNames) == 3: # only tell about the first player leaving, because the # others will then automatically leave too for name in oldTable.playerNames: if name != self.name and not newTable.isOnline(name): def sorried(dummy): """user ack""" game = self.game if game: self.game = None return game.close() if self.beginQuestion: self.beginQuestion.cancel() Sorry(m18n('Player %1 has left the table', name)).addCallback( sorried).addCallback(self.showTableList) break self.__updateTableList()
def headerData(self, section, orientation, role=Qt.DisplayRole): # pylint: disable=R0201 """show header""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: if section == 1: return QVariant(int(Qt.AlignRight)) else: return QVariant(int(Qt.AlignLeft)) if orientation != Qt.Horizontal: return QVariant(int(section + 1)) if role != Qt.DisplayRole: return QVariant() result = '' if section < self.columnCount(): result = [m18n('Time'), m18n('Player'), m18n('Message')][section] return QVariant(result)
def remote_gameOver(self, tableid, message, *args): """the game is over""" def yes(dummy): """now that the user clicked the 'game over' prompt away, clean up""" if self.game: self.game.rotateWinds() if Options.csv: gameWinner = max(self.game.players, key=lambda x: x.balance) writer = csv.writer(open(Options.csv,'a'), delimiter=';') if Debug.process: self.game.csvTags.append('MEM:%s' % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) row = [Options.AI, str(self.game.seed), ','.join(self.game.csvTags)] for player in sorted(self.game.players, key=lambda x: x.name): row.append(player.name.encode('utf-8')) row.append(player.balance) row.append(player.wonCount) row.append(1 if player == gameWinner else 0) writer.writerow(row) del writer if self.game.autoPlay and Internal.field: Internal.field.close() else: self.game.close().addCallback(Client.quitProgram) assert self.table and self.table.tableid == tableid if Internal.field: # update the balances in the status bar: Internal.field.updateGUI() logInfo(m18n(message, *args), showDialog=True).addCallback(yes)
def _loginReallyFailed(self, failure): """login failed, not fixable by adding missing user""" msg = self._prettifyErrorMessage(failure) if failure.check(CancelledError): # show no warning, just leave return failure if 'Errno 5' in msg: # The server is running but something is wrong with it if self.useSocket and os.name != 'nt': if removeIfExists(socketName()): logInfo( m18n('removed stale socket <filename>%1</filename>', socketName())) msg += '\n\n\n' + m18n('Please try again') logWarning(msg) return failure
def headerData(self, section, orientation, role=Qt.DisplayRole): # pylint: disable=R0201 """show header""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: if section in [3, 4]: return QVariant(int(Qt.AlignLeft)) else: return QVariant(int(Qt.AlignHCenter|Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation != Qt.Horizontal: return QVariant(int(section+1)) result = '' if section < 5: result = [m18n('Table'), '', m18n('Players'), m18nc('table status', 'Status'), m18n('Ruleset')][section] return QVariant(result)
def __init__(self): """self.servers is a list of tuples containing server and last playername""" QDialog.__init__(self, None) self.setWindowTitle(m18n('Login') + ' - Kajongg') self.setupUi() localName = m18nc('kajongg name for local game server', Query.localServerName) self.servers = Query('select url,lastname from server order by lasttime desc').records servers = [m18nc('kajongg name for local game server', x[0]) for x in self.servers] # the first server combobox item should be default: either the last used server # or localName for autoPlay if localName not in servers: servers.append(localName) if 'kajongg.org' not in servers: servers.append('kajongg.org') demoHost = Options.host or localName if demoHost in servers: servers.remove(demoHost) # we want a unique list, it will be re-used for all following games servers.insert(0, demoHost) # in this process but they will not be autoPlay self.cbServer.addItems(servers) self.passwords = Query('select url, p.name, passwords.password from passwords, player p ' 'where passwords.player=p.id').records Players.load() self.cbServer.editTextChanged.connect(self.serverChanged) self.cbUser.editTextChanged.connect(self.userChanged) self.serverChanged() StateSaver(self)