1# Copyright (C) 2016-2020 Damon Lynch <damonlynch@gmail.com> 2 3# This file is part of Rapid Photo Downloader. 4# 5# Rapid Photo Downloader is free software: you can redistribute it and/or 6# modify it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Rapid Photo Downloader is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Rapid Photo Downloader. If not, 17# see <http://www.gnu.org/licenses/>. 18 19""" 20Display an About window 21""" 22 23__author__ = 'Damon Lynch' 24__copyright__ = "Copyright 2016-2020, Damon Lynch" 25 26import re 27 28from PyQt5.QtCore import Qt, pyqtSlot, QSize 29from PyQt5.QtGui import QPixmap, QFont 30 31from PyQt5.QtWidgets import ( 32 QDialog, QLabel, QVBoxLayout, QDialogButtonBox, QSizePolicy, QHBoxLayout, QStackedWidget, 33 QWidget, QScrollArea, QPushButton 34) 35 36import raphodo.qrc_resources 37import raphodo.__about__ as __about__ 38from raphodo.viewutils import translateDialogBoxButtons 39 40 41class AboutDialog(QDialog): 42 """ 43 Display an About window 44 """ 45 46 def __init__(self, parent=None) -> None: 47 super().__init__(parent) 48 49 self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) 50 51 self.setObjectName('AboutDialog') 52 self.setStyleSheet('QDialog#AboutDialog {background-image: url(:/splashscreen.png);}') 53 pixmap = QPixmap(':/splashscreen.png') 54 try: 55 ratio = pixmap.devicePixelRatioF() 56 except AttributeError: 57 ratio = pixmap.devicePixelRatio() 58 59 if ratio > 1.0: 60 size = QSize(pixmap.width() / ratio, pixmap.height() / ratio) 61 else: 62 size = pixmap.size() 63 64 self.setFixedSize(size) 65 66 # These values are derived from the splash screen image contents. 67 # If the image changes, so should these 68 white_box_height = 80 69 title_bottom = 45 70 left_margin = 16 71 72 transparency = "rgba(0, 0, 0, 130)" 73 74 # Standard About view 75 76 msg = """Copyright © 2007-2020 Damon Lynch.<br><br> 77 <a href="http://www.damonlynch.net/rapid" %(link_style)s> 78 www.damonlynch.net/rapid</a><br><br> 79 This program comes with absolutely no warranty.<br> 80 See the <a href="http://www.gnu.org/copyleft/gpl.html" %(link_style)s>GNU General 81 Public License, 82 version 3 or later</a> for details. 83 """ % dict(link_style='style="color: white;"') 84 85 details = QLabel(msg) 86 87 details_style_sheet = """QLabel { 88 color: white; 89 background-color: %(transparency)s; 90 margin-left: 0px; 91 padding-left: %(left_margin)dpx; 92 padding-top: 6px; 93 padding-right: 6px; 94 padding-bottom: 6px; 95 }""" % dict(left_margin=left_margin, transparency=transparency) 96 97 details.setStyleSheet(details_style_sheet) 98 details.setOpenExternalLinks(True) 99 details.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) 100 font = self.font() # type: QFont 101 font_size = font.pointSize() - 2 102 font.setPointSize(font_size) 103 details.setFont(font) 104 105 aboutLayout = QVBoxLayout() 106 aboutLayout.setContentsMargins(0, 0, 0, 0) 107 aboutLayout.addSpacing(150) 108 detailsLayout = QHBoxLayout() 109 detailsLayout.setContentsMargins(0, 0, 0, 0) 110 detailsLayout.addWidget(details) 111 detailsLayout.addStretch(10) 112 aboutLayout.addLayout(detailsLayout) 113 aboutLayout.addStretch(10) 114 115 about = QWidget() 116 about.setLayout(aboutLayout) 117 118 # Credits view 119 120 credits_text = """ 121 Copyright © 2007-2020 Damon Lynch. 122 Portions copyright © 2008-2015 Canonical Ltd. 123 Portions copyright © 2013 Bernard Baeyens. 124 Portions copyright © 2012-2015 Jim Easterbrook. 125 Portions copyright © 2012 Sven Marnach. 126 Portions copyright © 2015 Dmitry Shachnev. 127 128 Photo %(photolink)s copyright © 2014-2018 Damon Lynch, all rights reserved. 129 Camera icon courtesy %(artlink1)s. 130 Video camera icon courtesy %(artlink2)s. 131 Home icon courtesy %(artlink3)s. 132 Speech bubble courtesy %(artlink4)s. 133 Lightbulb icon courtesy %(artlink5)s. 134 Unlink icon courtesy %(artlink6)s. 135 Clock icon courtesy %(artlink7)s. 136 """ 137 138 credits_text = credits_text.replace('\n', '<br>\n') 139 140 credits_text = credits_text % dict( 141 photolink="""<a href="https://500px.com/photo/246096445/afghan-men-pulling-heavy-load- 142 by-damon-lynch" style="color: white;">Afghan Men Pulling Heavy Load</a>""", 143 artlink1='<a href="http://www.webalys.com" style="color: white;">Vincent Le Moign</a>', 144 artlink2="""<a href="https://www.iconfinder.com/bluewolfski" style="color: white;">The 145 Pictographers</a>""", 146 artlink3='<a href="https://www.iconfinder.com/Enesdal" style="color: white;">Enes' 147 ' Dal</a>', 148 artlink4='<a href="http://www.iconsolid.com/" style="color: white;">Icons Solid</a>', 149 artlink5='<a href="https://sellfy.com/designcoon" style="color: white;">Icon Coon</a>', 150 artlink6='<a href="https://www.iconfinder.com/icons/1608708/unlink_icon" style="color: ' 151 'white;">Dave Gandy</a>', 152 artlink7='<a href="https://www.flaticon.com/authors/pixel-perfect" style="color: ' 153 'white;">Pixel perfect</a>' 154 ) 155 156 label_style_sheet = """QLabel { 157 background-color: rgba(0, 0, 0, 0); 158 color: white; 159 padding-left: %(left_margin)dpx; 160 padding-top: 6px; 161 padding-right: 6px; 162 padding-bottom: 6px; 163 }""" % dict(left_margin=left_margin) 164 165 creditsLabel = QLabel(credits_text) 166 creditsLabel.setFont(font) 167 creditsLabel.setStyleSheet(label_style_sheet) 168 creditsLabel.setOpenExternalLinks(True) 169 170 credits = QScrollArea() 171 credits.setWidget(creditsLabel) 172 scroll_area_style_sheet = """QScrollArea { 173 background-color: %(transparency)s; 174 border: 0px; 175 } 176 """ % dict(transparency=transparency) 177 credits.setStyleSheet(scroll_area_style_sheet) 178 179 # Translators view 180 181 translators_text = """ 182 <b>Algerian</b> 183 Algent Albrahimi <algent@protonmail.com> 184 185 <b>Belarusian</b> 186 Ilya Tsimokhin <ilya@tsimokhin.com> 187 188 <b>Brazilian Portuguese</b> 189 Ney Walens de Mesquita <walens@gmail.com> 190 Rubens Stuginski Jr <rubens.stuginski@gmail.com> 191 192 <b>Catalan</b> 193 Adolfo Jayme Barrientos <fitoschido@gmail.com> 194 195 <b>Czech</b> 196 Pavel Borecki <pavel.borecki@gmail.com> 197 198 <b>Danish</b> 199 Torben Gundtofte-Bruun <torben@g-b.dk> 200 201 <b>Dutch</b> 202 Alain J. Baudrez <a.baudrez@gmail.com> 203 204 <b>Estonian</b> 205 Tauno Erik <tauno.erik@gmail.com> 206 207 <b>Finnish</b> 208 Mikko Ruohola <mikko@ruohola.org> 209 210 <b>French</b> 211 Jean-Marc Lartigue <m.balthazar@posteo.net> 212 213 <b>Greek</b> 214 Dimitris Xenakis <dx@nkdx.gr> 215 216 <b>Hungarian</b> 217 László <csola48@gmail.com> 218 András Lőrincz <level.andrasnak@gmail.com> 219 220 <b>Italian</b> 221 Matteo Carotta <matteo.carotta@gmail.com> 222 Milo Casagrande <milo.casagrande@gmail.com> 223 224 <b>Japanese</b> 225 Koji Yokota <yokota6@gmail.com> 226 227 <b>Kabyle</b> 228 Mohammed Belkacem <belkacem77@gmail.com> 229 230 <b>Norwegian Bokmal</b> 231 Harlad H <haarektrans@gmail.com> 232 Rudolf Maurer <rudolf.maurer@googlemail.com> 233 234 <b>Norwegian Nynorsk</b> 235 Kevin Brubeck Unhammer <unhammer@fsfe.org> 236 Harlad H <haarektrans@gmail.com> 237 238 <b>Polish</b> 239 Michal Predotka <mpredotka@googlemail.com> 240 241 <b>Russian</b> 242 Evgeny Kozlov <evgeny.kozlov.mailbox@gmail.com> 243 244 <b>Serbian</b> 245 Мирослав Николић <miroslavnikolic@rocketmail.com> 246 247 <b>Slovak</b> 248 Robert Valik <robert@valik.sk> 249 250 <b>Spanish</b> 251 Adolfo Jayme Barrientos <fitoschido@gmail.com> 252 Jose Luis Tirado <joseluis.tirado@gmail.com> 253 254 <b>Swedish</b> 255 Joachim Johansson <joachim.j@gmail.com> 256 257 <b>Turkish</b> 258 Ilker Alp <ilkeryus@gmail.com> 259 260 <b>Previous translators</b> 261 Anton Alyab'ev <subeditor@dolgopa.org> 262 Michel Ange <michelange@wanadoo.fr> 263 Tobias Bannert <tobannert@gmail.com> 264 Bert <crinbert@yahoo.com> 265 Martin Dahl Moe 266 Marco de Freitas <marcodefreitas@gmail.com> 267 Martin Egger <martin.egger@gmx.net> 268 Sergiy Gavrylov <sergiovana@bigmir.net> 269 Emanuele Grande <caccolangrifata@gmail.com> 270 Toni Lähdekorpi <toni@lygon.net> 271 Miroslav Matejaš <silverspace@ubuntu-hr.org> 272 Erik M 273 Frederik Müller <spheniscus@freenet.de> 274 Jose Luis Navarro <jlnavarro111@gmail.com> 275 Tomas Novak <kuvaly@seznam.cz> 276 Abel O'Rian <abel.orian@gmail.com> 277 Balazs Oveges <ovegesb@freemail.hu> 278 Daniel Paessler <daniel@paessler.org> 279 Miloš Popović <gpopac@gmail.com> 280 Ye Qing <allen19920930@gmail.com> 281 Luca Reverberi <thereve@gmail.com> 282 Ahmed Shubbar <ahmed.shubbar@gmail.com> 283 Sergei Sedov <sedov@webmail.perm.ru> 284 Marco Solari <marcosolari@gmail.com> 285 Ulf Urdén <ulf.urden@purplescout.com> 286 Julien Valroff <julien@kirya.net> 287 Aron Xu <happyaron.xu@gmail.com> 288 Nicolás M. Zahlut <nzahlut@live.com> 289 梁其学 <yalongbay@gmail.com> 290 """ 291 292 # Replace < and > in email addresses 293 translators_text = re.sub( 294 r'<(.+)@(.+)>', r'<\1@\2>', translators_text, flags=re.MULTILINE 295 ) 296 translators_text = translators_text.replace('\n', '<br>\n') 297 298 translatorsLabel = QLabel(translators_text) 299 translatorsLabel.setFont(font) 300 translatorsLabel.setStyleSheet(label_style_sheet) 301 302 translators = QScrollArea() 303 translators.setWidget(translatorsLabel) 304 translators.setStyleSheet(scroll_area_style_sheet) 305 306 mainLayout = QVBoxLayout() 307 308 self.stack = QStackedWidget() 309 self.stack.addWidget(about) 310 self.stack.addWidget(credits) 311 self.stack.addWidget(translators) 312 self.stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) 313 314 buttonBox = QDialogButtonBox() 315 closeButton = buttonBox.addButton(QDialogButtonBox.Close) # type: QPushButton 316 translateDialogBoxButtons(buttonBox) 317 self.creditsButton = buttonBox.addButton( 318 _('Credits'), QDialogButtonBox.HelpRole 319 ) # type: QPushButton 320 self.creditsButton.setDefault(False) 321 self.creditsButton.setCheckable(True) 322 self.translatorsButton = buttonBox.addButton( 323 _('Translators'), QDialogButtonBox.ResetRole 324 ) # type: QPushButton 325 self.translatorsButton.setDefault(False) 326 self.translatorsButton.setCheckable(True) 327 closeButton.setDefault(True) 328 329 buttonLayout = QVBoxLayout() 330 buttonLayout.addWidget(buttonBox) 331 buttonLayout.setContentsMargins(left_margin, left_margin, left_margin, left_margin) 332 333 mainLayout.setContentsMargins(0, 0, 0, 0) 334 335 version = QLabel(__about__.__version__) 336 version.setFixedHeight(white_box_height-title_bottom) 337 338 version_style_sheet = """QLabel { 339 padding-left: %(left_margin)dpx; 340 }""" % dict(left_margin=left_margin) 341 342 version.setStyleSheet(version_style_sheet) 343 344 mainLayout.addSpacing(title_bottom) 345 mainLayout.addWidget(version) 346 mainLayout.addWidget(self.stack) 347 mainLayout.addLayout(buttonLayout) 348 349 self.setLayout(mainLayout) 350 351 buttonBox.rejected.connect(self.reject) 352 self.creditsButton.clicked.connect(self.creditsButtonClicked) 353 self.translatorsButton.clicked.connect(self.translatorsButtonClicked) 354 355 closeButton.setFocus() 356 357 @pyqtSlot() 358 def creditsButtonClicked(self) -> None: 359 self.translatorsButton.setChecked(False) 360 self.showStackItem() 361 362 @pyqtSlot() 363 def translatorsButtonClicked(self) -> None: 364 self.creditsButton.setChecked(False) 365 self.showStackItem() 366 367 @pyqtSlot() 368 def showStackItem(self) -> None: 369 if self.creditsButton.isChecked(): 370 self.stack.setCurrentIndex(1) 371 elif self.translatorsButton.isChecked(): 372 self.stack.setCurrentIndex(2) 373 self.creditsButton.setChecked(False) 374 else: 375 self.stack.setCurrentIndex(0) 376 377 378