class SearchDialog(Dialog): READY = 0 SEARCHING = 1 CANCELLED = 2 def __init__(self, ui): Dialog.__init__( self, ui, _('Search'), # T: Dialog title buttons=gtk.BUTTONS_CLOSE, help='Help:Searching', defaultwindowsize=(400, 300)) hbox = gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False) hbox.pack_start(gtk.Label(_('Search') + ': '), False) # T: input label self.query_entry = InputEntry() hbox.add(self.query_entry) self.search_button = gtk.Button(stock=gtk.STOCK_FIND) hbox.pack_start(self.search_button, False) if gtk.gtk_version >= (2, 20) \ and gtk.pygtk_version >= (2, 22): # update in pygtk was later self.spinner = gtk.Spinner() hbox.pack_start(self.spinner, False) else: self.spinner = None self.cancel_button = gtk.Button(stock=gtk.STOCK_STOP) hbox.pack_start(self.cancel_button, False) self._set_state(self.READY) help_text = _('For advanced search you can use operators like\n' 'AND, OR and NOT. See the help page for more details.' ) # T: help text for the search dialog if gtk.gtk_version >= (2, 12) \ and gtk.pygtk_version >= (2, 12): self.query_entry.set_tooltip_text(help_text) else: tooltips = gtk.Tooltips() tooltips.set_tip(self.query_entry, help_text) self.namespacecheckbox = gtk.CheckButton( _('Limit search to the current page and sub-pages')) # T: checkbox option in search dialog self.vbox.pack_start(self.namespacecheckbox, False) # TODO advanced query editor # TODO checkbox _('Match c_ase') # TODO checkbox _('Whole _word') self.results_treeview = SearchResultsTreeView(self.ui) self.vbox.add(ScrolledWindow(self.results_treeview)) self.search_button.connect_object('clicked', self.__class__._search, self) self.cancel_button.connect_object('clicked', self.__class__._cancel, self) self.query_entry.connect_object('activate', self.__class__._search, self) def search(self, query): '''Trigger a search to be performed. Because search can take a long time to execute it is best to call this method after the dialog is shown. @param query: the query as string ''' self.query_entry.set_text(query) self._search() def _search(self): string = self.query_entry.get_text() if self.namespacecheckbox.get_active(): string = 'Section: "%s" ' % self.ui.page.name + string #~ print '!! QUERY: ' + string self._set_state(self.SEARCHING) try: self.results_treeview.search(string) except Exception, error: ErrorDialog(self, error).run() if not self.results_treeview.cancelled: self._set_state(self.READY) else: self._set_state(self.CANCELLED)
class GoogletasksNewTaskDialog(Dialog): def __init__(self, *args, task=None, controller=None, **kwargs): self.input_title = None self.input_due = None self.input_notes = None self.label_object = None self.label_due = None self.task = task self.controller = controller super().__init__(*args, **kwargs) # noinspection PyArgumentList def setup(self): self.resize(300, 100) # reset size # title self.label_object = Gtk.Label(label='Update Google task' if self.task.get("id", "") else 'Create Google tasks') self.label_object.set_size_request(300, -1) self.vbox.pack_start(self.label_object, expand=False, fill=True, padding=0) # editable text fields (title and notes) self.input_title = InputEntry(allow_empty=False, placeholder_text="task title") self.vbox.pack_start(self.input_title, expand=False, fill=True, padding=0) self.input_notes = Gtk.TextView() # date field self.input_due = InputEntry(allow_empty=False) try: s = self.controller.get_time(mode="date-only", from_string=self.task["due"], past_dates=False) except (ValueError, KeyError): # task["due"] is not set or is in past s = self.controller.get_time(add_days=1, mode="date-only") self.input_due.set_text(s) self.input_due.connect('changed', self.update_date) self.label_due = Gtk.Label(self.controller.get_time(add_days=1, mode="day")) hbox = Gtk.HBox(spacing=1) hbox.pack_start(self.input_due, expand=True, fill=True, padding=0) hbox.pack_start(self.label_due, expand=True, fill=True, padding=0) self.vbox.pack_start(hbox, expand=False, fill=True, padding=0) # we cant tab out from notes textarea field, hence its placed under date self.vbox.pack_start(self.input_notes, expand=False, fill=True, padding=0) # arbitrary postponing buttons hbox = Gtk.HBox() def butt(label=None, date=None, days=None): """ Call either with label and date are with days.""" if days: label = f"{'_' if days < 10 else ''}{days} {self.controller.get_time(add_days=days, mode='day')}" date = self.controller.get_time(add_days=days, mode="date-only") b = Gtk.Button.new_with_mnemonic(label=label) b.connect("clicked", self.postpone(date)) b.set_tooltip_text(date) hbox.pack_start(b, expand=False, fill=True, padding=0) if self.controller.preferences["button_monday"]: butt("_Monday", self._slippy_date(next_monday=True)) if self.controller.preferences["button_next_monday"]: butt("_Next Monday", self._slippy_date(next_monday=True, relative_delta={"days": 7})) if self.controller.preferences["button_next_month"]: butt("Mon_th", self._slippy_date(relative_delta={"months": 1, "day": 1})) if self.controller.preferences["button_next_year"]: butt("_Year", self._slippy_date(relative_delta={"years": 1, "month": 2, "day": 1})) if hbox.get_children(): # there were some buttons to display self.vbox.add(hbox) # 9 (or more) postponing buttons days = self.controller.preferences["postponing_days"] if days: hbox = Gtk.HBox() self.vbox.add(hbox) hbox.pack_start(Gtk.Label(label='Days: '), expand=False, fill=True, padding=0) for i in range(1, days + 1): butt(days=i) if not i % 9: # put every 9 buttons to another line, do not expand the row to infinity hbox = Gtk.HBox() self.vbox.add(hbox) # predefined fields if "title" in self.task: self.input_title.set_text(self.task["title"]) if "notes" in self.task: self.input_notes.get_buffer().set_text(self.task["notes"]) if "due" in self.task: logger.error("Not yet implemented") # XX # display window self.show_all() return self def _slippy_date(self, add_days=0, next_monday=False, relative_delta=None): def next_weekday(d, weekday): days_ahead = weekday - d.weekday() if days_ahead <= 0: # Target day already happened this week days_ahead += 7 return d + datetime.timedelta(days_ahead) d = self.controller.get_time(add_days=add_days, mode="object") if next_monday: d = next_weekday(d, 0) # 0 = Monday, 1=Tuesday, 2=Wednesday... if relative_delta: d += relativedelta(**relative_delta) return self.controller.get_time(use_date=d, mode="date-only") def update_date(self, _): try: day = self.controller.get_time(from_string=self.input_due.get_text(), mode="day", past_dates=False) except ValueError: day = INVALID_DAY self.label_due.set_text(day) def _load_task(self): # noinspection PyBroadException try: o = self.input_notes.get_buffer() self.task["notes"] = o.get_text(*o.get_bounds(), include_hidden_chars=True) self.task["title"] = self.input_title.get_text() if self.input_due.get_text(): try: self.task["due"] = self.controller.get_time(from_string=self.input_due.get_text(), mode="morning") except Exception: logger.error("Failed due date parsing") raise except Exception: pass def do_response(self, id_): """ we cant use parent function because Esc is not handled as cancel """ if id_ == Gtk.ResponseType.OK: self.do_response_ok() else: self.do_response_cancel() def do_response_ok(self): if self.label_due.get_text() == INVALID_DAY: return False self._load_task() self.destroy() # immediately close (so that we wont hit Ok twice) if not self.controller.submit_task(task=self.task): self.do_response_cancel() return True def do_response_cancel(self): """ something failed, restore original text in the zim-page """ text = self.controller.get_task_text(self.task, self.controller.preferences["include_start_date"]) if text: buffer = self.controller.window.pageview.textview.get_buffer() buffer.insert_parsetree_at_cursor(Parser().parse(text)) self.destroy() # def postpone(self, _, number): # self.input_due.set_text(self.controller.get_time(add_days=number, mode="date-only")) # self.do_response_ok() def postpone(self, date): def _(_): self.input_due.set_text(date) self.do_response_ok() return _
class SearchDialog(Dialog): READY = 0 SEARCHING = 1 CANCELLED = 2 def __init__(self, widget, notebook, page, navigation): Dialog.__init__( self, widget, _('Search'), # T: Dialog title buttons=Gtk.ButtonsType.CLOSE, help='Help:Searching', defaultwindowsize=(400, 300)) self.page = page hbox = Gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False, True, 0) hbox.pack_start(Gtk.Label(_('Search') + ': '), False, True, 0) # T: input label self.query_entry = InputEntry() hbox.add(self.query_entry) self.search_button = Gtk.Button.new_with_mnemonic( _('_Find')) # T: Button label hbox.pack_start(self.search_button, False, True, 0) self.spinner = Gtk.Spinner() hbox.pack_start(self.spinner, False, True, 0) self.cancel_button = Gtk.Button.new_with_mnemonic( _('_Cancel')) # T: Button label hbox.pack_start(self.cancel_button, False, True, 0) self._set_state(self.READY) help_text = _('For advanced search you can use operators like\n' 'AND, OR and NOT. See the help page for more details.' ) # T: help text for the search dialog self.query_entry.set_tooltip_text(help_text) self.namespacecheckbox = Gtk.CheckButton.new_with_mnemonic( _('Limit search to the current page and sub-pages')) # T: checkbox option in search dialog if page is not None: self.vbox.pack_start(self.namespacecheckbox, False, True, 0) # TODO advanced query editor # TODO checkbox _('Match c_ase') # TODO checkbox _('Whole _word') self.results_treeview = SearchResultsTreeView(notebook, navigation) self.vbox.pack_start(ScrolledWindow(self.results_treeview), True, True, 0) self.search_button.connect_object('clicked', self.__class__._search, self) self.cancel_button.connect_object('clicked', self.__class__._cancel, self) self.query_entry.connect_object('activate', self.__class__._search, self) def search(self, query): '''Trigger a search to be performed. Because search can take a long time to execute it is best to call this method after the dialog is shown. @param query: the query as string ''' self.query_entry.set_text(query) self._search() def _search(self): string = self.query_entry.get_text() if self.namespacecheckbox.get_active(): assert self.page is not None string = 'Section: "%s" ' % self.page.name + string #~ print('!! QUERY: ' + string) self._set_state(self.SEARCHING) try: self.results_treeview.search(string) except Exception as error: ErrorDialog(self, error).run() if not self.results_treeview.cancelled: self._set_state(self.READY) else: self._set_state(self.CANCELLED) def _cancel(self): self.results_treeview.cancelled = True def _set_state(self, state): # TODO set cursor for treeview part # TODO set label or something ? def hide(button): button.hide() button.set_no_show_all(True) def show(button): button.set_no_show_all(False) button.show_all() if state in (self.READY, self.CANCELLED): self.query_entry.set_sensitive(True) hide(self.cancel_button) if self.spinner: self.spinner.stop() hide(self.spinner) show(self.search_button) elif state == self.SEARCHING: self.query_entry.set_sensitive(False) hide(self.search_button) if self.spinner: show(self.spinner) self.spinner.start() show(self.cancel_button) else: assert False, 'BUG: invalid state'
class SearchDialog(Dialog): READY = 0 SEARCHING = 1 CANCELLED = 2 def __init__(self, ui): Dialog.__init__(self, ui, _('Search'), # T: Dialog title buttons=gtk.BUTTONS_CLOSE, help='Help:Searching', defaultwindowsize=(400, 300) ) hbox = gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False) hbox.pack_start(gtk.Label(_('Search')+': '), False) # T: input label self.query_entry = InputEntry() hbox.add(self.query_entry) self.search_button = gtk.Button(stock=gtk.STOCK_FIND) hbox.pack_start(self.search_button, False) if gtk.gtk_version >= (2, 20) \ and gtk.pygtk_version >= (2, 22): self.spinner = gtk.Spinner() hbox.pack_start(self.spinner, False) else: self.spinner = None self.cancel_button = gtk.Button(stock=gtk.STOCK_STOP) hbox.pack_start(self.cancel_button, False) self._set_state(self.READY) help_text = _( 'For advanced search you can use operators like\n' 'AND, OR and NOT. See the help page for more details.' ) # T: help text for the search dialog if gtk.gtk_version >= (2, 12, 0): self.query_entry.set_tooltip_text(help_text) else: tooltips = gtk.Tooltips() tooltips.set_tip(self.query_entry, help_text) self.namespacecheckbox = gtk.CheckButton(_('Limit search to current namespace')) # T: checkbox option in search dialog self.vbox.pack_start(self.namespacecheckbox, False) # TODO advanced query editor # TODO checkbox _('Match c_ase') # TODO checkbox _('Whole _word') self.results_treeview = SearchResultsTreeView(self.ui) self.vbox.add(ScrolledWindow(self.results_treeview)) self.search_button.connect_object('clicked', self.__class__._search, self) self.cancel_button.connect_object('clicked', self.__class__._cancel, self) self.query_entry.connect_object('activate', self.__class__._search, self) def search(self, query): '''Trigger a search to be performed. Because search can take a long time to execute it is best to call this method after the dialog is shown. @param query: the query as string ''' self.query_entry.set_text(query) self._search() def _search(self): string = self.query_entry.get_text() if self.namespacecheckbox.get_active(): string = 'Namespace: "%s" ' % self.ui.page.name + string #~ print '!! QUERY: ' + string self._set_state(self.SEARCHING) try: self.results_treeview.search(string) except Exception, error: ErrorDialog(self, error).run() if not self.results_treeview.cancelled: self._set_state(self.READY) else: self._set_state(self.CANCELLED)
class FileRenameDialog(Dialog): """ A dialog for renaming a file. """ def __init__(self, parent, file): title = _('Rename file') # T: dialog title Dialog.__init__(self, parent, title) assert isinstance(file, LocalFile) and not isinstance(file, LocalFolder) self.old_file = file self.new_file = file # Add field for entering new filename. self.txt_filename = InputEntry() self.txt_filename.set_text(self.old_file.basename) self.txt_filename.set_activates_default( True) # Make ENTER key press trigger the OK button. self.txt_filename.connect("changed", self.do_validate, parent) # Add field for showing hints when an error occurs (e.g. filename already exists). self.txt_error = Gtk.Label() self.txt_error.set_visible(False) # Add ok button. self.btn_ok = self.get_widget_for_response( response_id=Gtk.ResponseType.OK) self.btn_ok.set_can_default(True) self.btn_ok.grab_default() self.btn_ok.set_sensitive(False) # Configure dialog. self.set_modal(True) self.set_default_size(380, 100) self.vbox.pack_start(self.txt_filename, False, True, 0) self.vbox.pack_start(self.txt_error, False, True, 0) # Set focus to search field self.txt_filename.grab_focus() def do_validate(self, widget, data): """ Validating new file name, show error when validation fails and enable/disable ok button. """ def is_filename(filename): """ Returns True when filename does not contain any path declaration. """ return filename == os.path.basename(filename) def does_file_already_exist(filename): """ Checks whether the new filename is already taken. """ return self.old_file.parent().file(filename).exists() def show_error(msg): """ Displays an error and disables the OK button. """ self.txt_error.set_text(msg) self.txt_error.set_visible(True) self.btn_ok.set_sensitive(False) return False if not widget.get_text(): return show_error( _('File name should not be blank.')) # T: Error message if does_file_already_exist(widget.get_text()): return show_error( _('A file with that name already exists.')) # T: Error message if not is_filename(widget.get_text()): return show_error( _('File name should not contain path declaration.') ) # T: Error message # No errors, hide error label and enable OK button. self.txt_error.hide() self.btn_ok.set_sensitive(True) return True def do_response_ok(self): self.new_file = self.old_file.parent().file( self.txt_filename.get_text()) self.result = Gtk.ResponseType.OK self.close()