1# Copyright (C) 2011 Chris Dekter 2# Copyright (C) 2018, 2019 Thomas Hess <thomas.hess@udo.edu> 3 4# This program is free software: you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation, either version 3 of the License, or 7# (at your option) any later version. 8 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13 14# You should have received a copy of the GNU General Public License 15# along with this program. If not, see <http://www.gnu.org/licenses/>. 16import subprocess 17 18from PyQt5.QtWidgets import QMessageBox 19 20from autokey import model 21from autokey.qtui import common as ui_common 22 23 24PROBLEM_MSG_PRIMARY = "Some problems were found" 25PROBLEM_MSG_SECONDARY = "{}\n\nYour changes have not been saved." 26 27 28# TODO: Once the port to Qt5 is done, set the editor placeholder text in the UI file to "Enter your phrase here." 29# TODO: Pure Qt4 QTextEdit does not support placeholder texts, so this functionality is currently unavailable. 30class PhrasePage(*ui_common.inherits_from_ui_file_with_name("phrasepage")): 31 32 def __init__(self): 33 super(PhrasePage, self).__init__() 34 self.setupUi(self) 35 36 self.initialising = True 37 self.current_phrase = None # type: model.Phrase 38 39 for val in sorted(model.SEND_MODES.keys()): 40 self.sendModeCombo.addItem(val) 41 self.initialising = False 42 43 def load(self, phrase: model.Phrase): 44 self.current_phrase = phrase 45 self.phraseText.setPlainText(phrase.phrase) 46 self.showInTrayCheckbox.setChecked(phrase.show_in_tray_menu) 47 48 for k, v in model.SEND_MODES.items(): 49 if v == phrase.sendMode: 50 self.sendModeCombo.setCurrentIndex(self.sendModeCombo.findText(k)) 51 break 52 53 if self.is_new_item(): 54 self.urlLabel.setEnabled(False) 55 self.urlLabel.setText("(Unsaved)") # TODO: i18n 56 else: 57 ui_common.set_url_label(self.urlLabel, self.current_phrase.path) 58 59 # TODO - re-enable me if restoring predictive functionality 60 #self.predictCheckbox.setChecked(model.TriggerMode.PREDICTIVE in phrase.modes) 61 62 self.promptCheckbox.setChecked(phrase.prompt) 63 self.settingsWidget.load(phrase) 64 65 def save(self): 66 self.settingsWidget.save() 67 self.current_phrase.phrase = str(self.phraseText.toPlainText()) 68 self.current_phrase.show_in_tray_menu = self.showInTrayCheckbox.isChecked() 69 70 self.current_phrase.sendMode = model.SEND_MODES[str(self.sendModeCombo.currentText())] 71 72 # TODO - re-enable me if restoring predictive functionality 73 #if self.predictCheckbox.isChecked(): 74 # self.currentPhrase.modes.append(model.TriggerMode.PREDICTIVE) 75 76 self.current_phrase.prompt = self.promptCheckbox.isChecked() 77 78 self.current_phrase.persist() 79 ui_common.set_url_label(self.urlLabel, self.current_phrase.path) 80 return False 81 82 def get_current_item(self): 83 """Returns the currently held item.""" 84 return self.current_phrase 85 86 def set_item_title(self, title): 87 self.current_phrase.description = title 88 89 def rebuild_item_path(self): 90 self.current_phrase.rebuild_path() 91 92 def is_new_item(self): 93 return self.current_phrase.path is None 94 95 def reset(self): 96 self.load(self.current_phrase) 97 98 def validate(self): 99 errors = [] 100 101 # Check phrase content 102 phrase = str(self.phraseText.toPlainText()) 103 if ui_common.EMPTY_FIELD_REGEX.match(phrase): 104 errors.append("The phrase content can't be empty") # TODO: i18n 105 106 # Check settings 107 errors += self.settingsWidget.validate() 108 109 if errors: 110 msg = PROBLEM_MSG_SECONDARY.format('\n'.join([str(e) for e in errors])) 111 QMessageBox.critical(self.window(), PROBLEM_MSG_PRIMARY, msg) 112 113 return not bool(errors) 114 115 def set_dirty(self): 116 self.window().set_dirty() 117 118 def undo(self): 119 self.phraseText.undo() 120 121 def redo(self): 122 self.phraseText.redo() 123 124 def insert_token(self, token): 125 self.phraseText.insertPlainText(token) 126 127 # --- Signal handlers 128 def on_phraseText_textChanged(self): 129 self.set_dirty() 130 131 def on_phraseText_undoAvailable(self, state): 132 self.window().set_undo_available(state) 133 134 def on_phraseText_redoAvailable(self, state): 135 self.window().set_redo_available(state) 136 137 def on_predictCheckbox_stateChanged(self, state): 138 self.set_dirty() 139 140 def on_promptCheckbox_stateChanged(self, state): 141 self.set_dirty() 142 143 def on_showInTrayCheckbox_stateChanged(self, state): 144 self.set_dirty() 145 146 def on_sendModeCombo_currentIndexChanged(self, index): 147 if not self.initialising: 148 self.set_dirty() 149 150 def on_urlLabel_leftClickedUrl(self, url=None): 151 if url: 152 subprocess.Popen(["/usr/bin/xdg-open", url]) 153