File indexing completed on 2024-04-14 03:59:09

0001 # -*- coding: utf-8 -*-
0002 """
0003 Copyright (C) 2010-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de>
0004 
0005 partially based on C++ code from:
0006 Copyright (C) 2006 Mauricio Piacentini <mauricio@tabuleiro.com>
0007 
0008 SPDX-License-Identifier: GPL-2.0
0009 
0010 """
0011 
0012 import os
0013 
0014 from qt import uic, QStandardPaths
0015 from qt import QComboBox, QTableView, QSizePolicy, QAbstractItemView
0016 from qt import QTransform
0017 
0018 from kde import KIcon
0019 
0020 from log import i18n
0021 
0022 
0023 def loadUi(base):
0024     """load the ui file for class base, deriving the file name from
0025     the class name"""
0026     name = base.__class__.__name__.lower() + '.ui'
0027     if os.path.exists(name):
0028         directory = os.getcwd()
0029     elif os.path.exists('share/kajongg/{}'.format(name)):
0030         directory = 'share/kajongg'
0031     else:
0032         directory = os.path.dirname(QStandardPaths.locate(QStandardPaths.AppDataLocation, name))
0033     uic.loadUi(os.path.join(directory, name), base)
0034 
0035 
0036 class MJTableView(QTableView):
0037 
0038     """a QTableView with app specific defaults"""
0039 
0040     def __init__(self, parent=None):
0041         QTableView.__init__(self, parent)
0042         self.horizontalHeader().setStretchLastSection(True)
0043         self.setAlternatingRowColors(True)
0044         pol = QSizePolicy()
0045         pol.setHorizontalPolicy(QSizePolicy.Expanding)
0046         pol.setVerticalPolicy(QSizePolicy.Expanding)
0047         self.setSizePolicy(pol)
0048         self.verticalHeader().hide()
0049 
0050     def initView(self):
0051         """set some app specific defaults"""
0052         self.selectRow(0)
0053         self.resizeColumnsToContents()
0054         self.setSelectionBehavior(QAbstractItemView.SelectRows)
0055 
0056 
0057 class ListComboBox(QComboBox):
0058 
0059     """easy to use with a python list. The elements must have an
0060     attribute 'name'."""
0061 
0062     def __init__(self, items=None, parent=None):
0063         QComboBox.__init__(self, parent)
0064         self.items = items
0065 
0066     @property
0067     def items(self):
0068         """combo box items"""
0069         return [self.itemData(idx) for idx in range(self.count())]
0070 
0071     @items.setter
0072     def items(self, items):
0073         """combo box items"""
0074         self.clear()
0075         if items:
0076             for item in items:
0077                 self.addItem(i18n(item.name), item)
0078 
0079     def findItem(self, search):
0080         """return the index or -1 of not found """
0081         for idx, item in enumerate(self.items):
0082             if item == search:
0083                 return idx
0084         return -1
0085 
0086     def names(self):
0087         """a list with all item names"""
0088         return list(x.name for x in self.items)
0089 
0090     @property
0091     def current(self):
0092         """current item"""
0093         return self.itemData(self.currentIndex())
0094 
0095     @current.setter
0096     def current(self, item):
0097         """current item"""
0098         newIdx = self.findItem(item)
0099         if newIdx < 0:
0100             raise Exception('%s not found in ListComboBox' % item.name)
0101         self.setCurrentIndex(newIdx)
0102 
0103 
0104 class Painter:
0105 
0106     """a helper class for painting: saves/restores painter"""
0107 
0108     def __init__(self, painter):
0109         """painter is the painter to be saved/restored"""
0110         self.painter = painter
0111 
0112     def __enter__(self):
0113         self.painter.save()
0114         return self
0115 
0116     def __exit__(self, exc_type, exc_value, trback):
0117         """now check time passed"""
0118         self.painter.restore()
0119 
0120 
0121 class BlockSignals:
0122 
0123     """a helper class for temporary blocking of Qt signals"""
0124 
0125     def __init__(self, qobject):
0126         self.qobject = qobject
0127 
0128     def __enter__(self):
0129         if isinstance(self.qobject, list):
0130             for obj in self.qobject:
0131                 obj.blockSignals(True)
0132         else:
0133             self.qobject.blockSignals(True)
0134 
0135     def __exit__(self, exc_type, exc_value, trback):
0136         if isinstance(self.qobject, list):
0137             for obj in self.qobject:
0138                 obj.blockSignals(False)
0139         else:
0140             self.qobject.blockSignals(False)
0141 
0142 
0143 def decorateWindow(window, name=None):
0144     """standard Kajongg window title and icon"""
0145     if name:
0146         window.setWindowTitle('{} – {}'.format(name, i18n('Kajongg')))
0147     else:
0148         window.setWindowTitle(i18n('Kajongg'))
0149     window.setWindowIcon(KIcon('kajongg'))
0150 
0151 
0152 def rotateCenter(item, angle):
0153     """rotates a QGraphicsItem around its center
0154     rotateCenter and sceneRotation could be a mixin class but there are so many
0155     classes needing this. If and when more QGraphicsItem* classes are changed
0156     to QGraphicsObject, those could be moved to GraphicsObject(QGraphicsObject)"""
0157     center = item.boundingRect().center()
0158     centerX, centerY = center.x() * item.scale(), center.y() * item.scale()
0159     item.setTransform(QTransform().translate(
0160         centerX, centerY).rotate(angle).translate(-centerX, -centerY))
0161 
0162 def sceneRotation(item):
0163     """the combined rotation of item and all parents in degrees: 0,90,180 or 270"""
0164     transform = item.sceneTransform()
0165     matrix = (
0166         round(transform.m11()),
0167         round(transform.m12()),
0168         round(transform.m21()),
0169         round(transform.m22()))
0170     matrix = tuple(1 if x > 0 else -1 if x < 0 else 0 for x in matrix)
0171     rotations = {(0, 0, 0, 0): 0, (1, 0, 0, 1): 0, (
0172         0, 1, -1, 0): 90, (-1, 0, 0, -1): 180, (0, -1, 1, 0): 270}
0173     if matrix not in rotations:
0174         raise Exception('matrix unknown:%s' % str(matrix))
0175     return rotations[matrix]