Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove optional column popup [CUSTOM] #249

Open
wants to merge 8 commits into
base: coog-22.14_41
Choose a base branch
from
15 changes: 8 additions & 7 deletions tryton/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
# this repository contains the full copyright notices and license terms.
from . import timedelta
from .common import (
COLORS,
COLOR_RGB, COLOR_SCHEMES, FORMAT_ERROR, MODELACCESS, MODELHISTORY,
COLOR_RGB, COLOR_SCHEMES, COLORS, FORMAT_ERROR, MODELACCESS, MODELHISTORY,
MODELNAME, TRYTON_ICON, VIEW_SEARCH, IconFactory, Login,
Logout, RPCContextReload, RPCException, RPCExecute, RPCProgress, Tooltips,
apply_label_attributes, ask, check_version, concurrency, data2pixbuf,
date_format, ellipsize, error, file_open, file_selection, file_write,
filter_domain, generateColorscheme, get_align, get_hostname, get_port,
get_sensible_widget, get_toplevel_window, hex2rgb, highlight_rgb, humanize,
idle_add, mailto, message, node_attributes, process_exception,
resize_pixbuf, selection, setup_window, slugify, sur, sur_3b,
timezoned_date, to_xml, untimezoned_date, url_open, userwarning, warning)
filter_domain, generateColorscheme, get_align,
get_gdk_backend, get_hostname, get_port, get_sensible_widget,
get_toplevel_window, hex2rgb, highlight_rgb, humanize, idle_add, mailto,
message, node_attributes, process_exception, resize_pixbuf, selection,
setup_window, slugify, sur, sur_3b, timezoned_date, to_xml,
untimezoned_date, url_open, userwarning, warning)
from .domain_inversion import (
concat, domain_inversion, eval_domain, extract_reference_models,
filter_leaf, inverse_leaf, localize_domain, merge,
Expand Down Expand Up @@ -57,6 +57,7 @@
filter_leaf,
generateColorscheme,
get_align,
get_gdk_backend,
get_hostname,
get_port,
get_sensible_widget,
Expand Down
16 changes: 16 additions & 0 deletions tryton/common/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1395,3 +1395,19 @@ def wrapper(*args, **kwargs):
def setup_window(window):
if sys.platform == 'darwin':
window.set_mnemonic_modifier(Gdk.ModifierType.CONTROL_MASK)


def get_gdk_backend():
if sys.platform == 'darwin':
return 'macos'
elif sys.platform == 'win32':
return 'win32'
else:
dm = Gdk.DisplayManager.get()
default = dm.props.default_display
dm_class_name = default.__class__.__name__
if 'X11' in dm_class_name:
return 'x11'
elif 'Wayland' in dm_class_name:
return 'wayland'
return 'x11'
1 change: 0 additions & 1 deletion tryton/gui/window/view_form/screen/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class Screen:
# Width of tree columns per model
# It is shared with all connection but it is the price for speed.
tree_column_width = collections.defaultdict(lambda: {})
tree_column_optional = {}

def __init__(self, model_name, **attributes):
context = attributes.get('context', {})
Expand Down
4 changes: 2 additions & 2 deletions tryton/gui/window/view_form/view/form_gtk/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,10 @@ def __init__(self, view, attrs):
else:
self.wid_text = None

self.tooltips = Tooltips()
if not no_command:
self.tooltips = Tooltips()
self.tooltips.set_tip(self.but_add, _('Add value'))
self.tooltips.enable()
self.tooltips.enable()

self._readonly = False
self._record_id = None
Expand Down
221 changes: 220 additions & 1 deletion tryton/gui/window/view_form/view/form_gtk/sourceeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,56 @@ def __init__(self, view, attrs):
check_btn.connect('clicked', self.check_code)
toolbar.insert(check_btn, -1)

self.replacing = False
self.replacements = None
self.search_band = Gtk.HBox()
self.search_band.connect('key-press-event', self._hide_search)
self.search_entry = Gtk.Entry()
self.search_entry.props.max_width_chars = 40
self.search_entry.props.placeholder_text = "Search"
self.search_entry.connect('activate', self.do_search)
self.search_entry.set_icon_from_icon_name(
Gtk.EntryIconPosition.PRIMARY, 'system-search-symbolic')
self.replace_entry = Gtk.Entry()
self.replace_entry.props.max_width_chars = 40
self.replace_entry.props.placeholder_text = "Replace"
self.replace_entry.connect('activate', self.do_replace)
replace = Gtk.Button.new_with_label("Replace")
replace.connect('clicked', self.do_replace)
replace_all = Gtk.Button.new_with_label("Replace All")
replace_all.connect('clicked', self.do_replace_all)
self.occurrence_label = Gtk.Label()
prev_button = Gtk.Button.new_from_icon_name(
'go-previous-symbolic', Gtk.IconSize.BUTTON)
prev_button.connect('clicked', self.prev_search_entry)
next_button = Gtk.Button.new_from_icon_name(
'go-next-symbolic', Gtk.IconSize.BUTTON)
next_button.connect('clicked', self.next_search_entry)
# Required because Tabbing from the next button to the replace entry
# deselects the text in the TextView
next_button.connect('key-press-event', self._go_replace)
self.search_band.pack_start(
self.search_entry, expand=False, fill=True, padding=2)
self.search_band.pack_start(
prev_button, expand=False, fill=True, padding=2)
self.search_band.pack_start(
next_button, expand=False, fill=True, padding=2)
self.search_band.pack_start(
self.occurrence_label, expand=True, fill=True, padding=2)
self.search_band.pack_start(
self.replace_entry, expand=False, fill=True, padding=2)
self.search_band.pack_start(
replace, expand=False, fill=True, padding=2)
self.search_band.pack_start(
replace_all, expand=False, fill=True, padding=2)
self.search_settings = GtkSource.SearchSettings()
self.search_settings.props.wrap_around = True
self.search_context = GtkSource.SearchContext.new(
self.sourcebuffer, self.search_settings)
self.search_context.connect(
'notify::occurrences-count', self.update_occurrences)
self.sourcebuffer.connect('mark-set', self._mark_cb)

self.error_store = Gtk.ListStore(
GObject.TYPE_INT, GObject.TYPE_STRING, GObject.TYPE_STRING)

Expand Down Expand Up @@ -167,6 +217,7 @@ def __init__(self, view, attrs):

vbox.pack_start(toolbar, expand=False, fill=True, padding=0)
vbox.pack_start(sc_editor, expand=True, fill=True, padding=0)
vbox.pack_start(self.search_band, expand=False, fill=True, padding=0)
vbox.pack_start(sc_error, expand=True, fill=True, padding=0)
vbox.show_all()

Expand Down Expand Up @@ -224,6 +275,7 @@ def cell_setter(column, cell, store, iter, data):
else:
self.widget = vbox

self.search_band.hide()
self.tree_data = []
self.known_funcs = set()

Expand Down Expand Up @@ -280,6 +332,7 @@ def display(self):
self.tree_data = []
self.model.clear()
self.known_funcs.clear()
self.search_band_hide()
self.check_code()

def populate_tree(self, tree_data, parent=None):
Expand Down Expand Up @@ -379,7 +432,15 @@ def focus_line(self, selection):
def _test_check(self, sourceview, event):
if Gdk.keyval_name(event.keyval) == 'F7':
self.check_code(None)
sourceview.emit_stop_by_name('key-press-event')
sourceview.stop_emission_by_name('key-press-event')
elif (Gdk.keyval_name(event.keyval) == 'f'
and event.state & Gdk.ModifierType.CONTROL_MASK):
if self.search_band.is_visible():
self.search_band_hide()
else:
self.search_band.show_all()
self.search_entry.grab_focus()
sourceview.stop_emission_by_name('key-press-event')

def _clear_marks(self, sourcebuffer):
tag_table = sourcebuffer.get_tag_table()
Expand All @@ -403,3 +464,161 @@ def _clear_marks(self, sourcebuffer):

def tree_display_tooltip(self, treeview, x, y, keyboard_mode, tooltip):
return False

def search_band_hide(self):
self.search_entry.set_text('')
self.replace_entry.set_text('')
self.occurrence_label.set_text('')
self.replacements = None
self.search_settings.props.search_text = ''
self.search_context.props.highlight = False
insert_mark = self.sourcebuffer.get_insert()
self.sourcebuffer.move_mark_by_name(
'selection_bound',
self.sourcebuffer.get_iter_at_mark(insert_mark))
self.search_band.hide()
self.grab_focus()

def do_search(self, entry, forward=True):
self.replacements = None
searched_text = entry.get_text()
if searched_text:
self.search_settings.props.search_text = searched_text
self.search_context.props.highlight = True
if forward:
self.next_search_entry(None)
else:
self.prev_search_entry(None)
else:
self.search_settings.props.search_text = ''
self.search_context.props.highlight = False

def prev_search_entry(self, button):
self.replacements = None
if not self.search_settings.props.search_text:
self.do_search(self.search_entry)

selection = self.sourcebuffer.get_selection_bounds()
if not selection:
insert_mark = self.sourcebuffer.get_insert()
start = self.sourcebuffer.get_iter_at_mark(insert_mark)
else:
start = selection[0]

self.search_context.backward_async(
start, None, self._backward_search_finished)

def _backward_search_finished(self, context, task):
success, start, stop, wrap = context.backward_finish2(task)
if not success:
return
self.sourcebuffer.select_range(start, stop)
insert_mark = self.sourcebuffer.get_insert()
self.sourceview.scroll_mark_onscreen(insert_mark)

if self.replacing:
self.replacing = False
GLib.idle_add(self.do_replace)

def next_search_entry(self, button):
self.replacements = None
if not self.search_settings.props.search_text:
self.do_search(self.search_entry)

selection = self.sourcebuffer.get_selection_bounds()
if not selection:
insert_mark = self.sourcebuffer.get_insert()
start = self.sourcebuffer.get_iter_at_mark(insert_mark)
else:
start = selection[1]

self.search_context.forward_async(
start, None, self._forward_search_finished)

def _forward_search_finished(self, context, task):
success, start, stop, wrap = context.forward_finish2(task)
if not success:
return
self.sourcebuffer.select_range(start, stop)
insert_mark = self.sourcebuffer.get_insert()
self.sourceview.scroll_mark_onscreen(insert_mark)

if self.replacing:
self.replacing = False
GLib.idle_add(self.do_replace)

def _go_replace(self, widget, event):
if (Gdk.keyval_name(event.keyval) == 'Tab'
and not event.state & Gdk.ModifierType.MODIFIER_MASK):
self.replace_entry.grab_focus_without_selecting()
return True

def _hide_search(self, widget, event):
if Gdk.keyval_name(event.keyval) in {'Escape'}:
self.search_band_hide()

def do_replace(self, *args):
self.replacements = None
replacement_text = self.replace_entry.get_text()
selection_bounds = self.sourcebuffer.get_selection_bounds()
if not replacement_text:
return
if (not self.search_settings.props.search_text
or not selection_bounds):
self.replacing = True
self.do_search(self.search_entry)
return

replacement_text_length = self.replace_entry.get_buffer().get_bytes()
start, end = selection_bounds
self.search_context.replace(
start, end, replacement_text, replacement_text_length)
self.replacing = False

selection_bound = self.sourcebuffer.get_selection_bound()
end = self.sourcebuffer.get_iter_at_mark(selection_bound)
self.search_context.forward_async(
end, None, self._forward_search_finished)

def do_replace_all(self, *args):
searched_text = self.search_entry.get_text()
replacement_text = self.replace_entry.get_text()
if not replacement_text or not searched_text:
return

self.search_settings.props.search_text = searched_text
start, _ = self.sourcebuffer.get_bounds()
self.search_context.forward_async(
start, None, self._replace_all_search_finished)

def _replace_all_search_finished(self, context, task):
success, start, stop, wrap = context.forward_finish2(task)
if not success:
return

replacement_text = self.replace_entry.get_text()
replacement_text_length = self.replace_entry.get_buffer().get_bytes()
self.replacements = context.replace_all(
replacement_text, replacement_text_length)

def update_occurrences(self, context, param):
count = context.get_occurrences_count()
if self.sourcebuffer.get_has_selection():
start, end = self.sourcebuffer.get_selection_bounds()
position = context.get_occurrence_position(start, end)
else:
position = -1

if self.replacements is not None:
text = f"{self.replacements} occurrence(s) replaced"
elif count == -1:
text = ""
elif position == -1:
text = f"{count} occurrence(s)"
else:
text = f"{position} / {count} occurrence(s)"
self.occurrence_label.set_text(text)

def _mark_cb(self, buffer, iter_, mark):
if mark.get_name() in {'insert', 'selection_bound'}:
GLib.idle_add(self.update_occurrences, self.search_context, None)
Loading