def loadData(self): """loads all data from the data base into a 2D matrix formatted like the wanted tree""" game = self.scoreTable.game data = [] records = Query( "select player,rotated,notrotated,penalty,won,prevailing,wind,points,payments,balance,manualrules" " from score where game=? order by player,hand", (game.gameid,), ).records humans = sorted((x for x in game.players if not x.name.startswith(u"Robot"))) robots = sorted((x for x in game.players if x.name.startswith(u"Robot"))) data = list( tuple([player.localName, [HandResult(*x[1:]) for x in records if x[0] == player.nameid]]) for player in humans + robots ) self.__findMinMaxChartPoints(data) parent = QModelIndex() groupIndex = self.index(self.rootItem.childCount(), 0, parent) groupNames = [ m18nc("kajongg", "Score"), m18nc("kajongg", "Payments"), m18nc("kajongg", "Balance"), m18nc("kajongg", "Chart"), ] for idx, groupName in enumerate(groupNames): self.insertRows(idx, list([ScoreGroupItem(groupName)]), groupIndex) listIndex = self.index(idx, 0, groupIndex) for idx1, item in enumerate(data): self.insertRows(idx1, list([ScorePlayerItem(item)]), listIndex)
def __stateName(self): """the translated name of the state""" if self.isBonus or self.isClaimedKong: return '' elif self.isExposed: return m18nc('kajongg meld state', 'Exposed') else: return m18nc('kajongg meld state', 'Concealed')
def status(self): """a status string""" result = u'' if self.suspendedAt: result = m18nc('table status', 'Suspended') result += u' ' + unicodeString(datetime.datetime.strptime(self.suspendedAt, '%Y-%m-%dT%H:%M:%S').strftime('%c')) if self.running: result += u' ' + m18nc('table status', 'Running') return result or m18nc('table status', 'New')
def contentStr(self): """make score readable for humans, i18n""" parts = [] if self.points: parts.append(m18nc('Kajongg', '%1 points', self.points)) if self.doubles: parts.append(m18nc('Kajongg', '%1 doubles', self.doubles)) if self.limits: limits = str(self.limits) if limits.endswith('.0'): limits = limits[-2:] parts.append(m18nc('Kajongg', '%1 limits', limits)) return u' '.join(parts)
def __init__(self, parent=None): super(Games, self).__init__(parent) self.selectedGame = None self.onlyPending = True decorateWindow(self, m18nc('kajongg', 'Games')) self.setObjectName('Games') self.resize(700, 400) self.model = GamesModel() 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 __navigateScoringGame(self, event): """keyboard navigation in a scoring game""" mod = event.modifiers() key = event.key() wind = chr(key % 128) windsX = ''.join(x.char for x in Wind.all) moveCommands = m18nc('kajongg:keyboard commands for moving tiles to the players ' 'with wind ESWN or to the central tile selector (X)', windsX) uiTile = self.focusItem() if wind in moveCommands: # translate i18n wind key to ESWN: wind = windsX[moveCommands.index(wind)] self.__moveTile(uiTile, wind, bool(mod & Qt.ShiftModifier)) return True if key == Qt.Key_Tab and self.game: tabItems = [self.selectorBoard] tabItems.extend( list(p.handBoard for p in self.game.players if p.handBoard.uiTiles)) tabItems.append(tabItems[0]) currentBoard = uiTile.board currIdx = 0 while tabItems[currIdx] != currentBoard and currIdx < len(tabItems) - 2: currIdx += 1 tabItems[currIdx + 1].hasFocus = True return True
def setupUi(self): """setup UI elements""" self.viewLeft = ScoreViewLeft(self) self.viewRight = ScoreViewRight(self) self.viewRight.setHorizontalScrollBar(HorizontalScrollBar(self)) self.viewRight.setHorizontalScrollMode(QAbstractItemView.ScrollPerItem) self.viewRight.setFocusPolicy(Qt.NoFocus) if usingQt5: self.viewRight.header().setSectionsClickable(False) self.viewRight.header().setSectionsMovable(False) else: self.viewRight.header().setClickable(False) self.viewRight.header().setMovable(False) self.viewRight.setSelectionMode(QAbstractItemView.NoSelection) windowLayout = QVBoxLayout(self) self.splitter = QSplitter(Qt.Vertical) self.splitter.setObjectName("ScoreTableSplitter") windowLayout.addWidget(self.splitter) scoreWidget = QWidget() self.scoreLayout = QHBoxLayout(scoreWidget) leftLayout = QVBoxLayout() leftLayout.addWidget(self.viewLeft) self.leftLayout = leftLayout self.scoreLayout.addLayout(leftLayout) self.scoreLayout.addWidget(self.viewRight) self.splitter.addWidget(scoreWidget) self.ruleTree = RuleTreeView(m18nc("kajongg", "Used Rules")) self.splitter.addWidget(self.ruleTree) # this shows just one line for the ruleTree - so we just see the # name of the ruleset: self.splitter.setSizes(list([1000, 1]))
def buttonCaption(self): """localized, with a & for the shortcut""" i18nShortcut = m18nc( 'kajongg game dialog:Key for ' + self.name, self.shortcut) return self.i18nName.replace(i18nShortcut, '&' + i18nShortcut, 1)
def formattedDiffs(self): """a list of tuples with 3 values: name, left, right""" formatted = [] leftRuleset = self.cbRuleset1.current rightRuleset = self.cbRuleset2.current assert rightRuleset, self.cbRuleset2.count() leftRuleset.load() rightRuleset.load() for rule1, rule2 in leftRuleset.diff(rightRuleset): name = m18n(rule1.name if rule1 else rule2.name) left = rule1.contentStr() if rule1 else m18nc("Kajongg-Rule", "not defined") right = rule2.contentStr() if rule2 else m18nc("Kajongg-Rule", "not defined") formatted.append((name, left, right)) if rule1 and rule2 and rule1.definition != rule2.definition: formatted.append(("", rule1.definition, rule2.definition)) return formatted
def __init__(self, parent): QDialog.__init__(self) self.parent = parent self._data = {} self.table = QTableWidget(self) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.itemChanged.connect(self.itemChanged) self.updateTable() self.buttonBox = QDialogButtonBox() self.buttonBox.setStandardButtons( QDialogButtonBox.Close) # Close has the Rejected role self.buttonBox.rejected.connect(self.accept) 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.table) layout.addLayout(cmdLayout) self.setLayout(layout) decorateWindow(self, m18n("Players")) self.setObjectName('Players')
def popupMsg(self, msg): """shows a yellow message from player""" if msg != Message.NoClaim: self.speak(msg.name.lower()) yellow = self.front.message yellow.setText( ' '.join([unicode(yellow.msg), m18nc('kajongg', msg.name)])) yellow.setVisible(True)
def name(self): """the long name""" result = m18nc( 'kajongg meld name, do not translate parameter names', '{state} {meldType} {name}') return result.format( state=self.__stateName(), meldType=self.typeName(), name=self[0].name()).replace(' ', ' ').strip()
def validate(self): """check for validity""" payers = int(self.options.get('payers', 1)) payees = int(self.options.get('payees', 1)) if not 2 <= payers + payees <= 4: logException( m18nc( '%1 can be a sentence', '%4 have impossible values %2/%3 in rule "%1"', self.name, payers, payees, 'payers/payees'))
def __init__(self, scene): QWidget.__init__(self) self.scene = scene decorateWindow(self, m18n("Scoring for this Hand")) self.nameLabels = [None] * 4 self.spValues = [None] * 4 self.windLabels = [None] * 4 self.wonBoxes = [None] * 4 self.detailsLayout = [None] * 4 self.details = [None] * 4 self.__tilePixMaps = [] self.__meldPixMaps = [] grid = QGridLayout(self) pGrid = QGridLayout() grid.addLayout(pGrid, 0, 0, 2, 1) pGrid.addWidget(QLabel(m18nc("kajongg", "Player")), 0, 0) pGrid.addWidget(QLabel(m18nc("kajongg", "Wind")), 0, 1) pGrid.addWidget(QLabel(m18nc("kajongg", "Score")), 0, 2) pGrid.addWidget(QLabel(m18n("Winner")), 0, 3) self.detailTabs = QTabWidget() self.detailTabs.setDocumentMode(True) pGrid.addWidget(self.detailTabs, 0, 4, 8, 1) for idx in range(4): self.setupUiForPlayer(pGrid, idx) self.draw = QCheckBox(m18nc("kajongg", "Draw")) self.draw.clicked.connect(self.wonChanged) btnPenalties = QPushButton(m18n("&Penalties")) btnPenalties.clicked.connect(self.penalty) self.btnSave = QPushButton(m18n("&Save Hand")) self.btnSave.clicked.connect(self.game.nextScoringHand) self.btnSave.setEnabled(False) self.setupUILastTileMeld(pGrid) pGrid.setRowStretch(87, 10) pGrid.addWidget(self.draw, 7, 3) self.cbLastTile.currentIndexChanged.connect(self.slotLastTile) self.cbLastMeld.currentIndexChanged.connect(self.slotInputChanged) btnBox = QHBoxLayout() btnBox.addWidget(btnPenalties) btnBox.addWidget(self.btnSave) pGrid.addLayout(btnBox, 8, 4) StateSaver(self) self.refresh()
def groupName(self): """the name of the group this tile is of""" names = { Tile.hidden: m18nc("kajongg", "hidden"), Tile.stone: m18nc("kajongg", "stone"), Tile.bamboo: m18nc("kajongg", "bamboo"), Tile.character: m18nc("kajongg", "character"), Tile.wind: m18nc("kajongg", "wind"), Tile.dragon: m18nc("kajongg", "dragon"), Tile.flower: m18nc("kajongg", "flower"), Tile.season: m18nc("kajongg", "season"), } return names[self.lowerGroup]
def name(self): """returns name of a single tile""" if self.group.lower() == Tile.wind: result = { East: m18n("East Wind"), South: m18n("South Wind"), West: m18n("West Wind"), North: m18n("North Wind"), }[self.value] else: result = m18nc("kajongg tile name", "{group} {value}") return result.format(value=self.valueName(), group=self.groupName())
def mapChar2Arrow(event): """maps the keys hjkl to arrows like in vi and konqueror""" key = event.key() if key in Board.arrows: return key charArrows = m18nc( 'kajongg:arrow keys hjkl like in konqueror', 'hjklHJKL') key = unicode(event.text()) if key and key in charArrows: key = Board.arrows[charArrows.index(key) % 4] return key
def __init__(self, scene): super(ScoreTable, self).__init__(None) self.setObjectName("ScoreTable") self.scene = scene self.scoreModel = None self.scoreModelTest = None decorateWindow(self, m18nc("kajongg", "Scores")) self.setAttribute(Qt.WA_AlwaysShowToolTips) self.setMouseTracking(True) self.__tableFields = ["prevailing", "won", "wind", "points", "payments", "balance", "hand", "manualrules"] self.setupUi() self.refresh() StateSaver(self, self.splitter)
def _newKey(self, minus=False): """generate a new id and a new name if the name already exists""" newId = self.newId(minus=minus) newName = self.name if minus: copyNr = 1 while self.nameExists(newName): copyStr = ' ' + str(copyNr) if copyNr > 1 else '' newName = m18nc( 'Ruleset._newKey:%1 is empty or space plus number', 'Copy%1 of %2', copyStr, m18n(self.name)) copyNr += 1 return newId, newName
def valueName(self): """the name of the value this tile has""" names = { "y": m18nc("kajongg", "tile"), Tile.white: m18nc("kajongg", "white"), Tile.red: m18nc("kajongg", "red"), Tile.green: m18nc("kajongg", "green"), East: m18nc("kajongg", "East"), South: m18nc("kajongg", "South"), West: m18nc("kajongg", "West"), North: m18nc("kajongg", "North"), } for idx in Tile.numbers: names[idx] = chr(idx + 48) return names[self.value]
def penaltyChanged(self): """total has changed, update payments""" # normally value is only validated when leaving the field self.spPenalty.interpretText() offense = self.cbCrime.current penalty = self.spPenalty.value() payers = int(offense.options.get("payers", 1)) payees = int(offense.options.get("payees", 1)) payerAmount = -penalty // payers payeeAmount = penalty // payees for pList, amount, count in ((self.payers, payerAmount, payers), (self.payees, payeeAmount, payees)): for idx, player in enumerate(pList): player.setVisible(idx < count) player.lblPayment.setVisible(idx < count) if idx < count: if pList == self.payers: player.lblPayment.setText( m18nc("penalty dialog, appears behind paying player combobox", "pays %1 points", -amount) ) else: player.lblPayment.setText( m18nc("penalty dialog, appears behind profiting player combobox", "gets %1 points", amount) )
def headerData(self, section, orientation, role): """tell the view about the wanted headers""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return toQVariant(int(Qt.AlignLeft | Qt.AlignVCenter)) if role != Qt.DisplayRole: return toQVariant() if orientation == Qt.Horizontal: if section == 0: return toQVariant(m18nc("Kajongg", "Rule")) if section == 1: return toQVariant(m18n(self.view.cbRuleset1.current.name)) if section == 2: return toQVariant(m18n(self.view.cbRuleset2.current.name)) return toQVariant()
def __init__(self, parent, name): # pylint: disable=super-init-not-called KConfigDialog.__init__( self, parent, QString(name), Internal.Preferences) StateSaver(self) 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")]
def typeName(self): """convert int to speaking name with shortcut. ATTENTION: UNTRANSLATED!""" # pylint: disable=too-many-return-statements if self.isBonus: return m18nc('kajongg meld type', 'Bonus') elif self.isSingle: return m18nc('kajongg meld type', '&single') elif self.isPair: return m18nc('kajongg meld type', '&pair') elif self.isChow: return m18nc('kajongg meld type', '&chow') elif self.isPung: return m18nc('kajongg meld type', 'p&ung') elif self.isClaimedKong: return m18nc('kajongg meld type', 'c&laimed kong') elif self.isKong: return m18nc('kajongg meld type', 'k&ong') else: return m18nc('kajongg meld type', 'rest of tiles')
def updateButtonsForTable(self, table): """update button status for the currently selected table""" hasTable = bool(table) suspended = hasTable and bool(table.suspendedAt) running = hasTable and table.running suspendedLocalGame = ( suspended and table.gameid and self.client.hasLocalServer()) self.joinButton.setEnabled( hasTable and not running and not table.isOnline(self.client.name) and (self.client.name in table.playerNames) == suspended) self.leaveButton.setVisible(not suspendedLocalGame) self.compareButton.setVisible(not suspendedLocalGame) self.startButton.setVisible(not suspended) if suspendedLocalGame: self.newButton.setToolTip(m18n("Start a new game")) self.joinButton.setText( m18nc('resuming a local suspended game', '&Resume')) self.joinButton.setToolTip( m18n("Resume the selected suspended game")) else: self.newButton.setToolTip(m18n("Allocate a new table")) self.joinButton.setText(m18n('&Join')) self.joinButton.setToolTip(m18n("Join a table")) self.leaveButton.setEnabled( hasTable and not running and not self.joinButton.isEnabled()) self.startButton.setEnabled( not running and not suspendedLocalGame and hasTable and self.client.name == table.playerNames[0]) self.compareButton.setEnabled(hasTable and table.myRuleset is None) self.chatButton.setVisible(not self.client.hasLocalServer()) self.chatButton.setEnabled( not running and hasTable and self.client.name in table.playerNames and sum(x.startswith(u'Robot ') for x in table.playerNames) < 3) if self.chatButton.isEnabled(): self.chatButton.setToolTip(m18n( "Chat with others on this table")) else: self.chatButton.setToolTip(m18n( "For chatting with others on this table, " "please first take a seat"))
def setupUi(self): """layout the window""" decorateWindow(self, m18n('Customize rulesets')) 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 __init__(self, name): """name may be: - an integer: ruleset.id from the sql table - a list: the full ruleset specification (probably sent from the server) - a string: The hash value of a ruleset""" Rule.importRulecode() self.name = name self.rulesetId = 0 self.__hash = None self.allRules = [] self.__dirty = False # only the ruleset editor is supposed to make us dirty self.__loaded = False self.__filteredLists = {} self.description = None self.rawRules = None # used when we get the rules over the network self.doublingMeldRules = [] self.doublingHandRules = [] self.standardMJRule = None self.meldRules = RuleList(1, m18n('Meld Rules'), m18n('Meld rules are applied to single melds independent of the rest of the hand')) self.handRules = RuleList(2, m18n('Hand Rules'), m18n('Hand rules are applied to the entire hand, for all players')) self.winnerRules = RuleList(3, m18n('Winner Rules'), m18n('Winner rules are applied to the entire hand but only for the winner')) self.loserRules = RuleList(33, m18n('Loser Rules'), m18n('Loser rules are applied to the entire hand but only for non-winners')) self.mjRules = RuleList(4, m18n('Mah Jongg Rules'), m18n('Only hands matching a Mah Jongg rule can win')) self.parameterRules = RuleList(999, m18nc('kajongg', 'Options'), m18n('Here we have several special game related options')) self.penaltyRules = RuleList(9999, m18n('Penalties'), m18n( """Penalties are applied manually by the user. They are only used for scoring games. When playing against the computer or over the net, Kajongg will never let you get into a situation where you have to pay a penalty""")) self.ruleLists = list( [self.meldRules, self.handRules, self.mjRules, self.winnerRules, self.loserRules, self.parameterRules, self.penaltyRules]) # the order of ruleLists is the order in which the lists appear in the ruleset editor # if you ever want to remove an entry from ruleLists: make sure its listId is not reused or you get # in trouble when updating self._initRuleset()
def headerData( # pylint: disable=no-self-use self, section, orientation, role=Qt.DisplayRole): """show header""" if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: if section in [3, 4]: return toQVariant(int(Qt.AlignLeft)) else: return toQVariant(int(Qt.AlignHCenter | Qt.AlignVCenter)) if role != Qt.DisplayRole: return toQVariant() if orientation != Qt.Horizontal: return toQVariant(int(section + 1)) result = '' if section < 5: result = [m18n('Table'), '', m18n('Players'), m18nc('table status', 'Status'), m18n('Ruleset')][section] return toQVariant(result)
def validate(self): """is the rule valid?""" if self.parameter < self.minimum: return m18nc( 'wrong value for rule', '%1: %2 is too small, minimal value is %3', m18n(self.name), self.parName, self.minimum)
def retranslateUi(self): """retranslate""" self.actionScoreGame.setText( m18nc('@action:inmenu', "&Score Manual Game")) self.actionScoreGame.setIconText( m18nc('@action:intoolbar', 'Manual Game')) self.actionScoreGame.setHelpText( m18nc('kajongg @info:tooltip', '&Score a manual game.')) self.actionPlayGame.setText(m18nc('@action:intoolbar', "&Play")) self.actionPlayGame.setPriority(QAction.LowPriority) self.actionPlayGame.setHelpText( m18nc('kajongg @info:tooltip', 'Start a new game.')) self.actionAbortGame.setText(m18nc('@action:inmenu', "&Abort Game")) self.actionAbortGame.setPriority(QAction.LowPriority) self.actionAbortGame.setHelpText( m18nc('kajongg @info:tooltip', 'Abort the current game.')) self.actionQuit.setText(m18nc('@action:inmenu', "&Quit Kajongg")) self.actionQuit.setPriority(QAction.LowPriority) self.actionPlayers.setText(m18nc('@action:intoolbar', "&Players")) self.actionPlayers.setHelpText( m18nc('kajongg @info:tooltip', 'define your players.')) self.actionRulesets.setText(m18nc('@action:intoolbar', "&Rulesets")) self.actionRulesets.setHelpText( m18nc('kajongg @info:tooltip', 'customize rulesets.')) self.actionAngle.setText( m18nc('@action:inmenu', "&Change Visual Angle")) self.actionAngle.setIconText(m18nc('@action:intoolbar', "Angle")) self.actionAngle.setHelpText( m18nc('kajongg @info:tooltip', "Change the visual appearance of the tiles.")) self.actionScoreTable.setText( m18nc('kajongg @action:inmenu', "&Score Table")) self.actionScoreTable.setIconText( m18nc('kajongg @action:intoolbar', "&Scores")) self.actionScoreTable.setHelpText(m18nc('kajongg @info:tooltip', "Show or hide the score table for the current game.")) self.actionExplain.setText(m18nc('@action:inmenu', "&Explain Scores")) self.actionExplain.setIconText(m18nc('@action:intoolbar', "&Explain")) self.actionExplain.setHelpText(m18nc('kajongg @info:tooltip', 'Explain the scoring for all players in the current game.')) self.actionAutoPlay.setText(m18nc('@action:inmenu', "&Demo Mode")) self.actionAutoPlay.setPriority(QAction.LowPriority) self.actionAutoPlay.setHelpText(m18nc('kajongg @info:tooltip', 'Let the computer take over for you. Start a new local game if needed.')) self.actionChat.setText(m18n("C&hat")) self.actionChat.setHelpText( m18nc('kajongg @info:tooltip', 'Chat with the other players.'))