Source code for _clockalarm.UI.MainWindow

# ClockAlarm is a cross-platform alarm manager
# Copyright (C) 2017  Loïc Charrière, Samuel Gauthier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.

import logging
from os.path import dirname, abspath, join
from shutil import SameFileError

from PyQt5.Qt import QIcon, QTime
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QMainWindow, QGridLayout, QWidget, \
    QSystemTrayIcon, QMenu, QAction, qApp, QPushButton, QStyle

from _clockalarm import Notification
from _clockalarm.SimpleAlert import SimpleAlert
from _clockalarm.UI.AlertListWidget import AlertListWidget
from _clockalarm.UI.SimpleAlertEditWidget import SimpleAlertEditWidget
from _clockalarm.utils.importExportUtils import export_alerts_file, \
    import_alerts_file, set_default_config, get_default_config


[docs]class MainWindow(QMainWindow): """Main window interface extending :class:`PyQt5.QtWidgets.QMainWindow`. Shows a list of all the alerts retrieved from a JSON file. Attributes: application: The main application *args: The parent pointer or window flags """ def __init__(self, application, *args): """Creates a main window with an Alert list""" super(MainWindow, self).__init__(*args) self.app = application self.tray_icon = None self.alert_list_widget = None self.mute_pushbutton = None self.dialog_widget = None self.init_ui()
[docs] def init_ui(self): """Init helper method to set up the main window.""" self.setMinimumSize(QSize(300, 100)) # Set sizes self.setWindowTitle("ClockAlarm Manager") # Set a title self.resize(get_default_config("MAIN_WINDOW_WIDTH", "int"), get_default_config("MAIN_WINDOW_HEIGHT", "int")) import_action = QAction("Import Alerts File", self) import_action.triggered.connect(self.import_json_db) export_action = QAction("Export Alerts File", self) export_action.triggered.connect(self.export_json_db) quit_action = QAction("Exit", self) quit_action.triggered.connect(qApp.quit) new_alert_action = QAction("New Simple Alert", self) new_alert_action.triggered.connect(self.add_simple_alert) delete_alert_action = QAction("Delete Alert", self) delete_alert_action.triggered.connect(self.delete_alerts) edit_alert_action = QAction("Edit Alert", self) edit_alert_action.triggered.connect(self.edit_simple_alert) menu_bar = self.menuBar() file_menu = menu_bar.addMenu('&File') edit_menu = menu_bar.addMenu('&Edit') file_menu.addAction(import_action) file_menu.addAction(export_action) file_menu.addSeparator() file_menu.addAction(quit_action) edit_menu.addAction(new_alert_action) edit_menu.addAction(delete_alert_action) edit_menu.addAction(edit_alert_action) central_widget = QWidget(self) # Create a central widget self.setCentralWidget(central_widget) # Set the central widget grid_layout = QGridLayout(central_widget) # Create a QGridLayout central_widget.setLayout(grid_layout) # Set the layout into the central widget self.alert_list_widget = AlertListWidget() self.mute_pushbutton = QPushButton() if get_default_config("MUTE", "bool"): self.mute_pushbutton.setIcon(self.style().standardIcon(QStyle.SP_MediaVolumeMuted)) else: self.mute_pushbutton.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) self.mute_pushbutton.clicked.connect(self.mute_button_click) grid_layout.addWidget(self.alert_list_widget, 0, 0) grid_layout.addWidget(self.mute_pushbutton, 1, 0, Qt.AlignRight) # Init QSystemTrayIcon icon_path = join(dirname(dirname(abspath(__file__))), 'resources', 'images', get_default_config("ICON_FILE_NAME")) icon = QIcon(icon_path) self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(icon) self.tray_icon.activated.connect(self.tray_icon_click) tray_menu = QMenu() tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.show()
[docs] def tray_icon_click(self, reason): """Displays the main window when clicking on the app icon in the tray. """ if reason == QSystemTrayIcon.DoubleClick: self.show()
[docs] def mute_button_click(self): """Mutes the alerts and updates the mute button.""" self.app.MUTE = not self.app.MUTE if self.app.MUTE: self.mute_pushbutton.setIcon(self.style().standardIcon(QStyle.SP_MediaVolumeMuted)) else: self.mute_pushbutton.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume)) set_default_config("MUTE", self.app.MUTE)
# Override closeEvent, to intercept the window closing event
[docs] def closeEvent(self, event): """Overrides :func:`~PyQt5.QtWidgets.QWidget.closeEvent` method. Allows to intercept the window closing event. """ event.ignore() self.hide() self.tray_icon.showMessage( "ClockAlarm", "Manager was minimized to Tray", QSystemTrayIcon.Information, 2000 )
[docs] def add_simple_alert(self): """Creates a :class:`~_clockalarm.UI.SimpleAlertEditWidget` and shows it to the user. """ def button_clicked(): dw = self.dialog_widget periodicity = QTime(0, 0).secsTo(dw.periodicity_edit.time()) font_family = dw.font_family_edit.text() font_size = dw.font_size_edit.value() message = dw.alert_message_edit.text() if periodicity == 0: periodicity = None if font_family == '': font_family = None if font_size <= 0: font_size = None if message == '': message = "Untitled simple alert" notification = Notification(message, font_family=font_family, font_size=font_size, color_hex=dw.color_edit.hex_color, sound=dw.sound_edit.sound_name) new_alert = SimpleAlert(dw.date_time_edit.dateTime().toTime_t(), notification, periodicity=periodicity) self.app.alert_collection.add(new_alert) dw.close() self.dialog_widget = SimpleAlertEditWidget() self.dialog_widget.accept_button.clicked.connect(button_clicked) self.dialog_widget.adjustSize() self.dialog_widget.show()
[docs] def edit_simple_alert(self): """Edits the selected alert and shows an SimpleAlertEditWidget to the user. """ def button_clicked(): dw = self.dialog_widget periodicity = QTime(0, 0).secsTo(dw.periodicity_edit.time()) font_family = dw.font_family_edit.text() font_size = dw.font_size_edit.value() message = dw.alert_message_edit.text() if font_family == '': font_family = None if font_size <= 0: font_size = None if message == '': message = "Untitled simple alert" notification = Notification(message, font_family=font_family, font_size=font_size, color_hex=dw.color_edit.hex_color, sound=dw.sound_edit.sound_name) trigger_time = dw.date_time_edit.dateTime().toTime_t() try: self.app.alert_collection.edit(id_alert, notification=notification, trigger_time=trigger_time, periodicity=periodicity) except KeyError: logging.info("The alert to edit doesn't exist anymore") dw.close() selection = self.alert_list_widget.selectionModel().selectedRows() if not selection: return id_alert = int(self.alert_list_widget.item(selection[0].row(), 0).text()) alert_to_edit = next(alert for alert in self.app.alert_collection.alert_list if alert.id == id_alert) self.dialog_widget = SimpleAlertEditWidget(alert_to_edit) self.dialog_widget.accept_button.clicked.connect(button_clicked) self.dialog_widget.adjustSize() self.dialog_widget.show()
[docs] def delete_alerts(self): """Deletes the selected alerts.""" selection = self.alert_list_widget.selectionModel() to_delete = [] for row in selection.selectedRows(): to_delete.append(int(self.alert_list_widget.item(row.row(), 0).text())) for alert_id in to_delete: self.app.alert_collection.delete(alert_id)
[docs] @staticmethod def import_json_db(): """Imports Alerts from a JSON file into ClockAlarm.""" src = QFileDialog.getOpenFileName(None, 'Import Alert File', '.json', filter='json files (*.json *.JSON *.)')[0] if src == '': logging.info("import alerts abort") return try: import_alerts_file(src) except SameFileError: logging.info("the file is already imported")
[docs] @staticmethod def export_json_db(): """Exports all the Alerts into a JSON file.""" dest = QFileDialog.getSaveFileName(None, "Export Alerts File", "alerts.json", filter="json files (*.json *.JSON *.)")[0] if dest == "": logging.info("export abort") return try: export_alerts_file(dest) except SameFileError: logging.info("the file is already exported")