kajongg.py 7.18 KB
Newer Older
1
#!/usr/bin/env python3
2
3
4
# -*- coding: utf-8 -*-

"""
5
Copyright (C) 2008-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de>
6

7
Kajongg is free software you can redistribute it and/or modify
8
9
10
11
12
13
14
15
16
17
18
it under the terms of the GNU General Public License as published by
the Free Software Foundation either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21
"""

22
23
# pylint: disable=wrong-import-position

24
# keyboardinterrupt should simply terminate
25
26
27
# import signal
# signal.signal(signal.SIGINT, signal.SIG_DFL)
import sys
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
28
import os
29
import logging
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
30

31
from PyQt5.QtGui import QGuiApplication
32
from PyQt5 import QtCore
33
34
from qt import QObject, QCommandLineParser, QCommandLineOption
from kde import KApplication
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
35
from mi18n import i18n, MLocale
36

37
from common import Options, SingleshotOptions, Internal, Debug
38
39
# do not import modules using twisted before our reactor is running

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
40
41
def initRulesets():
    """exits if user only wanted to see available rulesets"""
42
43
    import predefined
    predefined.load()
44
    if Options.showRulesets or Options.rulesetName:
45
        from rule import Ruleset
46
        rulesets = dict((x.name, x) for x in Ruleset.selectableRulesets())
47
        if Options.showRulesets:
48
            for name in rulesets:
49
                print(name)
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
50
            Internal.db.close()
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
51
            sys.exit(0)
52
53
        elif Options.rulesetName in rulesets:
            # we have an exact match
54
            Options.ruleset = rulesets[Options.rulesetName]
55
        else:
56
            matches = list(x for x in rulesets if Options.rulesetName in x)
57
            if len(matches) != 1:
58
                if not matches:
59
60
                    msg = 'Ruleset %s is unknown' % Options.rulesetName
                else:
61
62
63
                    msg = 'Ruleset %s is ambiguous: %s' % (
                        Options.rulesetName,
                        ', '.join(matches))
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
64
                Internal.db.close()
65
                raise SystemExit(msg)
66
            Options.ruleset = rulesets[matches[0]]
67

68

69
70
71
72
73
74
75
76
77
78
79
80
class CommandLineOption(QCommandLineOption):
    """add some helping attributes"""
    def __init__(self, *args, optName=None, argType=None, singleshot=False):
        QCommandLineOption.__init__(self, *args)
        if argType is None:
            if len(args) == 2:
                argType = bool
            else:
                argType = str
        self.argType = argType
        self.optName = optName or args[0]
        self.singleshot = singleshot
81

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def defineOptions():
    """define command line options"""
    parser = QCommandLineParser()
    options = []
    def option(*args, optName=None, argType=None, singleshot=False):
        """helper"""
        opt = CommandLineOption(*args, optName=optName, argType=argType, singleshot=singleshot)
        options.append(opt)
        parser.addOption(opt)

    parser.setApplicationDescription(i18n('Mah Jongg - the ancient Chinese board game for 4 players'))

    parser.addHelpOption()
    parser.addVersionOption()
    option('playopen', i18n('all robots play with visible concealed tiles'), optName='playOpen')
    option('demo', i18n('start with demo mode'))
    option('host', i18n("login to HOST"), 'HOST', '')
    option('table', i18n('start new TABLE'), 'TABLE', '1', argType=int, singleshot=True)
    option('join', i18n('join TABLE'), 'TABLE', '1', argType=int, singleshot=True)
    option('ruleset', i18n('use RULESET without asking'), 'RULESET', '', optName='rulesetName')
    option('rounds', i18n('play only ROUNDS rounds per game. Only for debugging!'), 'ROUNDS', '4', argType=int)
    option('player', i18n('prefer PLAYER for next login'), 'PLAYER', '')
    option('ai', i18n('use AI variant for human player in demo mode'), 'AI', '', optName='AI')
    option('csv', i18n('write statistics to CSV'), 'CSV', '')
    option('rulesets', i18n('show all available rulesets'), optName='showRulesets')
    option('game', i18n('for testing purposes: Initializes the random generator'),
           'seed(/firsthand)(..(lasthand))', '0')
    option('nogui', i18n('show no graphical user interface. Intended only for testing'), optName='gui')
    option('socket', i18n('use a dedicated server listening on SOCKET. Intended only for testing'), 'SOCKET', '')
    option('port', i18n('use a dedicated server listening on PORT. Intended only for testing'), 'PORT', '')
    option('debug', Debug.help(), 'DEBUG', '')
    return parser, options
114

115
116
def parseOptions():
    """parse command line options and save the values"""
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    Options.gui = True
    parser, options = defineOptions()
    parser.process(Internal.app)
    for option in options:
        if parser.isSet(option):
            value = parser.value(option)
            if option.optName == 'debug':
                msg = Debug.setOptions(value)
                if msg:
                    Internal.logger.debug(msg)
                    logging.shutdown()
                    sys.exit(2)
                continue
            if option.optName in SingleshotOptions.__dict__:
                target = SingleshotOptions
            else:
                target = Options
            if option.argType is bool:
                setattr(target, option.optName, not option.names()[0].startswith('no'))
            elif option.argType is int:
                setattr(target, option.optName, int(value))
            else:
                setattr(target, option.optName, value)

141
    Options.demo |= not Options.gui
142
    Internal.autoPlay = Options.demo
143

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
144
145
146
147
    from query import initDb
    if not initDb():
        raise SystemExit('Cannot initialize database')
    initRulesets()
148
149
    Options.fixed = True  # may not be changed anymore

150

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
151
class EvHandler(QObject):
152

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
153
    """an application wide event handler"""
154

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
155
156
    def eventFilter(self, receiver, event):
        """will be called for all events"""
157
158
        from log import EventData
        EventData(receiver, event)
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
159
160
        return QObject.eventFilter(self, receiver, event)

161
162
from util import gitHead

Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
163
164
165
166
167
168
if os.name == 'nt':
    _ = os.path.dirname(os.path.realpath(__file__))
    if _.endswith('.zip'):
        # cx_freeze
        os.chdir(os.path.dirname(_))

169
Internal.app = KApplication()
170
171
parseOptions()

172
173
174
if hasattr(QGuiApplication, 'setDesktopFileName'):
    QGuiApplication.setDesktopFileName('org.kde.kajongg')

175
if Debug.neutral:
Wolfgang Rohdewald's avatar
Wolfgang Rohdewald committed
176
    MLocale.translation = None
177

178
179
180
181
if Debug.locate:
    # this has been read before Debug.locate is set
    Internal.logger.debug('Configuration in %s', Internal.kajonggrc.path)

182
183
if Debug.events:
    EVHANDLER = EvHandler()
184
    Internal.app.installEventFilter(EVHANDLER)
185
186
187
188
189
190
191
192
193
194
195

from config import SetupPreferences
SetupPreferences()

if Options.csv:
    if gitHead() == 'current':
        Internal.logger.debug(
            'You cannot write to %s with changes uncommitted to git',
            Options.csv)
        sys.exit(2)
from mainwindow import MainWindow
196
QGuiApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
197
198
MainWindow()
Internal.app.exec_()