Esempio n. 1
0
 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)
Esempio n. 2
0
    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()
Esempio n. 3
0
    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))
Esempio n. 4
0
 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)
Esempio n. 5
0
    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')
Esempio n. 6
0
 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)
Esempio n. 7
0
    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()
Esempio n. 8
0
 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
Esempio n. 9
0
 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)
Esempio n. 10
0
 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, ''
Esempio n. 11
0
 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)
Esempio n. 12
0
 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)
Esempio n. 13
0
    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))
Esempio n. 14
0
 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)
Esempio n. 15
0
 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)
Esempio n. 16
0
 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)
Esempio n. 17
0
 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)
Esempio n. 18
0
    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)
Esempio n. 19
0
    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)
Esempio n. 20
0
    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 )))
Esempio n. 21
0
 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, '')
Esempio n. 22
0
 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'
             )))
Esempio n. 23
0
 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
Esempio n. 24
0
    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)
Esempio n. 25
0
 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()
Esempio n. 26
0
 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()
Esempio n. 27
0
    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)
Esempio n. 28
0
 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)
Esempio n. 29
0
 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)
Esempio n. 30
0
 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'))
Esempio n. 31
0
 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
Esempio n. 32
0
 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
Esempio n. 33
0
 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()
Esempio n. 34
0
 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'))
Esempio n. 35
0
 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))
Esempio n. 36
0
 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
Esempio n. 37
0
    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)
Esempio n. 38
0
    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()
Esempio n. 39
0
 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
Esempio n. 40
0
 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)
Esempio n. 41
0
 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
Esempio n. 42
0
 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)
Esempio n. 43
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()
Esempio n. 44
0
 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
Esempio n. 45
0
 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)
Esempio n. 46
0
 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
Esempio n. 47
0
 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)
Esempio n. 48
0
    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()
Esempio n. 49
0
 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)
Esempio n. 50
0
 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()
Esempio n. 51
0
 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)
Esempio n. 52
0
 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)
Esempio n. 53
0
 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
Esempio n. 54
0
 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)
Esempio n. 55
0
    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)