From 00f24da73c2e93bf68b0bfd281fd32be0486b220 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Sat, 21 Dec 2024 18:09:09 +0200 Subject: [PATCH 01/20] feat: upgrade to gtk4 --- README.md | 10 +++++----- meson.build | 12 ++++++------ src/codecore.deps | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9f440e8b3e..8e13c240ac 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,13 @@ You'll need the following dependencies: * libgail-3-dev * libgee-0.8-dev * libgit2-glib-1.0-dev -* libgtksourceview-4-dev +* libgtksourceview-5-dev * libgtkspell3-3-dev -* libgranite-dev >= 6.0.0 -* libhandy-1-dev >= 0.90.0 -* libpeas-dev +* libgranite-7-dev >= 6.0.0 +* libadwaita-1-dev >= 1.0.0 +* libpeas-2-dev * libsoup2.4-dev -* libvala-0.48-dev (or higher) +* libvala-0.56-dev (or higher) * libvte-2.91-dev * valac diff --git a/meson.build b/meson.build index b600a80667..c9161b2c83 100644 --- a/meson.build +++ b/meson.build @@ -26,14 +26,14 @@ pluginsdir = get_option('prefix') / get_option('libdir') / meson.project_name() gnome = import('gnome') i18n = import('i18n') -glib_dep = dependency('glib-2.0', version: '>=2.30.0') +glib_dep = dependency('glib-2.0', version: '>=2.74.0') gio_unix_dep = dependency('gio-unix-2.0', version: '>=2.20') gee_dep = dependency('gee-0.8', version: '>=0.8.5') -gtk_dep = dependency('gtk+-3.0', version: '>=3.6.0') -granite_dep = dependency('granite', version: '>=6.0.0') -handy_dep = dependency('libhandy-1', version: '>=0.90.0') -gtksourceview_dep = dependency('gtksourceview-4') -peas_dep = dependency('libpeas-1.0') +gtk_dep = dependency('gtk4', version: '>=4.14.2') +granite_dep = dependency('granite-7', version: '>=7.0.0') +handy_dep = dependency('libadwaita-1', version: '>=1.0.0') +gtksourceview_dep = dependency('gtksourceview-5') +peas_dep = dependency('libpeas-2') peasgtk_dep = dependency('libpeas-gtk-1.0') git_dep = dependency('libgit2-glib-1.0') fontconfig_dep = dependency('fontconfig') diff --git a/src/codecore.deps b/src/codecore.deps index dcfdbb4614..91677c3099 100644 --- a/src/codecore.deps +++ b/src/codecore.deps @@ -1,8 +1,8 @@ codecore -gtksourceview-4 +gtksourceview-5 gee-0.8 gobject-2.0 gio-2.0 -gtk+-3.0 -granite -libpeas-1.0 +gtk4 +granite-7 +libpeas-2 From 350dc4a7ad531d01a5f311143b894131f91ca75b Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Sun, 22 Dec 2024 17:37:55 +0200 Subject: [PATCH 02/20] feat: upgrade libs and remove libpeas --- README.md | 1 - io.elementary.code.yml | 87 ++++++++++++++------------------ meson.build | 6 +-- plugins/fuzzy-search/meson.build | 2 +- src/codecore.deps | 1 - 5 files changed, 40 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 8e13c240ac..c02bb107b8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ You'll need the following dependencies: * libgtkspell3-3-dev * libgranite-7-dev >= 6.0.0 * libadwaita-1-dev >= 1.0.0 -* libpeas-2-dev * libsoup2.4-dev * libvala-0.56-dev (or higher) * libvte-2.91-dev diff --git a/io.elementary.code.yml b/io.elementary.code.yml index c0764fbf43..77e4ffaff4 100644 --- a/io.elementary.code.yml +++ b/io.elementary.code.yml @@ -1,54 +1,43 @@ app-id: io.elementary.code runtime: io.elementary.Sdk # The outline plugin requires libvala which is only in the SDK, not the runtime -runtime-version: '7.1' +runtime-version: "7.1" sdk: io.elementary.Sdk command: io.elementary.code finish-args: - - '--filesystem=xdg-run/gvfsd' - - '--filesystem=host' + - "--filesystem=xdg-run/gvfsd" + - "--filesystem=host" - - '--share=ipc' - - '--socket=fallback-x11' - - '--socket=wayland' + - "--share=ipc" + - "--socket=fallback-x11" + - "--socket=wayland" - - '--talk-name=org.gtk.vfs.*' - - '--talk-name=org.gnome.SettingsDaemon' - - '--talk-name=org.elementary.Contractor' + - "--talk-name=org.gtk.vfs.*" + - "--talk-name=org.gnome.SettingsDaemon" + - "--talk-name=org.elementary.Contractor" - - '--metadata=X-DConf=migrate-path=/io/elementary/code/' + - "--metadata=X-DConf=migrate-path=/io/elementary/code/" cleanup: - - '/include' - - '/lib/pkgconfig' - - '/lib/cmake' - - '/lib/girepository-1.0' - - '/share/gir-1.0' - - '/share/vala' - - '*.a' - - '*.la' + - "/include" + - "/lib/pkgconfig" + - "/lib/cmake" + - "/lib/girepository-1.0" + - "/share/gir-1.0" + - "/share/vala" + - "*.a" + - "*.la" modules: - name: gtksourceview buildsystem: meson sources: - type: git url: https://gitlab.gnome.org/GNOME/gtksourceview.git - tag: '4.8.4' - - - name: peas - buildsystem: meson - config-opts: - - '-Dgtk_doc=false' - - '-Ddemos=false' - - '-Dvapi=true' - sources: - - type: git - url: https://gitlab.gnome.org/GNOME/libpeas.git - tag: libpeas-1.34.0 + tag: "4.8.4" - name: git2-glib buildsystem: meson builddir: true config-opts: - - '-Dpython=false' + - "-Dpython=false" sources: - type: git url: https://gitlab.gnome.org/GNOME/libgit2-glib.git @@ -57,14 +46,14 @@ modules: - name: ssh2 buildsystem: cmake-ninja config-opts: - - '-DCMAKE_BUILD_TYPE=RelWithDebInfo' - - '-DBUILD_SHARED_LIBS:BOOL=ON' - - '-DBUILD_EXAMPLES:BOOL=OFF' - - '-DBUILD_TESTING:BOOL=OFF' - - '-DCMAKE_INSTALL_LIBDIR:PATH=/app/lib' + - "-DCMAKE_BUILD_TYPE=RelWithDebInfo" + - "-DBUILD_SHARED_LIBS:BOOL=ON" + - "-DBUILD_EXAMPLES:BOOL=OFF" + - "-DBUILD_TESTING:BOOL=OFF" + - "-DCMAKE_INSTALL_LIBDIR:PATH=/app/lib" cleanup: - - '/share/man' - - '/share/doc' + - "/share/man" + - "/share/doc" sources: - type: git url: https://github.com/libssh2/libssh2.git @@ -72,28 +61,28 @@ modules: - name: libgit2 buildsystem: cmake-ninja config-opts: - - '-DCMAKE_BUILD_TYPE=RelWithDebInfo' + - "-DCMAKE_BUILD_TYPE=RelWithDebInfo" sources: - type: git url: https://github.com/libgit2/libgit2.git - tag: 'v1.5.1' + tag: "v1.5.1" - name: editorconfig buildsystem: cmake-ninja config-opts: - - '-DCMAKE_BUILD_TYPE=RelWithDebInfo' - - '-DBUILD_DOCUMENTATION:BOOL=OFF' + - "-DCMAKE_BUILD_TYPE=RelWithDebInfo" + - "-DBUILD_DOCUMENTATION:BOOL=OFF" sources: - type: git url: https://github.com/editorconfig/editorconfig-core-c.git - tag: 'v0.12.6' + tag: "v0.12.6" disable-submodules: true - name: gtkspell config-opts: - - '--disable-gtk-doc-html' + - "--disable-gtk-doc-html" cleanup: - - '/share/gtk-doc' # for some reason, it still install the html folder. + - "/share/gtk-doc" # for some reason, it still install the html folder. sources: - type: archive url: https://downloads.sourceforge.net/gtkspell/gtkspell3-3.0.10.tar.xz @@ -101,7 +90,7 @@ modules: modules: - name: intltool cleanup: - - '*' + - "*" sources: - type: archive url: https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz @@ -110,11 +99,11 @@ modules: - name: vte buildsystem: meson config-opts: - - '-Dbuildtype=debugoptimized' + - "-Dbuildtype=debugoptimized" sources: - type: git url: https://gitlab.gnome.org/GNOME/vte.git - branch: '0.70.2' + branch: "0.70.2" - name: universal-ctags sources: @@ -125,7 +114,7 @@ modules: - name: code buildsystem: meson config-opts: - - '-Dhave_pkexec=false' + - "-Dhave_pkexec=false" sources: - type: dir path: . diff --git a/meson.build b/meson.build index c9161b2c83..41de32d85d 100644 --- a/meson.build +++ b/meson.build @@ -12,7 +12,7 @@ add_project_arguments([ ) add_project_arguments( - ['--vapidir', meson.project_source_root() / 'vapi'], + ['--vapidir', meson.global_source_root() / 'vapi'], language: 'vala' ) @@ -33,8 +33,6 @@ gtk_dep = dependency('gtk4', version: '>=4.14.2') granite_dep = dependency('granite-7', version: '>=7.0.0') handy_dep = dependency('libadwaita-1', version: '>=1.0.0') gtksourceview_dep = dependency('gtksourceview-5') -peas_dep = dependency('libpeas-2') -peasgtk_dep = dependency('libpeas-gtk-1.0') git_dep = dependency('libgit2-glib-1.0') fontconfig_dep = dependency('fontconfig') pangofc_dep = dependency('pangoft2') @@ -58,8 +56,6 @@ dependencies = [ granite_dep, handy_dep, gtksourceview_dep, - peas_dep, - peasgtk_dep, git_dep, fontconfig_dep, pangofc_dep, diff --git a/plugins/fuzzy-search/meson.build b/plugins/fuzzy-search/meson.build index 5a717fcd1f..29f14c1e81 100644 --- a/plugins/fuzzy-search/meson.build +++ b/plugins/fuzzy-search/meson.build @@ -29,7 +29,7 @@ custom_target(module_name + '.plugin_merge', '--desktop', '--keyword=Description', '--keyword=Name', - '-d' + join_paths(meson.source_root (), 'po', 'plugins'), + '-d' + join_paths(meson.global_source_root (), 'po', 'plugins'), '--template=@INPUT@', '-o@OUTPUT@', ], diff --git a/src/codecore.deps b/src/codecore.deps index 91677c3099..a33d680b3f 100644 --- a/src/codecore.deps +++ b/src/codecore.deps @@ -5,4 +5,3 @@ gobject-2.0 gio-2.0 gtk4 granite-7 -libpeas-2 From f592c9091646db4b414a462921bd284a70d8a77e Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Sun, 22 Dec 2024 19:20:40 +0200 Subject: [PATCH 03/20] fix: upgrade vte library to gtk4 --- README.md | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c02bb107b8..0b26b050e7 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ You'll need the following dependencies: * libadwaita-1-dev >= 1.0.0 * libsoup2.4-dev * libvala-0.56-dev (or higher) -* libvte-2.91-dev +* libvte-2.91-gtk4-dev * valac Run `meson build` to configure the build environment. Change to the build directory and run `ninja test` to build diff --git a/meson.build b/meson.build index 41de32d85d..cc08b15a84 100644 --- a/meson.build +++ b/meson.build @@ -37,7 +37,7 @@ git_dep = dependency('libgit2-glib-1.0') fontconfig_dep = dependency('fontconfig') pangofc_dep = dependency('pangoft2') posix_dep = meson.get_compiler('vala').find_library('posix') -vte_dep = dependency('vte-2.91') +vte_dep = dependency('vte-2.91-gtk4', version: '>=0.76') code_resources = gnome.compile_resources( 'code-resources', 'data/' + meson.project_name() + '.gresource.xml', From fc1f7cddc48ff4d38462512cd94a90b2756858c3 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 02:31:07 +0200 Subject: [PATCH 04/20] upgrade: replace libhandy code with libadwaita --- src/MainWindow.vala | 2 +- src/Services/Document.vala | 4 ++-- src/Widgets/DocumentView.vala | 16 ++++++++-------- src/Widgets/HeaderBar.vala | 2 +- src/Widgets/Sidebar.vala | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 34fe7d93db..81322e0b43 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -19,7 +19,7 @@ */ namespace Scratch { - public class MainWindow : Hdy.Window { + public class MainWindow : Adw.Window { public const int FONT_SIZE_MAX = 72; public const int FONT_SIZE_MIN = 7; private const uint MAX_SEARCH_TEXT_LENGTH = 255; diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 2505959e16..01399c3e8d 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -37,7 +37,7 @@ namespace Scratch.Services { public unowned SimpleActionGroup actions { get; set construct; } // The TabPage that this document is a child of - public unowned Hdy.TabPage tab { get; private set; } + public unowned Adw.TabPage tab { get; private set; } public bool is_file_temporary { get { @@ -293,7 +293,7 @@ namespace Scratch.Services { this.show_all (); } - public void init_tab (Hdy.TabPage tab) { + public void init_tab (Adw.TabPage tab) { this.tab = tab; notify["tab.loading"].connect (on_tab_loading_change); diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index ed19bb6510..23d04cfd0c 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -59,9 +59,9 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { public bool outline_visible { get; set; default = false; } public int outline_width { get; set; } - private Hdy.TabView tab_view; - private Hdy.TabBar tab_bar; - private weak Hdy.TabPage? tab_menu_target = null; + private Adw.TabView tab_view; + private Adw.TabBar tab_bar; + private weak Adw.TabPage? tab_menu_target = null; private Gtk.CssProvider style_provider; private Gtk.MenuButton tab_history_button; @@ -423,7 +423,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } // This is called when tab context menu is opened or closed - private void tab_view_setup_menu (Hdy.TabPage? page) { + private void tab_view_setup_menu (Adw.TabPage? page) { tab_menu_target = page; var close_other_tabs_action = Utils.action_from_group (MainWindow.ACTION_CLOSE_OTHER_TABS, window.actions); @@ -467,7 +467,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { on_doc_removed_shared (doc); } - private void on_doc_removed (Hdy.TabPage tab, int position) { + private void on_doc_removed (Adw.TabPage tab, int position) { var doc = tab.get_child () as Services.Document; if (doc == null) { return; @@ -545,7 +545,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } } - private void on_doc_reordered (Hdy.TabPage tab, int new_position) { + private void on_doc_reordered (Adw.TabPage tab, int new_position) { var doc = tab.child as Services.Document; if (doc != null) { docs.remove (doc); @@ -556,12 +556,12 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { save_opened_files (); } - private unowned Hdy.TabView? on_doc_to_new_window (Hdy.TabView tab_view) { + private unowned Adw.TabView? on_doc_to_new_window (Adw.TabView tab_view) { var other_window = new MainWindow (false); return other_window.document_view.tab_view; } - private void on_doc_added (Hdy.TabPage page, int position) { + private void on_doc_added (Adw.TabPage page, int position) { var doc = page.get_child () as Services.Document; doc.init_tab (page); diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index 791361442e..71b04cf462 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -4,7 +4,7 @@ * 2013 Mario Guerriero */ -public class Scratch.HeaderBar : Hdy.HeaderBar { +public class Scratch.HeaderBar : Adw.HeaderBar { // Plugins segfault without full access public Code.FormatBar format_bar; public GLib.Menu share_menu; diff --git a/src/Widgets/Sidebar.vala b/src/Widgets/Sidebar.vala index 209548d2c5..dc67ccc929 100644 --- a/src/Widgets/Sidebar.vala +++ b/src/Widgets/Sidebar.vala @@ -24,7 +24,7 @@ public class Code.Sidebar : Gtk.Grid { public Gtk.Stack stack { get; private set; } public Code.ChooseProjectButton choose_project_button { get; private set; } - public Hdy.HeaderBar headerbar { get; private set; } + public Adw.HeaderBar headerbar { get; private set; } public GLib.MenuModel project_menu_model { get; construct; } private Gtk.StackSwitcher stack_switcher; From f8445135211578371b8c80384b2492d4527538c2 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 03:11:01 +0200 Subject: [PATCH 05/20] feat: migrate Gtk.Menu to GLib.Menu --- src/FolderManager/FileItem.vala | 6 ++---- src/FolderManager/FolderItem.vala | 6 ++---- src/FolderManager/ProjectFolderItem.vala | 6 ++---- src/Widgets/SourceList/SourceList.vala | 2 +- src/Widgets/SourceView.vala | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/FolderManager/FileItem.vala b/src/FolderManager/FileItem.vala index 03d7289275..ede06f7b0b 100644 --- a/src/FolderManager/FileItem.vala +++ b/src/FolderManager/FileItem.vala @@ -31,7 +31,7 @@ namespace Scratch.FolderManager { view.activate (file.path); } - public override Gtk.Menu? get_context_menu () { + public override GLib.Menu? get_context_menu () { GLib.FileInfo info = null; try { @@ -88,9 +88,7 @@ namespace Scratch.FolderManager { menu_model.append_section (null, external_actions_section); menu_model.append_section (null, direct_actions_section); - var menu = new Gtk.Menu.from_model (menu_model); - menu.insert_action_group (FileView.ACTION_GROUP, view.actions); - return menu; + return menu_model; } private GLib.MenuItem create_submenu_for_open_in (string? file_type) { diff --git a/src/FolderManager/FolderItem.vala b/src/FolderManager/FolderItem.vala index 33f8e130de..31dc92b85d 100644 --- a/src/FolderManager/FolderItem.vala +++ b/src/FolderManager/FolderItem.vala @@ -87,7 +87,7 @@ namespace Scratch.FolderManager { } } - public override Gtk.Menu? get_context_menu () { + public override GLib.Menu? get_context_menu () { var open_in_terminal_pane_item = new GLib.MenuItem ( (_("Open in Terminal Pane")), GLib.Action.print_detailed_name ( @@ -152,9 +152,7 @@ namespace Scratch.FolderManager { menu_model.append_section (null, direct_actions_section); menu_model.append_section (null, search_section); - var menu = new Gtk.Menu.from_model (menu_model); - menu.insert_action_group (FileView.ACTION_GROUP, view.actions); - return menu; + return menu_model; } protected GLib.MenuItem create_submenu_for_open_in (string? file_type) { diff --git a/src/FolderManager/ProjectFolderItem.vala b/src/FolderManager/ProjectFolderItem.vala index 9998db6be3..697d4ab6b8 100644 --- a/src/FolderManager/ProjectFolderItem.vala +++ b/src/FolderManager/ProjectFolderItem.vala @@ -123,7 +123,7 @@ namespace Scratch.FolderManager { } } - public override Gtk.Menu? get_context_menu () { + public override GLib.Menu? get_context_menu () { GLib.FileInfo info = null; unowned string? file_type = null; @@ -296,9 +296,7 @@ namespace Scratch.FolderManager { menu_model.append_section (null, delete_actions_section); menu_model.append_section (null, search_actions_section); - var menu = new Gtk.Menu.from_model (menu_model); - menu.insert_action_group (FileView.ACTION_GROUP, view.actions); - return menu; + return menu_model; } protected GLib.MenuItem create_submenu_for_branch () { diff --git a/src/Widgets/SourceList/SourceList.vala b/src/Widgets/SourceList/SourceList.vala index 0ecff6daea..0f1f17d539 100644 --- a/src/Widgets/SourceList/SourceList.vala +++ b/src/Widgets/SourceList/SourceList.vala @@ -425,7 +425,7 @@ public class SourceList : Gtk.ScrolledWindow { * @return A {@link Gtk.Menu} or //null// if nothing should be displayed. * @since 0.2 */ - public virtual Gtk.Menu? get_context_menu () { + public virtual GLib.Menu? get_context_menu () { return null; } } diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 2759b98bfe..0bb1b80a90 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -551,7 +551,7 @@ namespace Scratch.Widgets { } } - private void on_context_menu (Gtk.Menu menu) { + private void on_context_menu (GLib.Menu menu) { var sort_item = new Gtk.MenuItem (); sort_item.sensitive = get_selected_line_count () > 1; sort_item.add (new Granite.AccelLabel.from_action_name ( From 6eb18d8ddeaaec542e60e5e4ddb0aa442d1b8da7 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 14:41:39 +0200 Subject: [PATCH 06/20] feat: migrate Granite.Widgets.Welcome to Granite.Placeholder --- src/Widgets/WelcomeView.vala | 2 +- triage.txt | 699 +++++++++++++++++++++++++++++++++++ 2 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 triage.txt diff --git a/src/Widgets/WelcomeView.vala b/src/Widgets/WelcomeView.vala index 23ffaeef98..e91bf7356a 100644 --- a/src/Widgets/WelcomeView.vala +++ b/src/Widgets/WelcomeView.vala @@ -17,7 +17,7 @@ * Authored by: Corentin Noël */ -public class Code.WelcomeView : Granite.Widgets.Welcome { +public class Code.WelcomeView : Granite.Placeholder { public unowned Scratch.MainWindow window { get; construct; } public WelcomeView (Scratch.MainWindow window) { diff --git a/triage.txt b/triage.txt new file mode 100644 index 0000000000..f3b7dc9f58 --- /dev/null +++ b/triage.txt @@ -0,0 +1,699 @@ + + + + + GTK SOURCE VIEW + + + + + + +../src/Services/Document.vala:54.17-54.30: error: The type name `Gtk.SourceFile' could not be found + 54 | private Gtk.SourceFile source_file; + | ^~~~~~~~~~~~~~ +../src/Services/Document.vala:166.17-166.29: error: The type name `Gtk.SourceMap' could not be found + 166 | private Gtk.SourceMap source_map; + | ^~~~~~~~~~~~~ +../src/Services/Document.vala:416.59-416.74: error: The type name `Gtk.SourceBuffer' could not be found + 416 | var source_buffer = source_view.buffer as Gtk.SourceBuffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:596.63-596.78: error: The type name `Gtk.SourceBuffer' could not be found + 596 | var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:805.34-805.49: error: The type name `Gtk.SourceBuffer' could not be found + 805 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:816.34-816.49: error: The type name `Gtk.SourceBuffer' could not be found + 816 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:1076.34-1076.49: error: The type name `Gtk.SourceBuffer' could not be found + 1076 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:1253.34-1253.49: error: The type name `Gtk.SourceBuffer' could not be found + 1253 | var source_buffer = (Gtk.SourceBuffer)source_view.buffer; + +../src/SymbolPane/SymbolOutline.vala:240.32-240.47: error: The type name `Gtk.SourceBuffer' could not be found + 240 | update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); + | ^~~~~~~~~~~~~~~~ +../src/SymbolPane/SymbolOutline.vala:244.41-244.61: error: The type name `Gtk.SourceStyleScheme' could not be found + 244 | protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { + | ../src/Widgets/SourceGutterRenderer.vala:1.53-1.76: error: The type name `Gtk.SourceGutterRenderer' could not be found + 1 | public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:9.20-9.41: error: The type name `Gtk.SourceStyleScheme' could not be found + 9 | private static Gtk.SourceStyleScheme? fallback_scheme; + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:27.35-27.56: error: The type name `Gtk.SourceStyleScheme' could not be found + 27 | public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:36.43-36.64: error: The type name `Gtk.SourceStyleScheme' could not be found + 36 | Gtk.SourceStyleScheme? scheme, + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:40.9-40.23: error: The type name `Gtk.SourceStyle' could not be found + 40 | Gtk.SourceStyle style = null; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:64.32-64.60: error: The type name `Gtk.SourceGutterRendererState' could not be found + 64 | Gtk.SourceGutterRendererState state) { + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:243.79-243.94: error: The type name `Gtk.SourceBuffer' could not be found + 243 | this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); + | ^~~~~~~~~~~~~~~~ + ../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:23.31-23.44: error: The type name `Gtk.SourceView' could not be found + 23 | public class SourceView : Gtk.SourceView { + | ^~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:24.16-24.40: error: The type name `Gtk.SourceLanguageManager' could not be found + 24 | public Gtk.SourceLanguageManager manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:25.16-25.43: error: The type name `Gtk.SourceStyleSchemeManager' could not be found + 25 | public Gtk.SourceStyleSchemeManager style_scheme_manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:245.34-245.49: error: The type name `Gtk.SourceBuffer' could not be found + 245 | var source_buffer = (Gtk.SourceBuffer) buffer; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:510.34-510.49: error: The type name `Gtk.SourceBuffer' could not be found + 510 | var source_buffer = (Gtk.SourceBuffer) buffer; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:565.27-565.42: error: The type name `Gtk.SourceBuffer' could not be found + 565 | if (buffer is Gtk.SourceBuffer) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:566.75-566.90: error: The type name `Gtk.SourceBuffer' could not be found + 566 | var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ()); + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:575.53-575.68: error: The type name `Gtk.SourceBuffer' could not be found + 575 | CommentToggler.toggle_comment ((Gtk.SourceBuffer) buffer); + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:56.26-56.41: error: The type name `Gtk.SourceBuffer' could not be found + 56 | return ((Gtk.SourceBuffer) buffer).language; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:53.19-53.34: error: The type name `Gtk.SourceBuffer' could not be found + 53 | ((Gtk.SourceBuffer) buffer).language = value; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:45.43-45.63: error: The type name `Gtk.SourceStyleScheme' could not be found + 45 | public signal void style_changed (Gtk.SourceStyleScheme style); + | ^~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~ +../src/MainWindow.vala:1321.27-1321.42: error: The type name `Gtk.SourceBuffer' could not be found + 1321 | if (buffer is Gtk.SourceBuffer) { + | ^~~~~~~~~~~~~~~~ +../src/MainWindow.vala:1322.58-1322.73: error: The type name `Gtk.SourceBuffer' could not be found + 1322 | CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:27.59-27.76: error: The type name `Gtk.SourceLanguage' could not be found + 27 | private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, + | ^~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:67.47-67.65: error: The type name `Gtk.SourceLanguage' could not be found + 67 | public static bool language_has_comments (Gtk.SourceLanguage? lang) { + | ^~~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:80.57-80.72: error: The type name `Gtk.SourceBuffer' could not be found + 80 | private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:84.57-84.74: error: The type name `Gtk.SourceLanguage' could not be found + 84 | Gtk.SourceLanguage lang) { + | ^~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:121.42-121.57: error: The type name `Gtk.SourceBuffer' could not be found + 121 | private static void remove_comments (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:202.39-202.54: error: The type name `Gtk.SourceBuffer' could not be found + 202 | private static void add_comments (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:300.40-300.56: error: The type name `Gtk.SourceBuffer' could not be found + 300 | public static void toggle_comment (Gtk.SourceBuffer? buffer) { + | ^~~~~~~~~~~~~~~~~ +../src/Services/Document.vala:54.17-54.30: error: The type name `Gtk.SourceFile' could not be found + 54 | private Gtk.SourceFile source_file; + | ^~~~~~~~~~~~~~ +../src/Services/Document.vala:166.17-166.29: error: The type name `Gtk.SourceMap' could not be found + 166 | private Gtk.SourceMap source_map; + | ^~~~~~~~~~~~~ +../src/Services/Document.vala:416.59-416.74: error: The type name `Gtk.SourceBuffer' could not be found + 416 | var source_buffer = source_view.buffer as Gtk.SourceBuffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:596.63-596.78: error: The type name `Gtk.SourceBuffer' could not be found + 596 | var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:805.34-805.49: error: The type name `Gtk.SourceBuffer' could not be found + 805 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:816.34-816.49: error: The type name `Gtk.SourceBuffer' could not be found + 816 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:1076.34-1076.49: error: The type name `Gtk.SourceBuffer' could not be found + 1076 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + | ^~~~~~~~~~~~~~~~ +../src/Services/Document.vala:1253.34-1253.49: error: The type name `Gtk.SourceBuffer' could not be found + 1253 | var source_buffer = (Gtk.SourceBuffer)source_view.buffer; + | ../src/SymbolPane/SymbolOutline.vala:240.32-240.47: error: The type name `Gtk.SourceBuffer' could not be found + 240 | update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); + | ^~~~~~~~~~~~~~~~ +../src/SymbolPane/SymbolOutline.vala:244.41-244.61: error: The type name `Gtk.SourceStyleScheme' could not be found + 244 | protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { + | ^~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:1.53-1.76: error: The type name `Gtk.SourceGutterRenderer' could not be found + 1 | public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:9.20-9.41: error: The type name `Gtk.SourceStyleScheme' could not be found + 9 | private static Gtk.SourceStyleScheme? fallback_scheme; + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:27.35-27.56: error: The type name `Gtk.SourceStyleScheme' could not be found + 27 | public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:36.43-36.64: error: The type name `Gtk.SourceStyleScheme' could not be found + 36 | Gtk.SourceStyleScheme? scheme, + | ^~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:40.9-40.23: error: The type name `Gtk.SourceStyle' could not be found + 40 | Gtk.SourceStyle style = null; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceGutterRenderer.vala:64.32-64.60: error: The type name `Gtk.SourceGutterRendererState' could not be found + 64 | Gtk.SourceGutterRendererState state) { + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:243.79-243.94: error: The type name `Gtk.SourceBuffer' could not be found + 243 | this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found + 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:23.31-23.44: error: The type name `Gtk.SourceView' could not be found + 23 | public class SourceView : Gtk.SourceView { + | ^~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:24.16-24.40: error: The type name `Gtk.SourceLanguageManager' could not be found + 24 | public Gtk.SourceLanguageManager manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:25.16-25.43: error: The type name `Gtk.SourceStyleSchemeManager' could not be found + 25 | public Gtk.SourceStyleSchemeManager style_scheme_manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:245.34-245.49: error: The type name `Gtk.SourceBuffer' could not be found + 245 | var source_buffer = (Gtk.SourceBuffer) buffer; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:510.34-510.49: error: The type name `Gtk.SourceBuffer' could not be found + 510 | var source_buffer = (Gtk.SourceBuffer) buffer; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:565.27-565.42: error: The type name `Gtk.SourceBuffer' could not be found + 565 | if (buffer is Gtk.SourceBuffer) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:566.75-566.90: error: The type name `Gtk.SourceBuffer' could not be found + 566 | var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ()); + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:575.53-575.68: error: The type name `Gtk.SourceBuffer' could not be found + 575 | CommentToggler.toggle_comment ((Gtk.SourceBuffer) buffer); + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:56.26-56.41: error: The type name `Gtk.SourceBuffer' could not be found + 56 | return ((Gtk.SourceBuffer) buffer).language; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found + 51 | public Gtk.SourceLanguage? language { + | ^~~~~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:53.19-53.34: error: The type name `Gtk.SourceBuffer' could not be found + 53 | ((Gtk.SourceBuffer) buffer).language = value; + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceView.vala:45.43-45.63: error: The type name `Gtk.SourceStyleScheme' could not be found + 45 | public signal void style_changed (Gtk.SourceStyleScheme style); + | ^~~~~~~~~~~~~~~~~~~~~ + + + + + + + + + PEAS LIBRARY + + + + + + + | ^~~~~~~~~~~~~~~~ +../src/Services/PluginManager.vala:55.9-55.12: error: The symbol `Peas' could not be found + 55 | Peas.Engine engine; + | ^~~~ +../src/Services/PluginManager.vala:56.9-56.12: error: The symbol `Peas' could not be found + 56 | Peas.ExtensionSet exts; + | ^~~~ +../src/Services/PluginManager.vala:89.59-89.62: error: The symbol `Peas' could not be found + 89 | exts = new Peas.ExtensionSet (engine, typeof (Peas.Activatable), "object", plugin_iface, null); + | ^~~~ +../src/Services/PluginManager.vala:92.19-92.22: error: The symbol `Peas' could not be found + 92 | ((Peas.Activatable)ext).activate (); + | ^~~~ +../src/Services/PluginManager.vala:97.19-97.22: error: The symbol `Peas' could not be found + 97 | ((Peas.Activatable)ext).deactivate (); + | ^~~~ +../src/Services/PluginManager.vala:129.36-129.39: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:129.59-129.62: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:129.81-129.84: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:130.15-130.18: error: The symbol `Peas' could not be found + 130 | ((Peas.Activatable)extension).activate (); + | ^~~~ +../src/Services/PluginManager.vala:72.45-72.48: error: The symbol `Peas' could not be found + 72 | public signal void extension_added (Peas.PluginInfo info); + | ^~~~ +../src/Services/PluginManager.vala:73.47-73.50: error: The symbol `Peas' could not be found + 73 | public signal void extension_removed (Peas.PluginInfo info); + | ../src/Services/PluginManager.vala:55.9-55.12: error: The symbol `Peas' could not be found + 55 | Peas.Engine engine; + | ^~~~ +../src/Services/PluginManager.vala:56.9-56.12: error: The symbol `Peas' could not be found + 56 | Peas.ExtensionSet exts; + | ^~~~ +../src/Services/PluginManager.vala:89.59-89.62: error: The symbol `Peas' could not be found + 89 | exts = new Peas.ExtensionSet (engine, typeof (Peas.Activatable), "object", plugin_iface, null); + | ^~~~ +../src/Services/PluginManager.vala:92.19-92.22: error: The symbol `Peas' could not be found + 92 | ((Peas.Activatable)ext).activate (); + | ^~~~ +../src/Services/PluginManager.vala:97.19-97.22: error: The symbol `Peas' could not be found + 97 | ((Peas.Activatable)ext).deactivate (); + | ^~~~ +../src/Services/PluginManager.vala:129.36-129.39: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:129.59-129.62: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:129.81-129.84: error: The symbol `Peas' could not be found + 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { + | ^~~~ +../src/Services/PluginManager.vala:130.15-130.18: error: The symbol `Peas' could not be found + 130 | ((Peas.Activatable)extension).activate (); + | ^~~~ +../src/Services/PluginManager.vala:72.45-72.48: error: The symbol `Peas' could not be found + 72 | public signal void extension_added (Peas.PluginInfo info); + | ^~~~ +../src/Services/PluginManager.vala:73.47-73.50: error: The symbol `Peas' could not be found + 73 | public signal void extension_removed (Peas.PluginInfo info); + | ^~~~ ^~~~ + + + + + + GTK DRAG AND DROP OR WIDGETS + + + + + + +../src/Widgets/DocumentView.vala:650.33-650.47: error: The type name `Gdk.DragContext' could not be found + 650 | Gdk.DragContext ctx, + | ^~~~~~~~~~~~~~~ +../src/Widgets/DocumentView.vala:653.33-653.49: error: The type name `Gtk.SelectionData' could not be found + 653 | Gtk.SelectionData sel, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/DocumentView.vala:168.9-168.23: error: The type name `Gtk.TargetEntry' could not be found + 168 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:343.50-343.63: error: The type name `Gdk.EventFocus' could not be found + 343 | private bool on_search_entry_focused_in (Gdk.EventFocus event) { + | ^~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:480.49-480.60: error: The type name `Gdk.EventKey' could not be found + 480 | private bool on_search_entry_key_press (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:511.50-511.61: error: The type name `Gdk.EventKey' could not be found + 511 | private bool on_replace_entry_key_press (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/MainWindow.vala:53.16-53.28: error: The type name `Gtk.Clipboard' could not be found + 53 | public Gtk.Clipboard clipboard; + | ^~~~~~~~~~~~~ +../src/MainWindow.vala:456.13-456.27: error: The type name `Gtk.TargetEntry' could not be found + 456 | Gtk.TargetEntry target = {"text/uri-list", 0, 0}; + | ^~~~~~~~~~~~~~~ +../src/MainWindow.vala:724.47-724.58: error: The type name `Gdk.EventAny' could not be found + 724 | protected override bool delete_event (Gdk.EventAny event) { + | ^~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2767.37-2767.51: error: The type name `Gtk.TargetEntry' could not be found + 2767 | public void enable_drag_source (Gtk.TargetEntry[] src_entries) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2794.35-2794.49: error: The type name `Gtk.TargetEntry' could not be found + 2794 | public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1206.60-1206.76: error: The type name `Gtk.SelectionData' could not be found + 1206 | public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1310.59-1310.75: error: The type name `Gtk.SelectionData' could not be found + 1310 | public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1421.55-1421.71: error: The type name `Gtk.SelectionData' could not be found + 1421 | public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1730.43-1730.57: error: The type name `Gdk.DragContext' could not be found + 1730 | public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1795.13-1795.27: error: The type name `Gdk.DragContext' could not be found + 1795 | Gdk.DragContext context, + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1798.13-1798.29: error: The type name `Gtk.SelectionData' could not be found + 1798 | Gtk.SelectionData selection_data, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1853.44-1853.58: error: The type name `Gtk.TargetEntry' could not be found + 1853 | public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1861.42-1861.56: error: The type name `Gtk.TargetEntry' could not be found + 1861 | public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1918.24-1918.38: error: The type name `Gtk.TargetEntry' could not be found + 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1918.67-1918.81: error: The type name `Gtk.TargetEntry' could not be found + 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1919.19-1919.33: error: The type name `Gtk.TargetEntry' could not be found + 1919 | const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1925.31-1925.45: error: The type name `Gtk.TargetEntry' could not be found + 1925 | var entries = new Gtk.TargetEntry[0]; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2235.49-2235.60: error: The type name `Gdk.EventKey' could not be found + 2235 | public override bool key_release_event (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2250.52-2250.66: error: The type name `Gdk.EventButton' could not be found + 2250 | public override bool button_release_event (Gdk.EventButton event) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2271.50-2271.64: error: The type name `Gdk.EventButton' could not be found + 2271 | public override bool button_press_event (Gdk.EventButton event) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2396.54-2396.69: error: The type name `Gdk.EventButton' could not be found + 2396 | private bool popup_context_menu (Item? item, Gdk.EventButton? event) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:93.50-93.66: error: The type name `Gtk.SelectionData' could not be found + 93 | public abstract void prepare_selection_data (Gtk.SelectionData selection_data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:110.46-110.60: error: The type name `Gdk.DragContext' could not be found + 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:110.71-110.87: error: The type name `Gtk.SelectionData' could not be found + 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:122.51-122.65: error: The type name `Gdk.DragContext' could not be found + 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:122.76-122.92: error: The type name `Gtk.SelectionData' could not be found + 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found + 23 | public unowned Gtk.RadioButton? group_source { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found + 23 | public unowned Gtk.RadioButton? group_source { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:193.49-193.64: error: The type name `Gtk.RadioButton' could not be found + 193 | public ProjectRow (string project_path, Gtk.RadioButton? group_source ) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:34.13-34.37: error: The type name `Gtk.SourceLanguageManager' could not be found + 34 | private Gtk.SourceLanguageManager manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:103.23-103.37: error: The type name `Gtk.RadioButton' could not be found + 103 | unowned SList group = null; + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:105.13-105.35: error: The type name `Gtk.SourceLanguage' could not be found + 105 | weak Gtk.SourceLanguage lang = manager.get_language (id); + | ^~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:378.17-378.31: error: The type name `Gtk.RadioButton' could not be found + 378 | private Gtk.RadioButton lang_radio; + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:379.68-379.82: error: The type name `Gtk.RadioButton' could not be found + 379 | public LangEntry (string? lang_id, string lang_name, SList group) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:400.30-400.44: error: The type name `Gtk.RadioButton' could not be found + 400 | public unowned SList get_radio_group () { + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:120.33-120.47: error: The type name `Gdk.DragContext' could not be found + 120 | Gdk.DragContext ctx, + | ^~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:123.33-123.49: error: The type name `Gtk.SelectionData' could not be found + 123 | Gtk.SelectionData sel, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:114.9-114.23: error: The type name `Gtk.TargetEntry' could not be found + 114 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + | ^~~~~~~~~~~~~~~ +../src/Widgets/Terminal.vala:22.13-22.25: error: The type name `Gtk.Clipboard' could not be found + 22 | private Gtk.Clipboard current_clipboard; + | ^~~~~~~~~~~~~ +../src/Widgets/DocumentView.vala:650.33-650.47: error: The type name `Gdk.DragContext' could not be found + 650 | Gdk.DragContext ctx, + | ^~~~~~~~~~~~~~~ +../src/Widgets/DocumentView.vala:653.33-653.49: error: The type name `Gtk.SelectionData' could not be found + 653 | Gtk.SelectionData sel, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/DocumentView.vala:168.9-168.23: error: The type name `Gtk.TargetEntry' could not be found + 168 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:343.50-343.63: error: The type name `Gdk.EventFocus' could not be found + 343 | private bool on_search_entry_focused_in (Gdk.EventFocus event) { + | ^~~~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:480.49-480.60: error: The type name `Gdk.EventKey' could not be found + 480 | private bool on_search_entry_key_press (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/Widgets/SearchBar.vala:511.50-511.61: error: The type name `Gdk.EventKey' could not be found + 511 | private bool on_replace_entry_key_press (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/MainWindow.vala:53.16-53.28: error: The type name `Gtk.Clipboard' could not be found + 53 | public Gtk.Clipboard clipboard; + | ^~~~~~~~~~~~~ +../src/MainWindow.vala:456.13-456.27: error: The type name `Gtk.TargetEntry' could not be found + 456 | Gtk.TargetEntry target = {"text/uri-list", 0, 0}; + | ^~~~~~~~~~~~~~~ +../src/MainWindow.vala:724.47-724.58: error: The type name `Gdk.EventAny' could not be found + 724 | protected override bool delete_event (Gdk.EventAny event) { + | ^~~~~~~~~~~~ +../src/MainWindow.vala:1321.27-1321.42: error: The type name `Gtk.SourceBuffer' could not be found + 1321 | if (buffer is Gtk.SourceBuffer) { + | ^~~~~~~~~~~~~~~~ +../src/MainWindow.vala:1322.58-1322.73: error: The type name `Gtk.SourceBuffer' could not be found + 1322 | CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:27.59-27.76: error: The type name `Gtk.SourceLanguage' could not be found + 27 | private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, + | ^~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:67.47-67.65: error: The type name `Gtk.SourceLanguage' could not be found + 67 | public static bool language_has_comments (Gtk.SourceLanguage? lang) { + | ^~~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:80.57-80.72: error: The type name `Gtk.SourceBuffer' could not be found + 80 | private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:84.57-84.74: error: The type name `Gtk.SourceLanguage' could not be found + 84 | Gtk.SourceLanguage lang) { + | ^~~~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:121.42-121.57: error: The type name `Gtk.SourceBuffer' could not be found + 121 | private static void remove_comments (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:202.39-202.54: error: The type name `Gtk.SourceBuffer' could not be found + 202 | private static void add_comments (Gtk.SourceBuffer buffer, + | ^~~~~~~~~~~~~~~~ +../src/Services/CommentToggler.vala:300.40-300.56: error: The type name `Gtk.SourceBuffer' could not be found + 300 | public static void toggle_comment (Gtk.SourceBuffer? buffer) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2767.37-2767.51: error: The type name `Gtk.TargetEntry' could not be found + 2767 | public void enable_drag_source (Gtk.TargetEntry[] src_entries) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2794.35-2794.49: error: The type name `Gtk.TargetEntry' could not be found + 2794 | public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1206.60-1206.76: error: The type name `Gtk.SelectionData' could not be found + 1206 | public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1310.59-1310.75: error: The type name `Gtk.SelectionData' could not be found + 1310 | public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1421.55-1421.71: error: The type name `Gtk.SelectionData' could not be found + 1421 | public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1730.43-1730.57: error: The type name `Gdk.DragContext' could not be found + 1730 | public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1795.13-1795.27: error: The type name `Gdk.DragContext' could not be found + 1795 | Gdk.DragContext context, + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1798.13-1798.29: error: The type name `Gtk.SelectionData' could not be found + 1798 | Gtk.SelectionData selection_data, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1853.44-1853.58: error: The type name `Gtk.TargetEntry' could not be found + 1853 | public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1861.42-1861.56: error: The type name `Gtk.TargetEntry' could not be found + 1861 | public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1918.24-1918.38: error: The type name `Gtk.TargetEntry' could not be found + 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1918.67-1918.81: error: The type name `Gtk.TargetEntry' could not be found + 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1919.19-1919.33: error: The type name `Gtk.TargetEntry' could not be found + 1919 | const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:1925.31-1925.45: error: The type name `Gtk.TargetEntry' could not be found + 1925 | var entries = new Gtk.TargetEntry[0]; + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2235.49-2235.60: error: The type name `Gdk.EventKey' could not be found + 2235 | public override bool key_release_event (Gdk.EventKey event) { + | ^~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2250.52-2250.66: error: The type name `Gdk.EventButton' could not be found + 2250 | public override bool button_release_event (Gdk.EventButton event) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2271.50-2271.64: error: The type name `Gdk.EventButton' could not be found + 2271 | public override bool button_press_event (Gdk.EventButton event) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:2396.54-2396.69: error: The type name `Gdk.EventButton' could not be found + 2396 | private bool popup_context_menu (Item? item, Gdk.EventButton? event) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:93.50-93.66: error: The type name `Gtk.SelectionData' could not be found + 93 | public abstract void prepare_selection_data (Gtk.SelectionData selection_data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:110.46-110.60: error: The type name `Gdk.DragContext' could not be found + 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:110.71-110.87: error: The type name `Gtk.SelectionData' could not be found + 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:122.51-122.65: error: The type name `Gdk.DragContext' could not be found + 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~ +../src/Widgets/SourceList/SourceList.vala:122.76-122.92: error: The type name `Gtk.SelectionData' could not be found + 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found + 23 | public unowned Gtk.RadioButton? group_source { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found + 23 | public unowned Gtk.RadioButton? group_source { + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:193.49-193.64: error: The type name `Gtk.RadioButton' could not be found + 193 | public ProjectRow (string project_path, Gtk.RadioButton? group_source ) { + | ^~~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found + 191 | public Gtk.RadioButton project_radio { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:34.13-34.37: error: The type name `Gtk.SourceLanguageManager' could not be found + 34 | private Gtk.SourceLanguageManager manager; + | ^~~~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:103.23-103.37: error: The type name `Gtk.RadioButton' could not be found + 103 | unowned SList group = null; + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:105.13-105.35: error: The type name `Gtk.SourceLanguage' could not be found + 105 | weak Gtk.SourceLanguage lang = manager.get_language (id); + | ^~~~~~~~~~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:378.17-378.31: error: The type name `Gtk.RadioButton' could not be found + 378 | private Gtk.RadioButton lang_radio; + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:379.68-379.82: error: The type name `Gtk.RadioButton' could not be found + 379 | public LangEntry (string? lang_id, string lang_name, SList group) { + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:400.30-400.44: error: The type name `Gtk.RadioButton' could not be found + 400 | public unowned SList get_radio_group () { + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found + 354 | public unowned SList group { get; construct; } + | ^~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:120.33-120.47: error: The type name `Gdk.DragContext' could not be found + 120 | Gdk.DragContext ctx, + | ^~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:123.33-123.49: error: The type name `Gtk.SelectionData' could not be found + 123 | Gtk.SelectionData sel, + | ^~~~~~~~~~~~~~~~~ +../src/Widgets/Sidebar.vala:114.9-114.23: error: The type name `Gtk.TargetEntry' could not be found + 114 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + | ^~~~~~~~~~~~~~~ +../src/Widgets/Terminal.vala:22.13-22.25: error: The type name `Gtk.Clipboard' could not be found + 22 | private Gtk.Clipboard current_clipboard; + | ^~~~~~~~~~~~~ + + + + + GRANITE + + + +../src/Widgets/WelcomeView.vala:20.33-20.55: error: The type name `Granite.Widgets.Welcome' could not be found + 20 | public class Code.WelcomeView : Granite.Widgets.Welcome { +../src/Widgets/WelcomeView.vala:20.33-20.55: error: The type name `Granite.Widgets.Welcome' could not be found + 20 | public class Code.WelcomeView : Granite.Widgets.Welcome { + | ^~~~~~~~~~~~~~~~~~~~~~~ +Compilation failed: 109 error(s), 0 warning(s) +ninja: build stopped: subcommand failed. From 8fba88dca0d45510aec78fe7c1cac2cdf8d94fe1 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 14:53:00 +0200 Subject: [PATCH 07/20] feat: migrate Gtk.Clipboard --- src/MainWindow.vala | 4 ++-- src/Widgets/Terminal.vala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 81322e0b43..fe98949e65 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -50,7 +50,7 @@ namespace Scratch { private Gtk.Paned vp; private Gtk.Stack content_stack; - public Gtk.Clipboard clipboard; + public Gdk.Clipboard clipboard; // Delegates delegate void HookFunc (); @@ -279,7 +279,7 @@ namespace Scratch { update_style (); }); - clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + clipboard = Gdk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); plugins = new Scratch.Services.PluginsManager (this); diff --git a/src/Widgets/Terminal.vala b/src/Widgets/Terminal.vala index 2219769a5a..156c4b9965 100644 --- a/src/Widgets/Terminal.vala +++ b/src/Widgets/Terminal.vala @@ -19,7 +19,7 @@ public class Code.Terminal : Gtk.Box { public SimpleActionGroup actions { get; construct; } private GLib.Pid child_pid; - private Gtk.Clipboard current_clipboard; + private Gdk.Clipboard current_clipboard; construct { terminal = new Vte.Terminal () { From 4a879659daf77a5ad1ebdee466b5ee83ca6445ec Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 15:29:31 +0200 Subject: [PATCH 08/20] feat: migrate Gtk.RadioButton --- src/Widgets/ChooseProjectButton.vala | 10 ++++++---- src/Widgets/FormatBar.vala | 14 ++++++++------ src/Widgets/HeaderBar.vala | 10 ++++++---- src/Widgets/SourceView.vala | 4 ++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Widgets/ChooseProjectButton.vala b/src/Widgets/ChooseProjectButton.vala index 79f597435f..7d39a79bc1 100644 --- a/src/Widgets/ChooseProjectButton.vala +++ b/src/Widgets/ChooseProjectButton.vala @@ -16,11 +16,13 @@ * */ +// TODO: make CheckButton radio buttons + public class Code.ChooseProjectButton : Gtk.MenuButton { private const string NO_PROJECT_SELECTED = N_("No Project Selected"); private Gtk.Label label_widget; private Gtk.ListBox project_listbox; - public unowned Gtk.RadioButton? group_source { + public unowned Gtk.CheckButton? group_source { get { var first_row = project_listbox.get_row_at_index (0); if (first_row != null) { @@ -188,12 +190,12 @@ public class Code.ChooseProjectButton : Gtk.MenuButton { } } - public Gtk.RadioButton project_radio { get; construct; } + public Gtk.CheckButton project_radio { get; construct; } - public ProjectRow (string project_path, Gtk.RadioButton? group_source ) { + public ProjectRow (string project_path, Gtk.CheckButton? group_source ) { Object ( project_path: project_path, - project_radio: new Gtk.RadioButton.with_label_from_widget (group_source, Path.get_basename (project_path)) + project_radio: new Gtk.CheckButton.with_label_from_widget (group_source, Path.get_basename (project_path)) ); } diff --git a/src/Widgets/FormatBar.vala b/src/Widgets/FormatBar.vala index 53d4673eef..acf3b3a286 100644 --- a/src/Widgets/FormatBar.vala +++ b/src/Widgets/FormatBar.vala @@ -17,6 +17,8 @@ * Authored by: Corentin Noël */ +// TODO: make CheckButton radio buttons + public class Code.FormatBar : Gtk.Box { public bool tab_style_set_by_editor_config { get; set; default = false; } public bool tab_width_set_by_editor_config { get; set; default = false; } @@ -100,7 +102,7 @@ public class Code.FormatBar : Gtk.Box { lang_scrolled.add (lang_selection_listbox); unowned string[]? ids = manager.get_language_ids (); - unowned SList group = null; + unowned SList group = null; foreach (unowned string id in ids) { weak Gtk.SourceLanguage lang = manager.get_language (id); var entry = new LangEntry (id, lang.name, group); @@ -351,7 +353,7 @@ public class Code.FormatBar : Gtk.Box { public class LangEntry : Gtk.ListBoxRow { public string? lang_id { get; construct; } public string lang_name { get; construct; } - public unowned SList group { get; construct; } + public unowned SList group { get; construct; } public bool active { get { @@ -375,8 +377,8 @@ public class Code.FormatBar : Gtk.Box { } } - private Gtk.RadioButton lang_radio; - public LangEntry (string? lang_id, string lang_name, SList group) { + private Gtk.CheckButton lang_radio; + public LangEntry (string? lang_id, string lang_name, SList group) { Object (group: group, lang_id: lang_id, lang_name: lang_name); } @@ -385,7 +387,7 @@ public class Code.FormatBar : Gtk.Box { } construct { - lang_radio = new Gtk.RadioButton.with_label (group, lang_name); + lang_radio = new Gtk.CheckButton.with_label (group, lang_name); add (lang_radio); lang_radio.toggled.connect (radio_toggled); @@ -397,7 +399,7 @@ public class Code.FormatBar : Gtk.Box { } } - public unowned SList get_radio_group () { + public unowned SList get_radio_group () { return lang_radio.get_group (); } } diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index 71b04cf462..dab7781a1b 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -4,6 +4,8 @@ * 2013 Mario Guerriero */ +// TODO: make CheckButton radio buttons + public class Scratch.HeaderBar : Adw.HeaderBar { // Plugins segfault without full access public Code.FormatBar format_bar; @@ -147,19 +149,19 @@ public class Scratch.HeaderBar : Adw.HeaderBar { }; // Intentionally never attached so we can have a non-selected state - var color_button_none = new Gtk.RadioButton (null); + var color_button_none = new Gtk.CheckButton (null); - var color_button_white = new Gtk.RadioButton.from_widget (color_button_none) { + var color_button_white = new Gtk.CheckButton.from_widget (color_button_none) { halign = Gtk.Align.CENTER }; style_color_button (color_button_white, STYLE_SCHEME_HIGH_CONTRAST); - var color_button_light = new Gtk.RadioButton.from_widget (color_button_none) { + var color_button_light = new Gtk.CheckButton.from_widget (color_button_none) { halign = Gtk.Align.CENTER }; style_color_button (color_button_light, STYLE_SCHEME_LIGHT); - var color_button_dark = new Gtk.RadioButton.from_widget (color_button_none) { + var color_button_dark = new Gtk.CheckButton.from_widget (color_button_none) { halign = Gtk.Align.CENTER }; style_color_button (color_button_dark, STYLE_SCHEME_DARK); diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 0bb1b80a90..8b5e4b516c 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -155,7 +155,7 @@ namespace Scratch.Widgets { Gtk.TextIter iter_start, iter_end; if (get_current_line (out iter_start, out iter_end)) { - var clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + var clipboard = Gdk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); string cut_text = iter_start.get_slice (iter_end); buffer.begin_user_action (); @@ -176,7 +176,7 @@ namespace Scratch.Widgets { Gtk.TextIter iter_start, iter_end; if (get_current_line (out iter_start, out iter_end)) { - var clipboard = Gtk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); + var clipboard = Gdk.Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); string copy_text = iter_start.get_slice (iter_end); clipboard.set_text (copy_text, -1); From 7c9f662d331429dfb7bb00562997077a66ddeb4b Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:32:41 +0200 Subject: [PATCH 09/20] feat: migrate Gtk.SourceBuffer --- src/MainWindow.vala | 4 ++-- src/Services/CommentToggler.vala | 8 ++++---- src/Services/Document.vala | 16 ++++++++-------- src/SymbolPane/SymbolOutline.vala | 2 +- src/Widgets/SearchBar.vala | 2 +- src/Widgets/SourceView.vala | 16 ++++++++-------- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index fe98949e65..3825e549c1 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -1318,8 +1318,8 @@ namespace Scratch { } var buffer = doc.source_view.buffer; - if (buffer is Gtk.SourceBuffer) { - CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); + if (buffer is GtkSource.Buffer) { + CommentToggler.toggle_comment (buffer as GtkSource.Buffer); } } diff --git a/src/Services/CommentToggler.vala b/src/Services/CommentToggler.vala index 56e721f44c..739f5f7d63 100644 --- a/src/Services/CommentToggler.vala +++ b/src/Services/CommentToggler.vala @@ -77,7 +77,7 @@ public class Scratch.CommentToggler { // This is to detect whether to toggle comments on or off. If all lines are commented, then we want to remove // those comments. If only some are commented, then the user likely selected a chunk of code that already contained // a couple of comments. In that case, we still want to insert comments. - private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, + private static CommentType lines_already_commented (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, @@ -118,7 +118,7 @@ public class Scratch.CommentToggler { return CommentType.NONE; } - private static void remove_comments (Gtk.SourceBuffer buffer, + private static void remove_comments (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, @@ -199,7 +199,7 @@ public class Scratch.CommentToggler { buffer.end_user_action (); } - private static void add_comments (Gtk.SourceBuffer buffer, + private static void add_comments (GtkSource.Buffer buffer, Gtk.TextIter start, Gtk.TextIter end, uint num_lines, @@ -297,7 +297,7 @@ public class Scratch.CommentToggler { buffer.delete_mark (emark); } - public static void toggle_comment (Gtk.SourceBuffer? buffer) { + public static void toggle_comment (GtkSource.Buffer? buffer) { if (buffer != null) { Gtk.TextIter start, end; var sel = buffer.get_selection_bounds (out start, out end); diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 01399c3e8d..4ba3a74722 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -386,7 +386,7 @@ namespace Scratch.Services { Gtk.main_iteration (); } - var buffer = new Gtk.SourceBuffer (null); /* Faster to load into a separate buffer */ + var buffer = new GtkSource.Buffer (null); /* Faster to load into a separate buffer */ load_timout_id = Timeout.add_seconds_full (GLib.Priority.HIGH, 5, () => { if (load_cancellable != null && !load_cancellable.is_cancelled ()) { @@ -413,7 +413,7 @@ namespace Scratch.Services { try { var source_file_loader = new Gtk.SourceFileLoader (buffer, source_file); yield source_file_loader.load_async (GLib.Priority.LOW, load_cancellable, null); - var source_buffer = source_view.buffer as Gtk.SourceBuffer; + var source_buffer = source_view.buffer as GtkSource.Buffer; if (source_buffer != null) { source_buffer.begin_not_undoable_action (); source_buffer.text = buffer.text; @@ -593,7 +593,7 @@ namespace Scratch.Services { save_cancellable.cancel (); save_cancellable = new GLib.Cancellable (); - var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); + var source_file_saver = new Gtk.SourceFileSaver ((GtkSource.Buffer) source_view.buffer, source_file); var success = false; var error = ""; try { @@ -802,7 +802,7 @@ namespace Scratch.Services { // Get language name public string get_language_name () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.name; @@ -813,7 +813,7 @@ namespace Scratch.Services { // Get language id public string get_language_id () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.id; @@ -898,7 +898,7 @@ namespace Scratch.Services { // If user selects to continue regardless then no further // check made for this document // External changes will be overwritten on next (auto) save - var new_buffer = new Gtk.SourceBuffer (null); + var new_buffer = new GtkSource.Buffer (null); var source_file_loader = new Gtk.SourceFileLoader ( new_buffer, source_file @@ -1073,7 +1073,7 @@ namespace Scratch.Services { } // Set Undo/Redo action sensitive property public void check_undoable_actions () { - var source_buffer = (Gtk.SourceBuffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; Utils.action_from_group (MainWindow.ACTION_UNDO, actions).set_enabled (source_buffer.can_undo); Utils.action_from_group (MainWindow.ACTION_REDO, actions).set_enabled (source_buffer.can_redo); Utils.action_from_group (MainWindow.ACTION_REVERT, actions).set_enabled ( @@ -1250,7 +1250,7 @@ namespace Scratch.Services { return; } - var source_buffer = (Gtk.SourceBuffer)source_view.buffer; + var source_buffer = (GtkSource.Buffer)source_view.buffer; Gtk.TextIter iter; var cursor_pos = source_buffer.cursor_position; diff --git a/src/SymbolPane/SymbolOutline.vala b/src/SymbolPane/SymbolOutline.vala index a42a79f289..65e174d184 100644 --- a/src/SymbolPane/SymbolOutline.vala +++ b/src/SymbolPane/SymbolOutline.vala @@ -237,7 +237,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { ); // Add a class to distinguish from foldermanager sourcelist get_style_context ().add_class ("symbol-outline"); - update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); + update_style_scheme (((GtkSource.Buffer)(doc.source_view.buffer)).style_scheme); doc.source_view.style_changed.connect (update_style_scheme); } diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 5f43f00155..6589035f67 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -240,7 +240,7 @@ namespace Scratch.Widgets { this.text_view.selection_changed.connect (on_selection_changed); this.text_buffer = text_view.get_buffer (); this.text_buffer.changed.connect (on_text_buffer_changed); - this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); + this.search_context = new Gtk.SourceSearchContext (text_buffer as GtkSource.Buffer, null); search_context.settings.wrap_around = cycle_search_button.active; search_context.settings.regex_enabled = regex_search_button.active; search_context.settings.search_text = search_entry.text; diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 8b5e4b516c..8bd31f4255 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -50,10 +50,10 @@ namespace Scratch.Widgets { //lang can be null, in the case of *No highlight style* aka Normal text public Gtk.SourceLanguage? language { set { - ((Gtk.SourceBuffer) buffer).language = value; + ((GtkSource.Buffer) buffer).language = value; } get { - return ((Gtk.SourceBuffer) buffer).language; + return ((GtkSource.Buffer) buffer).language; } } @@ -96,7 +96,7 @@ namespace Scratch.Widgets { font_css_provider = new Gtk.CssProvider (); get_style_context ().add_provider (font_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var source_buffer = new Gtk.SourceBuffer (null); + var source_buffer = new GtkSource.Buffer (null); set_buffer (source_buffer); source_buffer.highlight_syntax = true; source_buffer.mark_set.connect (on_mark_set); @@ -242,7 +242,7 @@ namespace Scratch.Widgets { show_right_margin = Scratch.settings.get_boolean ("show-right-margin"); right_margin_position = Scratch.settings.get_int ("right-margin-position"); insert_spaces_instead_of_tabs = Scratch.settings.get_boolean ("spaces-instead-of-tabs"); - var source_buffer = (Gtk.SourceBuffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; source_buffer.highlight_matching_brackets = Scratch.settings.get_boolean ("highlight-matching-brackets"); space_drawer.enable_matrix = false; switch ((ScratchDrawSpacesState) Scratch.settings.get_enum ("draw-spaces")) { @@ -507,7 +507,7 @@ namespace Scratch.Widgets { } public void set_text (string text, bool opening = true) { - var source_buffer = (Gtk.SourceBuffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; if (opening) { source_buffer.begin_not_undoable_action (); } @@ -562,8 +562,8 @@ namespace Scratch.Widgets { menu.add (sort_item); - if (buffer is Gtk.SourceBuffer) { - var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ()); + if (buffer is GtkSource.Buffer) { + var can_comment = CommentToggler.language_has_comments (((GtkSource.Buffer) buffer).get_language ()); var comment_item = new Gtk.MenuItem (); comment_item.sensitive = can_comment; @@ -572,7 +572,7 @@ namespace Scratch.Widgets { MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_COMMENT )); comment_item.activate.connect (() => { - CommentToggler.toggle_comment ((Gtk.SourceBuffer) buffer); + CommentToggler.toggle_comment ((GtkSource.Buffer) buffer); }); menu.add (comment_item); From e4510771c554f3e342f5556d9d428d36e909f3c5 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:36:55 +0200 Subject: [PATCH 10/20] feat: migrate Gtk.Source --- src/Services/Document.vala | 28 ++++++++--------- src/SymbolPane/SymbolOutline.vala | 2 +- src/Widgets/DocumentView.vala | 2 +- src/Widgets/SearchBar.vala | 4 +-- src/Widgets/SourceView.vala | 50 +++++++++++++++---------------- 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 4ba3a74722..c2859f11d3 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -51,7 +51,7 @@ namespace Scratch.Services { } } - private Gtk.SourceFile source_file; + private GtkSource..File source_file; public GLib.File file { get { return source_file.location; @@ -163,7 +163,7 @@ namespace Scratch.Services { private bool completion_shown = false; private Gtk.ScrolledWindow scroll; - private Gtk.SourceMap source_map; + private GtkSource..Map source_map; private Gtk.Paned outline_widget_pane; private GLib.Cancellable save_cancellable; @@ -210,8 +210,8 @@ namespace Scratch.Services { expand = true }; scroll.add (source_view); - source_file = new Gtk.SourceFile (); - source_map = new Gtk.SourceMap (); + source_file = new GtkSource..File (); + source_map = new GtkSource..Map (); outline_widget_pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); if (builder_blocks_font != null && builder_font_map != null) { @@ -386,7 +386,7 @@ namespace Scratch.Services { Gtk.main_iteration (); } - var buffer = new GtkSource.Buffer (null); /* Faster to load into a separate buffer */ + var buffer = new GtkSource..Buffer (null); /* Faster to load into a separate buffer */ load_timout_id = Timeout.add_seconds_full (GLib.Priority.HIGH, 5, () => { if (load_cancellable != null && !load_cancellable.is_cancelled ()) { @@ -411,9 +411,9 @@ namespace Scratch.Services { }); try { - var source_file_loader = new Gtk.SourceFileLoader (buffer, source_file); + var source_file_loader = new GtkSource.FileLoader (buffer, source_file); yield source_file_loader.load_async (GLib.Priority.LOW, load_cancellable, null); - var source_buffer = source_view.buffer as GtkSource.Buffer; + var source_buffer = source_view.buffer as GtkSource..Buffer; if (source_buffer != null) { source_buffer.begin_not_undoable_action (); source_buffer.text = buffer.text; @@ -593,7 +593,7 @@ namespace Scratch.Services { save_cancellable.cancel (); save_cancellable = new GLib.Cancellable (); - var source_file_saver = new Gtk.SourceFileSaver ((GtkSource.Buffer) source_view.buffer, source_file); + var source_file_saver = new GtkSource.FileSaver ((GtkSource.Buffer) source_view.buffer, source_file); var success = false; var error = ""; try { @@ -802,7 +802,7 @@ namespace Scratch.Services { // Get language name public string get_language_name () { - var source_buffer = (GtkSource.Buffer) source_view.buffer; + var source_buffer = (GtkSource..Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.name; @@ -813,7 +813,7 @@ namespace Scratch.Services { // Get language id public string get_language_id () { - var source_buffer = (GtkSource.Buffer) source_view.buffer; + var source_buffer = (GtkSource..Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.id; @@ -898,8 +898,8 @@ namespace Scratch.Services { // If user selects to continue regardless then no further // check made for this document // External changes will be overwritten on next (auto) save - var new_buffer = new GtkSource.Buffer (null); - var source_file_loader = new Gtk.SourceFileLoader ( + var new_buffer = new GtkSource..Buffer (null); + var source_file_loader = new GtkSource.FileLoader ( new_buffer, source_file ); @@ -1073,7 +1073,7 @@ namespace Scratch.Services { } // Set Undo/Redo action sensitive property public void check_undoable_actions () { - var source_buffer = (GtkSource.Buffer) source_view.buffer; + var source_buffer = (GtkSource..Buffer) source_view.buffer; Utils.action_from_group (MainWindow.ACTION_UNDO, actions).set_enabled (source_buffer.can_undo); Utils.action_from_group (MainWindow.ACTION_REDO, actions).set_enabled (source_buffer.can_redo); Utils.action_from_group (MainWindow.ACTION_REVERT, actions).set_enabled ( @@ -1250,7 +1250,7 @@ namespace Scratch.Services { return; } - var source_buffer = (GtkSource.Buffer)source_view.buffer; + var source_buffer = (GtkSource..Buffer)source_view.buffer; Gtk.TextIter iter; var cursor_pos = source_buffer.cursor_position; diff --git a/src/SymbolPane/SymbolOutline.vala b/src/SymbolPane/SymbolOutline.vala index 65e174d184..41e21a9dac 100644 --- a/src/SymbolPane/SymbolOutline.vala +++ b/src/SymbolPane/SymbolOutline.vala @@ -241,7 +241,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { doc.source_view.style_changed.connect (update_style_scheme); } - protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { + protected void update_style_scheme (GtkSourceStyleScheme style_scheme) { var text_color_data = style_scheme.get_style ("text"); // Default gtksourceview background color is white diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index 23d04cfd0c..297850bb44 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -186,7 +186,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { style_scheme = Scratch.settings.get_string ("style-scheme"); } - var sssm = Gtk.SourceStyleSchemeManager.get_default (); + var sssm = GtkSourceStyleSchemeManager.get_default (); if (style_scheme in sssm.scheme_ids) { var theme = sssm.get_scheme (style_scheme); var text_color_data = theme.get_style ("text"); diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 6589035f67..8ce607205d 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -50,7 +50,7 @@ namespace Scratch.Widgets { private Scratch.Widgets.SourceView? text_view = null; private Gtk.TextBuffer? text_buffer = null; - public Gtk.SourceSearchContext? search_context { get; private set; default = null; } + public GtkSourceSearchContext? search_context { get; private set; default = null; } public signal void search_empty (); @@ -240,7 +240,7 @@ namespace Scratch.Widgets { this.text_view.selection_changed.connect (on_selection_changed); this.text_buffer = text_view.get_buffer (); this.text_buffer.changed.connect (on_text_buffer_changed); - this.search_context = new Gtk.SourceSearchContext (text_buffer as GtkSource.Buffer, null); + this.search_context = new GtkSourceSearchContext (text_buffer as GtkSource.Buffer, null); search_context.settings.wrap_around = cycle_search_button.active; search_context.settings.regex_enabled = regex_search_button.active; search_context.settings.search_text = search_entry.text; diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index 8bd31f4255..ff04e73f2d 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -20,9 +20,9 @@ */ namespace Scratch.Widgets { - public class SourceView : Gtk.SourceView { - public Gtk.SourceLanguageManager manager; - public Gtk.SourceStyleSchemeManager style_scheme_manager; + public class SourceView : GtkSource.View { + public GtkSource.LanguageManager manager; + public GtkSource.StyleSchemeManager style_scheme_manager; public Gtk.CssProvider font_css_provider; public Gtk.TextTag warning_tag; public Gtk.TextTag error_tag; @@ -42,15 +42,15 @@ namespace Scratch.Widgets { private double total_delta = 0; private const double SCROLL_THRESHOLD = 1.0; - public signal void style_changed (Gtk.SourceStyleScheme style); + public signal void style_changed (GtkSource.StyleScheme style); // "selection_changed" signal now only emitted when the selected text changes (position ignored). Listened to by searchbar and highlight word selection plugin public signal void selection_changed (Gtk.TextIter start_iter, Gtk.TextIter end_iter); public signal void deselected (); //lang can be null, in the case of *No highlight style* aka Normal text - public Gtk.SourceLanguage? language { + public GtkSource.Language? language { set { - ((GtkSource.Buffer) buffer).language = value; + ((GtkSource..Buffer) buffer).language = value; } get { return ((GtkSource.Buffer) buffer).language; @@ -77,7 +77,7 @@ namespace Scratch.Widgets { Object ( show_line_numbers: true, smart_backspace: true, - smart_home_end: Gtk.SourceSmartHomeEndType.BEFORE, + smart_home_end: GtkSource.SmartHomeEndType.BEFORE, wrap_mode: Gtk.WrapMode.WORD ); } @@ -90,23 +90,23 @@ namespace Scratch.Widgets { space_drawer.enable_matrix = true; expand = true; - manager = Gtk.SourceLanguageManager.get_default (); - style_scheme_manager = new Gtk.SourceStyleSchemeManager (); + manager = GtkSource.LanguageManager.get_default (); + style_scheme_manager = new GtkSource.StyleSchemeManager (); font_css_provider = new Gtk.CssProvider (); get_style_context ().add_provider (font_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var source_buffer = new GtkSource.Buffer (null); + var source_buffer = new GtkSource..Buffer (null); set_buffer (source_buffer); source_buffer.highlight_syntax = true; source_buffer.mark_set.connect (on_mark_set); highlight_current_line = true; - var draw_spaces_tag = new Gtk.SourceTag ("draw_spaces"); + var draw_spaces_tag = new GtkSource.Tag ("draw_spaces"); draw_spaces_tag.draw_spaces = true; source_buffer.tag_table.add (draw_spaces_tag); - smart_home_end = Gtk.SourceSmartHomeEndType.AFTER; + smart_home_end = GtkSource.SmartHomeEndType.AFTER; // Create common tags warning_tag = new Gtk.TextTag ("warning_bg"); @@ -242,31 +242,31 @@ namespace Scratch.Widgets { show_right_margin = Scratch.settings.get_boolean ("show-right-margin"); right_margin_position = Scratch.settings.get_int ("right-margin-position"); insert_spaces_instead_of_tabs = Scratch.settings.get_boolean ("spaces-instead-of-tabs"); - var source_buffer = (GtkSource.Buffer) buffer; + var source_buffer = (GtkSource..Buffer) buffer; source_buffer.highlight_matching_brackets = Scratch.settings.get_boolean ("highlight-matching-brackets"); space_drawer.enable_matrix = false; switch ((ScratchDrawSpacesState) Scratch.settings.get_enum ("draw-spaces")) { case ScratchDrawSpacesState.ALWAYS: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.SPACE | Gtk.SourceSpaceTypeFlags.TAB + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.SPACE | GtkSource.SpaceTypeFlags.TAB ); break; case ScratchDrawSpacesState.FOR_SELECTION: case ScratchDrawSpacesState.CURRENT: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.NONE + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.NONE ); space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.TRAILING, - Gtk.SourceSpaceTypeFlags.SPACE | Gtk.SourceSpaceTypeFlags.TAB + GtkSource.SpaceLocationFlags.TRAILING, + GtkSource.SpaceTypeFlags.SPACE | GtkSource.SpaceTypeFlags.TAB ); break; default: space_drawer.set_types_for_locations ( - Gtk.SourceSpaceLocationFlags.ALL, - Gtk.SourceSpaceTypeFlags.NONE + GtkSource.SpaceLocationFlags.ALL, + GtkSource.SpaceTypeFlags.NONE ); break; } @@ -507,7 +507,7 @@ namespace Scratch.Widgets { } public void set_text (string text, bool opening = true) { - var source_buffer = (GtkSource.Buffer) buffer; + var source_buffer = (GtkSource..Buffer) buffer; if (opening) { source_buffer.begin_not_undoable_action (); } @@ -562,8 +562,8 @@ namespace Scratch.Widgets { menu.add (sort_item); - if (buffer is GtkSource.Buffer) { - var can_comment = CommentToggler.language_has_comments (((GtkSource.Buffer) buffer).get_language ()); + if (buffer is GtkSource..Buffer) { + var can_comment = CommentToggler.language_has_comments (((GtkSource..Buffer) buffer).get_language ()); var comment_item = new Gtk.MenuItem (); comment_item.sensitive = can_comment; @@ -572,7 +572,7 @@ namespace Scratch.Widgets { MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_COMMENT )); comment_item.activate.connect (() => { - CommentToggler.toggle_comment ((GtkSource.Buffer) buffer); + CommentToggler.toggle_comment ((GtkSource..Buffer) buffer); }); menu.add (comment_item); From 64fb9871bcf8328c1f3ef6c5d3f38262587860d0 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:39:47 +0200 Subject: [PATCH 11/20] fix: search replacement errors --- src/Services/CommentToggler.vala | 6 +++--- src/Services/Document.vala | 22 +++++++++++----------- src/Widgets/DocumentView.vala | 4 ++-- src/Widgets/FormatBar.vala | 6 +++--- src/Widgets/HeaderBar.vala | 2 +- src/Widgets/SearchBar.vala | 4 ++-- src/Widgets/SourceGutterRenderer.vala | 14 +++++++------- src/Widgets/SourceView.vala | 14 +++++++------- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Services/CommentToggler.vala b/src/Services/CommentToggler.vala index 739f5f7d63..12a5fe4b2c 100644 --- a/src/Services/CommentToggler.vala +++ b/src/Services/CommentToggler.vala @@ -24,7 +24,7 @@ public class Scratch.CommentToggler { BLOCK } - private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, + private static CommentType get_comment_tags_for_lang (GtkSource.Language lang, CommentType type, out string? start, out string? end) { @@ -64,7 +64,7 @@ public class Scratch.CommentToggler { return CommentType.NONE; } - public static bool language_has_comments (Gtk.SourceLanguage? lang) { + public static bool language_has_comments (GtkSource.Language? lang) { if (lang == null) { return false; } @@ -81,7 +81,7 @@ public class Scratch.CommentToggler { Gtk.TextIter start, Gtk.TextIter end, uint num_lines, - Gtk.SourceLanguage lang) { + GtkSource.Language lang) { string start_tag, end_tag; var type = get_comment_tags_for_lang (lang, CommentType.BLOCK, out start_tag, out end_tag); diff --git a/src/Services/Document.vala b/src/Services/Document.vala index c2859f11d3..0cdb492de9 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -51,7 +51,7 @@ namespace Scratch.Services { } } - private GtkSource..File source_file; + private GtkSource.File source_file; public GLib.File file { get { return source_file.location; @@ -163,7 +163,7 @@ namespace Scratch.Services { private bool completion_shown = false; private Gtk.ScrolledWindow scroll; - private GtkSource..Map source_map; + private GtkSource.Map source_map; private Gtk.Paned outline_widget_pane; private GLib.Cancellable save_cancellable; @@ -210,8 +210,8 @@ namespace Scratch.Services { expand = true }; scroll.add (source_view); - source_file = new GtkSource..File (); - source_map = new GtkSource..Map (); + source_file = new GtkSource.File (); + source_map = new GtkSource.Map (); outline_widget_pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); if (builder_blocks_font != null && builder_font_map != null) { @@ -386,7 +386,7 @@ namespace Scratch.Services { Gtk.main_iteration (); } - var buffer = new GtkSource..Buffer (null); /* Faster to load into a separate buffer */ + var buffer = new GtkSource.Buffer (null); /* Faster to load into a separate buffer */ load_timout_id = Timeout.add_seconds_full (GLib.Priority.HIGH, 5, () => { if (load_cancellable != null && !load_cancellable.is_cancelled ()) { @@ -413,7 +413,7 @@ namespace Scratch.Services { try { var source_file_loader = new GtkSource.FileLoader (buffer, source_file); yield source_file_loader.load_async (GLib.Priority.LOW, load_cancellable, null); - var source_buffer = source_view.buffer as GtkSource..Buffer; + var source_buffer = source_view.buffer as GtkSource.Buffer; if (source_buffer != null) { source_buffer.begin_not_undoable_action (); source_buffer.text = buffer.text; @@ -802,7 +802,7 @@ namespace Scratch.Services { // Get language name public string get_language_name () { - var source_buffer = (GtkSource..Buffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.name; @@ -813,7 +813,7 @@ namespace Scratch.Services { // Get language id public string get_language_id () { - var source_buffer = (GtkSource..Buffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; var lang = source_buffer.language; if (lang != null) { return lang.id; @@ -898,7 +898,7 @@ namespace Scratch.Services { // If user selects to continue regardless then no further // check made for this document // External changes will be overwritten on next (auto) save - var new_buffer = new GtkSource..Buffer (null); + var new_buffer = new GtkSource.Buffer (null); var source_file_loader = new GtkSource.FileLoader ( new_buffer, source_file @@ -1073,7 +1073,7 @@ namespace Scratch.Services { } // Set Undo/Redo action sensitive property public void check_undoable_actions () { - var source_buffer = (GtkSource..Buffer) source_view.buffer; + var source_buffer = (GtkSource.Buffer) source_view.buffer; Utils.action_from_group (MainWindow.ACTION_UNDO, actions).set_enabled (source_buffer.can_undo); Utils.action_from_group (MainWindow.ACTION_REDO, actions).set_enabled (source_buffer.can_redo); Utils.action_from_group (MainWindow.ACTION_REVERT, actions).set_enabled ( @@ -1250,7 +1250,7 @@ namespace Scratch.Services { return; } - var source_buffer = (GtkSource..Buffer)source_view.buffer; + var source_buffer = (GtkSource.Buffer)source_view.buffer; Gtk.TextIter iter; var cursor_pos = source_buffer.cursor_position; diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index 297850bb44..84e82ee14c 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -186,12 +186,12 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { style_scheme = Scratch.settings.get_string ("style-scheme"); } - var sssm = GtkSourceStyleSchemeManager.get_default (); + var sssm = GtkSource.StyleSchemeManager.get_default (); if (style_scheme in sssm.scheme_ids) { var theme = sssm.get_scheme (style_scheme); var text_color_data = theme.get_style ("text"); - // Default gtksourceview background color is white + // Default GtkSource.view background color is white var color = "#FFFFFF"; if (text_color_data != null) { // If the current style has a background color, use that diff --git a/src/Widgets/FormatBar.vala b/src/Widgets/FormatBar.vala index acf3b3a286..747e8ab2d1 100644 --- a/src/Widgets/FormatBar.vala +++ b/src/Widgets/FormatBar.vala @@ -33,7 +33,7 @@ public class Code.FormatBar : Gtk.Box { private Gtk.Entry goto_entry; private Gtk.ListBox lang_selection_listbox; private Gtk.SearchEntry lang_selection_filter; - private Gtk.SourceLanguageManager manager; + private GtkSourceLanguageManager manager; private LangEntry normal_entry; private unowned Scratch.Services.Document? doc = null; @@ -41,7 +41,7 @@ public class Code.FormatBar : Gtk.Box { construct { get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - manager = Gtk.SourceLanguageManager.get_default (); + manager = GtkSourceLanguageManager.get_default (); tab_menubutton = new FormatButton () { icon = new ThemedIcon ("format-indent-more-symbolic") @@ -104,7 +104,7 @@ public class Code.FormatBar : Gtk.Box { unowned string[]? ids = manager.get_language_ids (); unowned SList group = null; foreach (unowned string id in ids) { - weak Gtk.SourceLanguage lang = manager.get_language (id); + weak GtkSourceLanguage lang = manager.get_language (id); var entry = new LangEntry (id, lang.name, group); group = entry.get_radio_group (); lang_selection_listbox.add (entry); diff --git a/src/Widgets/HeaderBar.vala b/src/Widgets/HeaderBar.vala index dab7781a1b..4f52a0e96f 100644 --- a/src/Widgets/HeaderBar.vala +++ b/src/Widgets/HeaderBar.vala @@ -326,7 +326,7 @@ public class Scratch.HeaderBar : Adw.HeaderBar { string background = "#FFF"; string foreground = "#333"; - var sssm = Gtk.SourceStyleSchemeManager.get_default (); + var sssm = GtkSourceStyleSchemeManager.get_default (); if (style_id in sssm.scheme_ids) { var scheme = sssm.get_scheme (style_id); color_button.tooltip_text = scheme.name; diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 8ce607205d..645ed19999 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -50,7 +50,7 @@ namespace Scratch.Widgets { private Scratch.Widgets.SourceView? text_view = null; private Gtk.TextBuffer? text_buffer = null; - public GtkSourceSearchContext? search_context { get; private set; default = null; } + public GtkSource.SearchContext? search_context { get; private set; default = null; } public signal void search_empty (); @@ -240,7 +240,7 @@ namespace Scratch.Widgets { this.text_view.selection_changed.connect (on_selection_changed); this.text_buffer = text_view.get_buffer (); this.text_buffer.changed.connect (on_text_buffer_changed); - this.search_context = new GtkSourceSearchContext (text_buffer as GtkSource.Buffer, null); + this.search_context = new GtkSource.SearchContext (text_buffer as GtkSource.Buffer, null); search_context.settings.wrap_around = cycle_search_button.active; search_context.settings.regex_enabled = regex_search_button.active; search_context.settings.search_text = search_entry.text; diff --git a/src/Widgets/SourceGutterRenderer.vala b/src/Widgets/SourceGutterRenderer.vala index 19b6683c0b..b1b37d1722 100644 --- a/src/Widgets/SourceGutterRenderer.vala +++ b/src/Widgets/SourceGutterRenderer.vala @@ -1,4 +1,4 @@ -public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { +public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { // These style_ids must be present in the "classic" SourceStyleScheme (or allowed Code SourceStyleSchemes) to avoid terminal spam) public const string ADDED_STYLE_ID = "diff:added-line"; public const string REMOVED_STYLE_ID = "diff:removed-line"; @@ -6,14 +6,14 @@ public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { public const string REPLACES_DELETED_STYLE_ID = "diff:special-case"; public const string NONE_STYLE_ID = "background-pattern"; - private static Gtk.SourceStyleScheme? fallback_scheme; + private static GtkSourceStyleScheme? fallback_scheme; public Gee.HashMap line_status_map; public Gee.HashMap status_color_map; public FolderManager.ProjectFolderItem? project { get; set; default = null; } static construct { - fallback_scheme = Gtk.SourceStyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists + fallback_scheme = GtkSourceStyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists } construct { @@ -24,7 +24,7 @@ public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { set_visible (true); } - public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { + public void set_style_scheme (GtkSourceStyleScheme? scheme) { update_status_color_map (Services.VCStatus.ADDED, scheme, ADDED_STYLE_ID); update_status_color_map (Services.VCStatus.REMOVED, scheme, REMOVED_STYLE_ID); update_status_color_map (Services.VCStatus.CHANGED, scheme, CHANGED_STYLE_ID); @@ -33,11 +33,11 @@ public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { } private void update_status_color_map (Services.VCStatus status, - Gtk.SourceStyleScheme? scheme, + GtkSourceStyleScheme? scheme, string style_id, bool use_foreground = true) { - Gtk.SourceStyle style = null; + GtkSourceStyle style = null; if (scheme != null) { style = scheme.get_style (style_id); if (style != null) { @@ -61,7 +61,7 @@ public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { Gdk.Rectangle area, Gtk.TextIter start, Gtk.TextIter end, - Gtk.SourceGutterRendererState state) { + GtkSourceGutterRendererState state) { //Gutter and diff lines numbers start at one, source lines start at 0 var gutter_line_no = start.get_line () + 1; diff --git a/src/Widgets/SourceView.vala b/src/Widgets/SourceView.vala index ff04e73f2d..cdb03c44ff 100644 --- a/src/Widgets/SourceView.vala +++ b/src/Widgets/SourceView.vala @@ -50,7 +50,7 @@ namespace Scratch.Widgets { //lang can be null, in the case of *No highlight style* aka Normal text public GtkSource.Language? language { set { - ((GtkSource..Buffer) buffer).language = value; + ((GtkSource.Buffer) buffer).language = value; } get { return ((GtkSource.Buffer) buffer).language; @@ -96,7 +96,7 @@ namespace Scratch.Widgets { font_css_provider = new Gtk.CssProvider (); get_style_context ().add_provider (font_css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - var source_buffer = new GtkSource..Buffer (null); + var source_buffer = new GtkSource.Buffer (null); set_buffer (source_buffer); source_buffer.highlight_syntax = true; source_buffer.mark_set.connect (on_mark_set); @@ -242,7 +242,7 @@ namespace Scratch.Widgets { show_right_margin = Scratch.settings.get_boolean ("show-right-margin"); right_margin_position = Scratch.settings.get_int ("right-margin-position"); insert_spaces_instead_of_tabs = Scratch.settings.get_boolean ("spaces-instead-of-tabs"); - var source_buffer = (GtkSource..Buffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; source_buffer.highlight_matching_brackets = Scratch.settings.get_boolean ("highlight-matching-brackets"); space_drawer.enable_matrix = false; switch ((ScratchDrawSpacesState) Scratch.settings.get_enum ("draw-spaces")) { @@ -507,7 +507,7 @@ namespace Scratch.Widgets { } public void set_text (string text, bool opening = true) { - var source_buffer = (GtkSource..Buffer) buffer; + var source_buffer = (GtkSource.Buffer) buffer; if (opening) { source_buffer.begin_not_undoable_action (); } @@ -562,8 +562,8 @@ namespace Scratch.Widgets { menu.add (sort_item); - if (buffer is GtkSource..Buffer) { - var can_comment = CommentToggler.language_has_comments (((GtkSource..Buffer) buffer).get_language ()); + if (buffer is GtkSource.Buffer) { + var can_comment = CommentToggler.language_has_comments (((GtkSource.Buffer) buffer).get_language ()); var comment_item = new Gtk.MenuItem (); comment_item.sensitive = can_comment; @@ -572,7 +572,7 @@ namespace Scratch.Widgets { MainWindow.ACTION_PREFIX + MainWindow.ACTION_TOGGLE_COMMENT )); comment_item.activate.connect (() => { - CommentToggler.toggle_comment ((GtkSource..Buffer) buffer); + CommentToggler.toggle_comment ((GtkSource.Buffer) buffer); }); menu.add (comment_item); From 8d1f974309b818d28c130a867b36ca2f89a8c533 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:48:15 +0200 Subject: [PATCH 12/20] fix: GtkSource.GutterRendererState deprecated and missing GtkSource. search errors --- src/SymbolPane/SymbolOutline.vala | 2 +- src/Widgets/FormatBar.vala | 6 +++--- src/Widgets/SourceGutterRenderer.vala | 17 ++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/SymbolPane/SymbolOutline.vala b/src/SymbolPane/SymbolOutline.vala index 41e21a9dac..b6fc4b77ce 100644 --- a/src/SymbolPane/SymbolOutline.vala +++ b/src/SymbolPane/SymbolOutline.vala @@ -241,7 +241,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { doc.source_view.style_changed.connect (update_style_scheme); } - protected void update_style_scheme (GtkSourceStyleScheme style_scheme) { + protected void update_style_scheme (GtkSource.StyleScheme style_scheme) { var text_color_data = style_scheme.get_style ("text"); // Default gtksourceview background color is white diff --git a/src/Widgets/FormatBar.vala b/src/Widgets/FormatBar.vala index 747e8ab2d1..8f6f8228c3 100644 --- a/src/Widgets/FormatBar.vala +++ b/src/Widgets/FormatBar.vala @@ -33,7 +33,7 @@ public class Code.FormatBar : Gtk.Box { private Gtk.Entry goto_entry; private Gtk.ListBox lang_selection_listbox; private Gtk.SearchEntry lang_selection_filter; - private GtkSourceLanguageManager manager; + private GtkSource.LanguageManager manager; private LangEntry normal_entry; private unowned Scratch.Services.Document? doc = null; @@ -41,7 +41,7 @@ public class Code.FormatBar : Gtk.Box { construct { get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); - manager = GtkSourceLanguageManager.get_default (); + manager = GtkSource.LanguageManager.get_default (); tab_menubutton = new FormatButton () { icon = new ThemedIcon ("format-indent-more-symbolic") @@ -104,7 +104,7 @@ public class Code.FormatBar : Gtk.Box { unowned string[]? ids = manager.get_language_ids (); unowned SList group = null; foreach (unowned string id in ids) { - weak GtkSourceLanguage lang = manager.get_language (id); + weak GtkSource.Language lang = manager.get_language (id); var entry = new LangEntry (id, lang.name, group); group = entry.get_radio_group (); lang_selection_listbox.add (entry); diff --git a/src/Widgets/SourceGutterRenderer.vala b/src/Widgets/SourceGutterRenderer.vala index b1b37d1722..958e14e131 100644 --- a/src/Widgets/SourceGutterRenderer.vala +++ b/src/Widgets/SourceGutterRenderer.vala @@ -1,4 +1,4 @@ -public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { +public class Scratch.Widgets.SourceGutterRenderer : GtkSource.GutterRenderer { // These style_ids must be present in the "classic" SourceStyleScheme (or allowed Code SourceStyleSchemes) to avoid terminal spam) public const string ADDED_STYLE_ID = "diff:added-line"; public const string REMOVED_STYLE_ID = "diff:removed-line"; @@ -6,14 +6,14 @@ public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { public const string REPLACES_DELETED_STYLE_ID = "diff:special-case"; public const string NONE_STYLE_ID = "background-pattern"; - private static GtkSourceStyleScheme? fallback_scheme; + private static GtkSource.StyleScheme? fallback_scheme; public Gee.HashMap line_status_map; public Gee.HashMap status_color_map; public FolderManager.ProjectFolderItem? project { get; set; default = null; } static construct { - fallback_scheme = GtkSourceStyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists + fallback_scheme = GtkSource.StyleSchemeManager.get_default ().get_scheme ("classic"); // We can assume this always exists } construct { @@ -24,7 +24,7 @@ public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { set_visible (true); } - public void set_style_scheme (GtkSourceStyleScheme? scheme) { + public void set_style_scheme (GtkSource.StyleScheme? scheme) { update_status_color_map (Services.VCStatus.ADDED, scheme, ADDED_STYLE_ID); update_status_color_map (Services.VCStatus.REMOVED, scheme, REMOVED_STYLE_ID); update_status_color_map (Services.VCStatus.CHANGED, scheme, CHANGED_STYLE_ID); @@ -33,11 +33,11 @@ public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { } private void update_status_color_map (Services.VCStatus status, - GtkSourceStyleScheme? scheme, + GtkSource.StyleScheme? scheme, string style_id, bool use_foreground = true) { - GtkSourceStyle style = null; + GtkSource.Style style = null; if (scheme != null) { style = scheme.get_style (style_id); if (style != null) { @@ -60,8 +60,7 @@ public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { Gdk.Rectangle bg, Gdk.Rectangle area, Gtk.TextIter start, - Gtk.TextIter end, - GtkSourceGutterRendererState state) { + Gtk.TextIter end) { //Gutter and diff lines numbers start at one, source lines start at 0 var gutter_line_no = start.get_line () + 1; @@ -71,6 +70,6 @@ public class Scratch.Widgets.SourceGutterRenderer : GtkSourceGutterRenderer { set_background (status_color_map [Services.VCStatus.NONE]); } - base.draw (cr, bg, area, start, end, state); + base.draw (cr, bg, area, start, end); } } From bcca47e64d76b953793376f2be2b07585e59fa92 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:49:39 +0200 Subject: [PATCH 13/20] rm: accidental triage.txt file --- triage.txt | 699 ----------------------------------------------------- 1 file changed, 699 deletions(-) delete mode 100644 triage.txt diff --git a/triage.txt b/triage.txt deleted file mode 100644 index f3b7dc9f58..0000000000 --- a/triage.txt +++ /dev/null @@ -1,699 +0,0 @@ - - - - - GTK SOURCE VIEW - - - - - - -../src/Services/Document.vala:54.17-54.30: error: The type name `Gtk.SourceFile' could not be found - 54 | private Gtk.SourceFile source_file; - | ^~~~~~~~~~~~~~ -../src/Services/Document.vala:166.17-166.29: error: The type name `Gtk.SourceMap' could not be found - 166 | private Gtk.SourceMap source_map; - | ^~~~~~~~~~~~~ -../src/Services/Document.vala:416.59-416.74: error: The type name `Gtk.SourceBuffer' could not be found - 416 | var source_buffer = source_view.buffer as Gtk.SourceBuffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:596.63-596.78: error: The type name `Gtk.SourceBuffer' could not be found - 596 | var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:805.34-805.49: error: The type name `Gtk.SourceBuffer' could not be found - 805 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:816.34-816.49: error: The type name `Gtk.SourceBuffer' could not be found - 816 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:1076.34-1076.49: error: The type name `Gtk.SourceBuffer' could not be found - 1076 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:1253.34-1253.49: error: The type name `Gtk.SourceBuffer' could not be found - 1253 | var source_buffer = (Gtk.SourceBuffer)source_view.buffer; - -../src/SymbolPane/SymbolOutline.vala:240.32-240.47: error: The type name `Gtk.SourceBuffer' could not be found - 240 | update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); - | ^~~~~~~~~~~~~~~~ -../src/SymbolPane/SymbolOutline.vala:244.41-244.61: error: The type name `Gtk.SourceStyleScheme' could not be found - 244 | protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { - | ../src/Widgets/SourceGutterRenderer.vala:1.53-1.76: error: The type name `Gtk.SourceGutterRenderer' could not be found - 1 | public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:9.20-9.41: error: The type name `Gtk.SourceStyleScheme' could not be found - 9 | private static Gtk.SourceStyleScheme? fallback_scheme; - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:27.35-27.56: error: The type name `Gtk.SourceStyleScheme' could not be found - 27 | public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:36.43-36.64: error: The type name `Gtk.SourceStyleScheme' could not be found - 36 | Gtk.SourceStyleScheme? scheme, - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:40.9-40.23: error: The type name `Gtk.SourceStyle' could not be found - 40 | Gtk.SourceStyle style = null; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:64.32-64.60: error: The type name `Gtk.SourceGutterRendererState' could not be found - 64 | Gtk.SourceGutterRendererState state) { - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:243.79-243.94: error: The type name `Gtk.SourceBuffer' could not be found - 243 | this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); - | ^~~~~~~~~~~~~~~~ - ../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:23.31-23.44: error: The type name `Gtk.SourceView' could not be found - 23 | public class SourceView : Gtk.SourceView { - | ^~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:24.16-24.40: error: The type name `Gtk.SourceLanguageManager' could not be found - 24 | public Gtk.SourceLanguageManager manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:25.16-25.43: error: The type name `Gtk.SourceStyleSchemeManager' could not be found - 25 | public Gtk.SourceStyleSchemeManager style_scheme_manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:245.34-245.49: error: The type name `Gtk.SourceBuffer' could not be found - 245 | var source_buffer = (Gtk.SourceBuffer) buffer; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:510.34-510.49: error: The type name `Gtk.SourceBuffer' could not be found - 510 | var source_buffer = (Gtk.SourceBuffer) buffer; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:565.27-565.42: error: The type name `Gtk.SourceBuffer' could not be found - 565 | if (buffer is Gtk.SourceBuffer) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:566.75-566.90: error: The type name `Gtk.SourceBuffer' could not be found - 566 | var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ()); - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:575.53-575.68: error: The type name `Gtk.SourceBuffer' could not be found - 575 | CommentToggler.toggle_comment ((Gtk.SourceBuffer) buffer); - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:56.26-56.41: error: The type name `Gtk.SourceBuffer' could not be found - 56 | return ((Gtk.SourceBuffer) buffer).language; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:53.19-53.34: error: The type name `Gtk.SourceBuffer' could not be found - 53 | ((Gtk.SourceBuffer) buffer).language = value; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:45.43-45.63: error: The type name `Gtk.SourceStyleScheme' could not be found - 45 | public signal void style_changed (Gtk.SourceStyleScheme style); - | ^~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~ -../src/MainWindow.vala:1321.27-1321.42: error: The type name `Gtk.SourceBuffer' could not be found - 1321 | if (buffer is Gtk.SourceBuffer) { - | ^~~~~~~~~~~~~~~~ -../src/MainWindow.vala:1322.58-1322.73: error: The type name `Gtk.SourceBuffer' could not be found - 1322 | CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:27.59-27.76: error: The type name `Gtk.SourceLanguage' could not be found - 27 | private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, - | ^~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:67.47-67.65: error: The type name `Gtk.SourceLanguage' could not be found - 67 | public static bool language_has_comments (Gtk.SourceLanguage? lang) { - | ^~~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:80.57-80.72: error: The type name `Gtk.SourceBuffer' could not be found - 80 | private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:84.57-84.74: error: The type name `Gtk.SourceLanguage' could not be found - 84 | Gtk.SourceLanguage lang) { - | ^~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:121.42-121.57: error: The type name `Gtk.SourceBuffer' could not be found - 121 | private static void remove_comments (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:202.39-202.54: error: The type name `Gtk.SourceBuffer' could not be found - 202 | private static void add_comments (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:300.40-300.56: error: The type name `Gtk.SourceBuffer' could not be found - 300 | public static void toggle_comment (Gtk.SourceBuffer? buffer) { - | ^~~~~~~~~~~~~~~~~ -../src/Services/Document.vala:54.17-54.30: error: The type name `Gtk.SourceFile' could not be found - 54 | private Gtk.SourceFile source_file; - | ^~~~~~~~~~~~~~ -../src/Services/Document.vala:166.17-166.29: error: The type name `Gtk.SourceMap' could not be found - 166 | private Gtk.SourceMap source_map; - | ^~~~~~~~~~~~~ -../src/Services/Document.vala:416.59-416.74: error: The type name `Gtk.SourceBuffer' could not be found - 416 | var source_buffer = source_view.buffer as Gtk.SourceBuffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:596.63-596.78: error: The type name `Gtk.SourceBuffer' could not be found - 596 | var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:805.34-805.49: error: The type name `Gtk.SourceBuffer' could not be found - 805 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:816.34-816.49: error: The type name `Gtk.SourceBuffer' could not be found - 816 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:1076.34-1076.49: error: The type name `Gtk.SourceBuffer' could not be found - 1076 | var source_buffer = (Gtk.SourceBuffer) source_view.buffer; - | ^~~~~~~~~~~~~~~~ -../src/Services/Document.vala:1253.34-1253.49: error: The type name `Gtk.SourceBuffer' could not be found - 1253 | var source_buffer = (Gtk.SourceBuffer)source_view.buffer; - | ../src/SymbolPane/SymbolOutline.vala:240.32-240.47: error: The type name `Gtk.SourceBuffer' could not be found - 240 | update_style_scheme (((Gtk.SourceBuffer)(doc.source_view.buffer)).style_scheme); - | ^~~~~~~~~~~~~~~~ -../src/SymbolPane/SymbolOutline.vala:244.41-244.61: error: The type name `Gtk.SourceStyleScheme' could not be found - 244 | protected void update_style_scheme (Gtk.SourceStyleScheme style_scheme) { - | ^~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:1.53-1.76: error: The type name `Gtk.SourceGutterRenderer' could not be found - 1 | public class Scratch.Widgets.SourceGutterRenderer : Gtk.SourceGutterRenderer { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:9.20-9.41: error: The type name `Gtk.SourceStyleScheme' could not be found - 9 | private static Gtk.SourceStyleScheme? fallback_scheme; - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:27.35-27.56: error: The type name `Gtk.SourceStyleScheme' could not be found - 27 | public void set_style_scheme (Gtk.SourceStyleScheme? scheme) { - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:36.43-36.64: error: The type name `Gtk.SourceStyleScheme' could not be found - 36 | Gtk.SourceStyleScheme? scheme, - | ^~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:40.9-40.23: error: The type name `Gtk.SourceStyle' could not be found - 40 | Gtk.SourceStyle style = null; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceGutterRenderer.vala:64.32-64.60: error: The type name `Gtk.SourceGutterRendererState' could not be found - 64 | Gtk.SourceGutterRendererState state) { - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:243.79-243.94: error: The type name `Gtk.SourceBuffer' could not be found - 243 | this.search_context = new Gtk.SourceSearchContext (text_buffer as Gtk.SourceBuffer, null); - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:53.16-53.39: error: The type name `Gtk.SourceSearchContext' could not be found - 53 | public Gtk.SourceSearchContext? search_context { get; private set; default = null; } - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:23.31-23.44: error: The type name `Gtk.SourceView' could not be found - 23 | public class SourceView : Gtk.SourceView { - | ^~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:24.16-24.40: error: The type name `Gtk.SourceLanguageManager' could not be found - 24 | public Gtk.SourceLanguageManager manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:25.16-25.43: error: The type name `Gtk.SourceStyleSchemeManager' could not be found - 25 | public Gtk.SourceStyleSchemeManager style_scheme_manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:245.34-245.49: error: The type name `Gtk.SourceBuffer' could not be found - 245 | var source_buffer = (Gtk.SourceBuffer) buffer; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:510.34-510.49: error: The type name `Gtk.SourceBuffer' could not be found - 510 | var source_buffer = (Gtk.SourceBuffer) buffer; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:565.27-565.42: error: The type name `Gtk.SourceBuffer' could not be found - 565 | if (buffer is Gtk.SourceBuffer) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:566.75-566.90: error: The type name `Gtk.SourceBuffer' could not be found - 566 | var can_comment = CommentToggler.language_has_comments (((Gtk.SourceBuffer) buffer).get_language ()); - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:575.53-575.68: error: The type name `Gtk.SourceBuffer' could not be found - 575 | CommentToggler.toggle_comment ((Gtk.SourceBuffer) buffer); - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:56.26-56.41: error: The type name `Gtk.SourceBuffer' could not be found - 56 | return ((Gtk.SourceBuffer) buffer).language; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:51.16-51.34: error: The type name `Gtk.SourceLanguage' could not be found - 51 | public Gtk.SourceLanguage? language { - | ^~~~~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:53.19-53.34: error: The type name `Gtk.SourceBuffer' could not be found - 53 | ((Gtk.SourceBuffer) buffer).language = value; - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceView.vala:45.43-45.63: error: The type name `Gtk.SourceStyleScheme' could not be found - 45 | public signal void style_changed (Gtk.SourceStyleScheme style); - | ^~~~~~~~~~~~~~~~~~~~~ - - - - - - - - - PEAS LIBRARY - - - - - - - | ^~~~~~~~~~~~~~~~ -../src/Services/PluginManager.vala:55.9-55.12: error: The symbol `Peas' could not be found - 55 | Peas.Engine engine; - | ^~~~ -../src/Services/PluginManager.vala:56.9-56.12: error: The symbol `Peas' could not be found - 56 | Peas.ExtensionSet exts; - | ^~~~ -../src/Services/PluginManager.vala:89.59-89.62: error: The symbol `Peas' could not be found - 89 | exts = new Peas.ExtensionSet (engine, typeof (Peas.Activatable), "object", plugin_iface, null); - | ^~~~ -../src/Services/PluginManager.vala:92.19-92.22: error: The symbol `Peas' could not be found - 92 | ((Peas.Activatable)ext).activate (); - | ^~~~ -../src/Services/PluginManager.vala:97.19-97.22: error: The symbol `Peas' could not be found - 97 | ((Peas.Activatable)ext).deactivate (); - | ^~~~ -../src/Services/PluginManager.vala:129.36-129.39: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:129.59-129.62: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:129.81-129.84: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:130.15-130.18: error: The symbol `Peas' could not be found - 130 | ((Peas.Activatable)extension).activate (); - | ^~~~ -../src/Services/PluginManager.vala:72.45-72.48: error: The symbol `Peas' could not be found - 72 | public signal void extension_added (Peas.PluginInfo info); - | ^~~~ -../src/Services/PluginManager.vala:73.47-73.50: error: The symbol `Peas' could not be found - 73 | public signal void extension_removed (Peas.PluginInfo info); - | ../src/Services/PluginManager.vala:55.9-55.12: error: The symbol `Peas' could not be found - 55 | Peas.Engine engine; - | ^~~~ -../src/Services/PluginManager.vala:56.9-56.12: error: The symbol `Peas' could not be found - 56 | Peas.ExtensionSet exts; - | ^~~~ -../src/Services/PluginManager.vala:89.59-89.62: error: The symbol `Peas' could not be found - 89 | exts = new Peas.ExtensionSet (engine, typeof (Peas.Activatable), "object", plugin_iface, null); - | ^~~~ -../src/Services/PluginManager.vala:92.19-92.22: error: The symbol `Peas' could not be found - 92 | ((Peas.Activatable)ext).activate (); - | ^~~~ -../src/Services/PluginManager.vala:97.19-97.22: error: The symbol `Peas' could not be found - 97 | ((Peas.Activatable)ext).deactivate (); - | ^~~~ -../src/Services/PluginManager.vala:129.36-129.39: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:129.59-129.62: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:129.81-129.84: error: The symbol `Peas' could not be found - 129 | void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - | ^~~~ -../src/Services/PluginManager.vala:130.15-130.18: error: The symbol `Peas' could not be found - 130 | ((Peas.Activatable)extension).activate (); - | ^~~~ -../src/Services/PluginManager.vala:72.45-72.48: error: The symbol `Peas' could not be found - 72 | public signal void extension_added (Peas.PluginInfo info); - | ^~~~ -../src/Services/PluginManager.vala:73.47-73.50: error: The symbol `Peas' could not be found - 73 | public signal void extension_removed (Peas.PluginInfo info); - | ^~~~ ^~~~ - - - - - - GTK DRAG AND DROP OR WIDGETS - - - - - - -../src/Widgets/DocumentView.vala:650.33-650.47: error: The type name `Gdk.DragContext' could not be found - 650 | Gdk.DragContext ctx, - | ^~~~~~~~~~~~~~~ -../src/Widgets/DocumentView.vala:653.33-653.49: error: The type name `Gtk.SelectionData' could not be found - 653 | Gtk.SelectionData sel, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/DocumentView.vala:168.9-168.23: error: The type name `Gtk.TargetEntry' could not be found - 168 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:343.50-343.63: error: The type name `Gdk.EventFocus' could not be found - 343 | private bool on_search_entry_focused_in (Gdk.EventFocus event) { - | ^~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:480.49-480.60: error: The type name `Gdk.EventKey' could not be found - 480 | private bool on_search_entry_key_press (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:511.50-511.61: error: The type name `Gdk.EventKey' could not be found - 511 | private bool on_replace_entry_key_press (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/MainWindow.vala:53.16-53.28: error: The type name `Gtk.Clipboard' could not be found - 53 | public Gtk.Clipboard clipboard; - | ^~~~~~~~~~~~~ -../src/MainWindow.vala:456.13-456.27: error: The type name `Gtk.TargetEntry' could not be found - 456 | Gtk.TargetEntry target = {"text/uri-list", 0, 0}; - | ^~~~~~~~~~~~~~~ -../src/MainWindow.vala:724.47-724.58: error: The type name `Gdk.EventAny' could not be found - 724 | protected override bool delete_event (Gdk.EventAny event) { - | ^~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2767.37-2767.51: error: The type name `Gtk.TargetEntry' could not be found - 2767 | public void enable_drag_source (Gtk.TargetEntry[] src_entries) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2794.35-2794.49: error: The type name `Gtk.TargetEntry' could not be found - 2794 | public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1206.60-1206.76: error: The type name `Gtk.SelectionData' could not be found - 1206 | public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1310.59-1310.75: error: The type name `Gtk.SelectionData' could not be found - 1310 | public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1421.55-1421.71: error: The type name `Gtk.SelectionData' could not be found - 1421 | public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1730.43-1730.57: error: The type name `Gdk.DragContext' could not be found - 1730 | public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1795.13-1795.27: error: The type name `Gdk.DragContext' could not be found - 1795 | Gdk.DragContext context, - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1798.13-1798.29: error: The type name `Gtk.SelectionData' could not be found - 1798 | Gtk.SelectionData selection_data, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1853.44-1853.58: error: The type name `Gtk.TargetEntry' could not be found - 1853 | public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1861.42-1861.56: error: The type name `Gtk.TargetEntry' could not be found - 1861 | public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1918.24-1918.38: error: The type name `Gtk.TargetEntry' could not be found - 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1918.67-1918.81: error: The type name `Gtk.TargetEntry' could not be found - 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1919.19-1919.33: error: The type name `Gtk.TargetEntry' could not be found - 1919 | const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1925.31-1925.45: error: The type name `Gtk.TargetEntry' could not be found - 1925 | var entries = new Gtk.TargetEntry[0]; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2235.49-2235.60: error: The type name `Gdk.EventKey' could not be found - 2235 | public override bool key_release_event (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2250.52-2250.66: error: The type name `Gdk.EventButton' could not be found - 2250 | public override bool button_release_event (Gdk.EventButton event) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2271.50-2271.64: error: The type name `Gdk.EventButton' could not be found - 2271 | public override bool button_press_event (Gdk.EventButton event) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2396.54-2396.69: error: The type name `Gdk.EventButton' could not be found - 2396 | private bool popup_context_menu (Item? item, Gdk.EventButton? event) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:93.50-93.66: error: The type name `Gtk.SelectionData' could not be found - 93 | public abstract void prepare_selection_data (Gtk.SelectionData selection_data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:110.46-110.60: error: The type name `Gdk.DragContext' could not be found - 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:110.71-110.87: error: The type name `Gtk.SelectionData' could not be found - 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:122.51-122.65: error: The type name `Gdk.DragContext' could not be found - 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:122.76-122.92: error: The type name `Gtk.SelectionData' could not be found - 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found - 23 | public unowned Gtk.RadioButton? group_source { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found - 23 | public unowned Gtk.RadioButton? group_source { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:193.49-193.64: error: The type name `Gtk.RadioButton' could not be found - 193 | public ProjectRow (string project_path, Gtk.RadioButton? group_source ) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:34.13-34.37: error: The type name `Gtk.SourceLanguageManager' could not be found - 34 | private Gtk.SourceLanguageManager manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:103.23-103.37: error: The type name `Gtk.RadioButton' could not be found - 103 | unowned SList group = null; - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:105.13-105.35: error: The type name `Gtk.SourceLanguage' could not be found - 105 | weak Gtk.SourceLanguage lang = manager.get_language (id); - | ^~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:378.17-378.31: error: The type name `Gtk.RadioButton' could not be found - 378 | private Gtk.RadioButton lang_radio; - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:379.68-379.82: error: The type name `Gtk.RadioButton' could not be found - 379 | public LangEntry (string? lang_id, string lang_name, SList group) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:400.30-400.44: error: The type name `Gtk.RadioButton' could not be found - 400 | public unowned SList get_radio_group () { - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:120.33-120.47: error: The type name `Gdk.DragContext' could not be found - 120 | Gdk.DragContext ctx, - | ^~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:123.33-123.49: error: The type name `Gtk.SelectionData' could not be found - 123 | Gtk.SelectionData sel, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:114.9-114.23: error: The type name `Gtk.TargetEntry' could not be found - 114 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - | ^~~~~~~~~~~~~~~ -../src/Widgets/Terminal.vala:22.13-22.25: error: The type name `Gtk.Clipboard' could not be found - 22 | private Gtk.Clipboard current_clipboard; - | ^~~~~~~~~~~~~ -../src/Widgets/DocumentView.vala:650.33-650.47: error: The type name `Gdk.DragContext' could not be found - 650 | Gdk.DragContext ctx, - | ^~~~~~~~~~~~~~~ -../src/Widgets/DocumentView.vala:653.33-653.49: error: The type name `Gtk.SelectionData' could not be found - 653 | Gtk.SelectionData sel, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/DocumentView.vala:168.9-168.23: error: The type name `Gtk.TargetEntry' could not be found - 168 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:343.50-343.63: error: The type name `Gdk.EventFocus' could not be found - 343 | private bool on_search_entry_focused_in (Gdk.EventFocus event) { - | ^~~~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:480.49-480.60: error: The type name `Gdk.EventKey' could not be found - 480 | private bool on_search_entry_key_press (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/Widgets/SearchBar.vala:511.50-511.61: error: The type name `Gdk.EventKey' could not be found - 511 | private bool on_replace_entry_key_press (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/MainWindow.vala:53.16-53.28: error: The type name `Gtk.Clipboard' could not be found - 53 | public Gtk.Clipboard clipboard; - | ^~~~~~~~~~~~~ -../src/MainWindow.vala:456.13-456.27: error: The type name `Gtk.TargetEntry' could not be found - 456 | Gtk.TargetEntry target = {"text/uri-list", 0, 0}; - | ^~~~~~~~~~~~~~~ -../src/MainWindow.vala:724.47-724.58: error: The type name `Gdk.EventAny' could not be found - 724 | protected override bool delete_event (Gdk.EventAny event) { - | ^~~~~~~~~~~~ -../src/MainWindow.vala:1321.27-1321.42: error: The type name `Gtk.SourceBuffer' could not be found - 1321 | if (buffer is Gtk.SourceBuffer) { - | ^~~~~~~~~~~~~~~~ -../src/MainWindow.vala:1322.58-1322.73: error: The type name `Gtk.SourceBuffer' could not be found - 1322 | CommentToggler.toggle_comment (buffer as Gtk.SourceBuffer); - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:27.59-27.76: error: The type name `Gtk.SourceLanguage' could not be found - 27 | private static CommentType get_comment_tags_for_lang (Gtk.SourceLanguage lang, - | ^~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:67.47-67.65: error: The type name `Gtk.SourceLanguage' could not be found - 67 | public static bool language_has_comments (Gtk.SourceLanguage? lang) { - | ^~~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:80.57-80.72: error: The type name `Gtk.SourceBuffer' could not be found - 80 | private static CommentType lines_already_commented (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:84.57-84.74: error: The type name `Gtk.SourceLanguage' could not be found - 84 | Gtk.SourceLanguage lang) { - | ^~~~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:121.42-121.57: error: The type name `Gtk.SourceBuffer' could not be found - 121 | private static void remove_comments (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:202.39-202.54: error: The type name `Gtk.SourceBuffer' could not be found - 202 | private static void add_comments (Gtk.SourceBuffer buffer, - | ^~~~~~~~~~~~~~~~ -../src/Services/CommentToggler.vala:300.40-300.56: error: The type name `Gtk.SourceBuffer' could not be found - 300 | public static void toggle_comment (Gtk.SourceBuffer? buffer) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2767.37-2767.51: error: The type name `Gtk.TargetEntry' could not be found - 2767 | public void enable_drag_source (Gtk.TargetEntry[] src_entries) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2794.35-2794.49: error: The type name `Gtk.TargetEntry' could not be found - 2794 | public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1206.60-1206.76: error: The type name `Gtk.SelectionData' could not be found - 1206 | public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1310.59-1310.75: error: The type name `Gtk.SelectionData' could not be found - 1310 | public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1421.55-1421.71: error: The type name `Gtk.SelectionData' could not be found - 1421 | public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1730.43-1730.57: error: The type name `Gdk.DragContext' could not be found - 1730 | public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1795.13-1795.27: error: The type name `Gdk.DragContext' could not be found - 1795 | Gdk.DragContext context, - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1798.13-1798.29: error: The type name `Gtk.SelectionData' could not be found - 1798 | Gtk.SelectionData selection_data, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1853.44-1853.58: error: The type name `Gtk.TargetEntry' could not be found - 1853 | public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1861.42-1861.56: error: The type name `Gtk.TargetEntry' could not be found - 1861 | public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1918.24-1918.38: error: The type name `Gtk.TargetEntry' could not be found - 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1918.67-1918.81: error: The type name `Gtk.TargetEntry' could not be found - 1918 | private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1919.19-1919.33: error: The type name `Gtk.TargetEntry' could not be found - 1919 | const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:1925.31-1925.45: error: The type name `Gtk.TargetEntry' could not be found - 1925 | var entries = new Gtk.TargetEntry[0]; - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2235.49-2235.60: error: The type name `Gdk.EventKey' could not be found - 2235 | public override bool key_release_event (Gdk.EventKey event) { - | ^~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2250.52-2250.66: error: The type name `Gdk.EventButton' could not be found - 2250 | public override bool button_release_event (Gdk.EventButton event) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2271.50-2271.64: error: The type name `Gdk.EventButton' could not be found - 2271 | public override bool button_press_event (Gdk.EventButton event) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:2396.54-2396.69: error: The type name `Gdk.EventButton' could not be found - 2396 | private bool popup_context_menu (Item? item, Gdk.EventButton? event) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:93.50-93.66: error: The type name `Gtk.SelectionData' could not be found - 93 | public abstract void prepare_selection_data (Gtk.SelectionData selection_data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:110.46-110.60: error: The type name `Gdk.DragContext' could not be found - 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:110.71-110.87: error: The type name `Gtk.SelectionData' could not be found - 110 | public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:122.51-122.65: error: The type name `Gdk.DragContext' could not be found - 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~ -../src/Widgets/SourceList/SourceList.vala:122.76-122.92: error: The type name `Gtk.SelectionData' could not be found - 122 | public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found - 23 | public unowned Gtk.RadioButton? group_source { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:23.12-23.35: error: The type name `Gtk.RadioButton' could not be found - 23 | public unowned Gtk.RadioButton? group_source { - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:193.49-193.64: error: The type name `Gtk.RadioButton' could not be found - 193 | public ProjectRow (string project_path, Gtk.RadioButton? group_source ) { - | ^~~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/ChooseProjectButton.vala:191.16-191.30: error: The type name `Gtk.RadioButton' could not be found - 191 | public Gtk.RadioButton project_radio { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:34.13-34.37: error: The type name `Gtk.SourceLanguageManager' could not be found - 34 | private Gtk.SourceLanguageManager manager; - | ^~~~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:103.23-103.37: error: The type name `Gtk.RadioButton' could not be found - 103 | unowned SList group = null; - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:105.13-105.35: error: The type name `Gtk.SourceLanguage' could not be found - 105 | weak Gtk.SourceLanguage lang = manager.get_language (id); - | ^~~~~~~~~~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:378.17-378.31: error: The type name `Gtk.RadioButton' could not be found - 378 | private Gtk.RadioButton lang_radio; - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:379.68-379.82: error: The type name `Gtk.RadioButton' could not be found - 379 | public LangEntry (string? lang_id, string lang_name, SList group) { - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:400.30-400.44: error: The type name `Gtk.RadioButton' could not be found - 400 | public unowned SList get_radio_group () { - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/FormatBar.vala:354.30-354.44: error: The type name `Gtk.RadioButton' could not be found - 354 | public unowned SList group { get; construct; } - | ^~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:120.33-120.47: error: The type name `Gdk.DragContext' could not be found - 120 | Gdk.DragContext ctx, - | ^~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:123.33-123.49: error: The type name `Gtk.SelectionData' could not be found - 123 | Gtk.SelectionData sel, - | ^~~~~~~~~~~~~~~~~ -../src/Widgets/Sidebar.vala:114.9-114.23: error: The type name `Gtk.TargetEntry' could not be found - 114 | Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; - | ^~~~~~~~~~~~~~~ -../src/Widgets/Terminal.vala:22.13-22.25: error: The type name `Gtk.Clipboard' could not be found - 22 | private Gtk.Clipboard current_clipboard; - | ^~~~~~~~~~~~~ - - - - - GRANITE - - - -../src/Widgets/WelcomeView.vala:20.33-20.55: error: The type name `Granite.Widgets.Welcome' could not be found - 20 | public class Code.WelcomeView : Granite.Widgets.Welcome { -../src/Widgets/WelcomeView.vala:20.33-20.55: error: The type name `Granite.Widgets.Welcome' could not be found - 20 | public class Code.WelcomeView : Granite.Widgets.Welcome { - | ^~~~~~~~~~~~~~~~~~~~~~~ -Compilation failed: 109 error(s), 0 warning(s) -ninja: build stopped: subcommand failed. From 26444c1bf05fc07bbaba7e3b316df461ac132cef Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 23 Dec 2024 16:50:19 +0200 Subject: [PATCH 14/20] fix: missing migrations from plugins folder --- plugins/detect-indent/detect-indent.vala | 2 +- plugins/highlight-word-selection/highlight-word-selection.vala | 2 +- plugins/spell/spell.vala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/detect-indent/detect-indent.vala b/plugins/detect-indent/detect-indent.vala index 09fe9c1d24..9f079e4d4b 100644 --- a/plugins/detect-indent/detect-indent.vala +++ b/plugins/detect-indent/detect-indent.vala @@ -17,7 +17,7 @@ public class Scratch.Plugins.DetectIndent: Peas.ExtensionBase, Peas.Activatable return; } - var source_buffer = (Gtk.SourceBuffer) view.buffer; + var source_buffer = (GtkSource.Buffer) view.buffer; Gtk.TextIter it; source_buffer.get_iter_at_line (out it, 0); diff --git a/plugins/highlight-word-selection/highlight-word-selection.vala b/plugins/highlight-word-selection/highlight-word-selection.vala index 5896b5d43e..be17df4ac6 100644 --- a/plugins/highlight-word-selection/highlight-word-selection.vala +++ b/plugins/highlight-word-selection/highlight-word-selection.vala @@ -58,7 +58,7 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Peas.A window_search_context.get_occurrences_count () == 0) { // Perform plugin selection when there is no ongoing and successful search current_search_context = new Gtk.SourceSearchContext ( - (Gtk.SourceBuffer)current_source.buffer, + (GtkSource.Buffer)current_source.buffer, null ); current_search_context.settings.search_text = ""; diff --git a/plugins/spell/spell.vala b/plugins/spell/spell.vala index 6e90e60e2f..4c9d03e885 100644 --- a/plugins/spell/spell.vala +++ b/plugins/spell/spell.vala @@ -98,7 +98,7 @@ public class Scratch.Plugins.Spell: Peas.ExtensionBase, Peas.Activatable { }); // Deactivate Spell checker when we are editing a code file - var source_buffer = (Gtk.SourceBuffer) d.source_view.buffer; + var source_buffer = (GtkSource.Buffer) d.source_view.buffer; var lang = source_buffer.language; if (lang != null && lang.id != "markdown") { spell.detach (); From 7250ba378110b75fa51ebe59c9a51897a471bf09 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Tue, 24 Dec 2024 17:23:18 +0200 Subject: [PATCH 15/20] fix: typo in variable name of libadwaita --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index cc08b15a84..17b2771716 100644 --- a/meson.build +++ b/meson.build @@ -31,7 +31,7 @@ gio_unix_dep = dependency('gio-unix-2.0', version: '>=2.20') gee_dep = dependency('gee-0.8', version: '>=0.8.5') gtk_dep = dependency('gtk4', version: '>=4.14.2') granite_dep = dependency('granite-7', version: '>=7.0.0') -handy_dep = dependency('libadwaita-1', version: '>=1.0.0') +adwaita_dep = dependency('libadwaita-1', version: '>=1.0.0') gtksourceview_dep = dependency('gtksourceview-5') git_dep = dependency('libgit2-glib-1.0') fontconfig_dep = dependency('fontconfig') @@ -54,7 +54,7 @@ dependencies = [ gee_dep, gtk_dep, granite_dep, - handy_dep, + adwaita_dep, gtksourceview_dep, git_dep, fontconfig_dep, From bb33ca52f4fbd5bc09a23705403632edbf51b55b Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Thu, 26 Dec 2024 17:33:22 +0200 Subject: [PATCH 16/20] ci: update dependencies --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9090e51f05..173e73096b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgit2-glib-1.0-dev libgranite-dev libgtk-3-dev libgtksourceview-4-dev libgtkspell3-3-dev libhandy-1-dev libpeas-dev libsoup2.4-dev libvala-dev libvte-2.91-dev meson valac polkitd libpolkit-gobject-1-dev + apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgranite-7-dev libgtk-4-dev libgtksourceview-5-dev libgtkspell3-3-dev libadwaita-1-dev libpeas-2-dev libsoup2.4-dev libvala-dev libvte-2.91-dev meson valac polkitd libpolkit-gobject-1-dev - name: Build env: DESTDIR: out From b112f1f5f58aa956a4a929888779eae1333927d9 Mon Sep 17 00:00:00 2001 From: kaixoo <174825714+kaixoo@users.noreply.github.com> Date: Sat, 28 Dec 2024 11:20:21 +0100 Subject: [PATCH 17/20] gtk4 migration: Drag-and-Drop (#1) * feat: migrate DocumentView.vala drag-and-drop Replaced drag_received with drag_begin(Gtk.DragSource). Replaced Gtk.TargetEntry with GLib.Value * feat: migrate Sidebar.vala gtk drag-and-drop * feat: migrate MainWindow.vala Gtk.TargetEntry. TODO: Gdk.EventAny * feat: migrate Gtk.DragContext in SourceList.vala --------- Co-authored-by: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> --- src/MainWindow.vala | 2 +- src/Widgets/DocumentView.vala | 14 +++++------ src/Widgets/Sidebar.vala | 14 +++-------- src/Widgets/SourceList/SourceList.vala | 33 ++++++++++---------------- 4 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 3825e549c1..7fdfa6acd9 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -453,7 +453,7 @@ namespace Scratch { welcome_view = new Code.WelcomeView (this); document_view = new Scratch.Widgets.DocumentView (this); // Handle Drag-and-drop for files functionality on welcome screen - Gtk.TargetEntry target = {"text/uri-list", 0, 0}; + GLib.Value target = {"text/uri-list", 0, 0}; Gtk.drag_dest_set (welcome_view, Gtk.DestDefaults.ALL, {target}, Gdk.DragAction.COPY); welcome_view.drag_data_received.connect ((ctx, x, y, sel, info, time) => { diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index 84e82ee14c..cbd3ef19df 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -165,7 +165,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { }); // Handle Drag-and-drop of files onto add-tab button to create document - Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + GLib.Value uris = {"text/uri-list", 0, GLib.Value.URI_LIST}; Gtk.drag_dest_set (tab_bar, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); tab_bar.drag_data_received.connect (drag_received); @@ -646,23 +646,21 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { return menu; } - private void drag_received (Gtk.Widget w, - Gdk.DragContext ctx, + private void drag_begin (Gdk.Drag drag) { + /* + Gdk.DragSource ctx, int x, int y, Gtk.SelectionData sel, uint info, - uint time) { - - if (info == TargetType.URI_LIST) { + uint time*/ + if (info == GLib.Value.URI_LIST) { var uris = sel.get_uris (); foreach (var filename in uris) { var file = File.new_for_uri (filename); var doc = new Services.Document (window.actions, file); open_document (doc); } - - Gtk.drag_finish (ctx, true, false, time); } } } diff --git a/src/Widgets/Sidebar.vala b/src/Widgets/Sidebar.vala index dc67ccc929..543d076fcd 100644 --- a/src/Widgets/Sidebar.vala +++ b/src/Widgets/Sidebar.vala @@ -111,20 +111,14 @@ public class Code.Sidebar : Gtk.Grid { } }); - Gtk.TargetEntry uris = {"text/uri-list", 0, TargetType.URI_LIST}; + GLib.Value uris = {"text/uri-list", 0, GLib.Value.URI_LIST}; Gtk.drag_dest_set (this, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.COPY); drag_data_received.connect (drag_received); } - private void drag_received (Gtk.Widget w, - Gdk.DragContext ctx, - int x, - int y, - Gtk.SelectionData sel, - uint info, - uint time) { + private void drag_received (Gdk.Drag drag) { - if (info == TargetType.URI_LIST) { + if (info == GLib.Value.URI_LIST) { var uri_list = sel.get_uris (); GLib.List folder_list = null; foreach (unowned var uri in uri_list) { @@ -143,8 +137,6 @@ public class Code.Sidebar : Gtk.Grid { new Variant.string (folder.get_path ()) ); } - - Gtk.drag_finish (ctx, folder_list.length () > 0, false, time); } } diff --git a/src/Widgets/SourceList/SourceList.vala b/src/Widgets/SourceList/SourceList.vala index 0f1f17d539..24fde8049a 100644 --- a/src/Widgets/SourceList/SourceList.vala +++ b/src/Widgets/SourceList/SourceList.vala @@ -107,7 +107,7 @@ public interface SourceListDragDest : SourceList.Item { * @return //true// if the drop is possible; //false// otherwise. * @since 0.3 */ - public abstract bool data_drop_possible (Gdk.DragContext context, Gtk.SelectionData data); + public abstract bool data_drop_possible (Gdk.Drag drag, Gtk.SelectionData data); /** * If a data drop is deemed possible, then this method is called @@ -119,7 +119,7 @@ public interface SourceListDragDest : SourceList.Item { * @return The action taken, or //0// to indicate that the dropped data was not accepted. * @since 0.3 */ - public abstract Gdk.DragAction data_received (Gdk.DragContext context, Gtk.SelectionData data); + public abstract Gdk.DragAction data_received (Gdk.Drag drag, Gtk.SelectionData data); } /** @@ -1727,7 +1727,7 @@ public class SourceList : Gtk.ScrolledWindow { disable_item_property_monitor (); } - public override bool drag_motion (Gdk.DragContext context, int x, int y, uint time) { + public override bool drag_motion (Gdk.Drag drag) { // call the base signal to get rows with children to spring open if (!base.drag_motion (context, x, y, time)) return false; @@ -1791,14 +1791,7 @@ public class SourceList : Gtk.ScrolledWindow { return true; } - public override void drag_data_received ( - Gdk.DragContext context, - int x, - int y, - Gtk.SelectionData selection_data, - uint info, - uint time - ) { + public override void drag_data_received (Gdk.Drag drag) { var target_list = Gtk.drag_dest_get_target_list (this); var target = Gtk.drag_dest_find_target (this, context, target_list); @@ -1850,7 +1843,7 @@ public class SourceList : Gtk.ScrolledWindow { } } - public void configure_drag_source (Gtk.TargetEntry[]? src_entries) { + public void configure_drag_source (GLib.Value[]? src_entries) { // Append GTK_TREE_MODEL_ROW to src_entries and src_entries to enable row DnD. var entries = append_row_target_entry (src_entries); @@ -1858,7 +1851,7 @@ public class SourceList : Gtk.ScrolledWindow { enable_model_drag_source (Gdk.ModifierType.BUTTON1_MASK, entries, Gdk.DragAction.MOVE); } - public void configure_drag_dest (Gtk.TargetEntry[]? dest_entries, Gdk.DragAction actions) { + public void configure_drag_dest (GLib.Value[]? dest_entries, Gdk.DragAction actions) { // Append GTK_TREE_MODEL_ROW to dest_entries and dest_entries to enable row DnD. var entries = append_row_target_entry (dest_entries); @@ -1915,14 +1908,14 @@ public class SourceList : Gtk.ScrolledWindow { return false; } - private static Gtk.TargetEntry[] append_row_target_entry (Gtk.TargetEntry[]? orig) { - const Gtk.TargetEntry row_target_entry = { // vala-lint=naming-convention + private static GLib.Value[] append_row_target_entry (GLib.Value[]? orig) { + const GLib.Value row_target_entry = { // vala-lint=naming-convention "GTK_TREE_MODEL_ROW", Gtk.TargetFlags.SAME_WIDGET, 0 }; - var entries = new Gtk.TargetEntry[0]; + var entries = new GLib.Value[0]; entries += row_target_entry; if (orig != null) { @@ -2758,13 +2751,13 @@ public class SourceList : Gtk.ScrolledWindow { * This enables items that implement {@link Code.Widgets.SourceListDragSource} * to be dragged outside the Source List and drop data into external widgets. * - * @param src_entries an array of {@link Gtk.TargetEntry}s indicating the targets + * @param src_entries an array of {@link GLib.Value}s indicating the targets * that the drag will support. * @see Code.Widgets.SourceListDragSource * @see Code.Widgets.SourceList.disable_drag_source * @since 0.3 */ - public void enable_drag_source (Gtk.TargetEntry[] src_entries) { + public void enable_drag_source (GLib.Value[] src_entries) { tree.configure_drag_source (src_entries); } @@ -2784,14 +2777,14 @@ public class SourceList : Gtk.ScrolledWindow { * This enables items that implement {@link Code.Widgets.SourceListDragDest} * to receive data from external widgets via drag-and-drop. * - * @param dest_entries an array of {@link Gtk.TargetEntry}s indicating the drop + * @param dest_entries an array of {@link GLib.Value}s indicating the drop * types that Source List items will accept. * @param actions a bitmask of possible actions for a drop onto Source List items. * @see Code.Widgets.SourceListDragDest * @see Code.Widgets.SourceList.disable_drag_dest * @since 0.3 */ - public void enable_drag_dest (Gtk.TargetEntry[] dest_entries, Gdk.DragAction actions) { + public void enable_drag_dest (GLib.Value[] dest_entries, Gdk.DragAction actions) { tree.configure_drag_dest (dest_entries, actions); } From 65e6f6788fed0254a0476c6934b96e1560e4f482 Mon Sep 17 00:00:00 2001 From: kaixoo <21697330-kaixoo@users.noreply.gitlab.com> Date: Mon, 30 Dec 2024 15:26:08 +0200 Subject: [PATCH 18/20] migrate: Gtk.SelectionData in DocumentView.vala --- src/Widgets/DocumentView.vala | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index cbd3ef19df..bd7367c9a5 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -647,13 +647,6 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } private void drag_begin (Gdk.Drag drag) { - /* - Gdk.DragSource ctx, - int x, - int y, - Gtk.SelectionData sel, - uint info, - uint time*/ if (info == GLib.Value.URI_LIST) { var uris = sel.get_uris (); foreach (var filename in uris) { From 923fc28549483e1f750841c91106b74c2ba318d2 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 30 Dec 2024 20:11:26 +0000 Subject: [PATCH 19/20] Update ci.yml for libsoup3 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 173e73096b..b1f0d011e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgranite-7-dev libgtk-4-dev libgtksourceview-5-dev libgtkspell3-3-dev libadwaita-1-dev libpeas-2-dev libsoup2.4-dev libvala-dev libvte-2.91-dev meson valac polkitd libpolkit-gobject-1-dev + apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgranite-7-dev libgtk-4-dev libgtksourceview-5-dev libgtkspell3-3-dev libadwaita-1-dev libpeas-2-dev libsoup-3.0-dev libvala-dev libvte-2.91-dev meson valac polkitd libpolkit-gobject-1-dev - name: Build env: DESTDIR: out From 90cd82ec19f264146d4333411dd5e48dbc9d5e41 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 30 Dec 2024 22:14:01 +0000 Subject: [PATCH 20/20] Fix Sourcelist, DnD and events for Gtk4 port - stage 1 (#2) * First compilable version * Emulate previous appearance of Plugins view * Update ci.yml * Update io.elementary.code.yml * Bump glib dependency for libpeas-2 * Rename non-functional Flatpak manifest * Sync checkbutton with plugin loaded on show * Action when checkbox toggled * Fix double parenting * Sort plugins by name * Use bind_model and factory * Lose unused entities * Cleanup and code style * Fix initial appearance of preferences dialog * Add some comments * Lose commented out code * Make activate and deactivate methods mandatory to implement * Fix Flatpak build for OS8 * Fix ci.yml * Add libgit2-glib-1.0-dev to ci.yml * Split SourceList into one file per class * Fix changed namespace * Remove DnD code * Replace Gdk.EventKey * Use GestureClick * Handle showing context menu * Handle search_entry focus in * Handle window close request --- .github/workflows/ci.yml | 3 +- io.elementary.code.yml | 19 +- meson.build | 2 + .../brackets-completion.vala | 4 +- plugins/detect-indent/detect-indent.vala | 4 +- plugins/editorconfig/editorconfig.vala | 4 +- plugins/fuzzy-search/fuzzy-search.vala | 4 +- .../highlight-word-selection.vala | 4 +- .../markdown-actions/markdown-actions.vala | 4 +- plugins/pastebin/meson.build | 2 +- plugins/pastebin/pastebin.vala | 21 +- plugins/preserve-indent/preserve-indent.vala | 4 +- plugins/spell/spell.vala | 4 +- plugins/vim-emulation/vim-emulation.vala | 4 +- plugins/word-completion/plugin.vala | 4 +- src/Dialogs/PreferencesDialog.vala | 9 +- src/FolderManager/FileView.vala | 2 +- src/FolderManager/Item.vala | 154 +- src/MainWindow.vala | 4 +- src/Services/PluginManager.vala | 135 +- src/SymbolPane/SymbolOutline.vala | 2 +- src/SymbolPane/Vala/ValaSymbolItem.vala | 2 +- src/Widgets/SearchBar.vala | 55 +- src/Widgets/SourceList/CellRendererIcon.vala | 31 + .../SourceList/CellRendererSpacer.vala | 36 + src/Widgets/SourceList/SourceList.vala | 2769 +---------------- .../SourceList/SourceListDataModel.vala | 525 ++++ .../SourceList/SourceListExpandableItem.vala | 357 +++ src/Widgets/SourceList/SourceListItem.vala | 182 ++ src/Widgets/SourceList/SourceListTree.vala | 912 ++++++ src/meson.build | 6 + vapi/libpeas-2.vapi | 136 + 32 files changed, 2618 insertions(+), 2786 deletions(-) create mode 100644 src/Widgets/SourceList/CellRendererIcon.vala create mode 100644 src/Widgets/SourceList/CellRendererSpacer.vala create mode 100644 src/Widgets/SourceList/SourceListDataModel.vala create mode 100644 src/Widgets/SourceList/SourceListExpandableItem.vala create mode 100644 src/Widgets/SourceList/SourceListItem.vala create mode 100644 src/Widgets/SourceList/SourceListTree.vala create mode 100644 vapi/libpeas-2.vapi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1f0d011e6..e4f8c60c3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,8 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgranite-7-dev libgtk-4-dev libgtksourceview-5-dev libgtkspell3-3-dev libadwaita-1-dev libpeas-2-dev libsoup-3.0-dev libvala-dev libvte-2.91-dev meson valac polkitd libpolkit-gobject-1-dev + apt install -y exuberant-ctags libeditorconfig-dev libgail-3-dev libgee-0.8-dev libgranite-7-dev libgtk-4-dev libgtksourceview-5-dev libgtkspell3-3-dev libadwaita-1-dev libpeas-2-dev libsoup2.4-dev libvala-dev libvte-2.91-gtk4-dev meson valac polkitd libpolkit-gobject-1-dev libgit2-glib-1.0-dev + - name: Build env: DESTDIR: out diff --git a/io.elementary.code.yml b/io.elementary.code.yml index 77e4ffaff4..24f23e0af9 100644 --- a/io.elementary.code.yml +++ b/io.elementary.code.yml @@ -1,6 +1,6 @@ app-id: io.elementary.code runtime: io.elementary.Sdk # The outline plugin requires libvala which is only in the SDK, not the runtime -runtime-version: "7.1" +runtime-version: 'daily' sdk: io.elementary.Sdk command: io.elementary.code finish-args: @@ -31,7 +31,22 @@ modules: sources: - type: git url: https://gitlab.gnome.org/GNOME/gtksourceview.git - tag: "4.8.4" + tag: '4.8.4' + + - name: libpeas + buildsystem: meson + config-opts: + - -Dlua51=false + - -Dgjs=false + sources: + - type: archive + url: https://download.gnome.org/sources/libpeas/2.0/libpeas-2.0.5.tar.xz + sha256: 376f2f73d731b54e13ddbab1d91b6382cf6a980524def44df62add15489de6dd + x-checker-data: + type: gnome + versions: + <: '2.0.6' + name: libpeas - name: git2-glib buildsystem: meson diff --git a/meson.build b/meson.build index 17b2771716..f699a8ae24 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ gtk_dep = dependency('gtk4', version: '>=4.14.2') granite_dep = dependency('granite-7', version: '>=7.0.0') adwaita_dep = dependency('libadwaita-1', version: '>=1.0.0') gtksourceview_dep = dependency('gtksourceview-5') +peas_dep = dependency('libpeas-2') git_dep = dependency('libgit2-glib-1.0') fontconfig_dep = dependency('fontconfig') pangofc_dep = dependency('pangoft2') @@ -56,6 +57,7 @@ dependencies = [ granite_dep, adwaita_dep, gtksourceview_dep, + peas_dep, git_dep, fontconfig_dep, pangofc_dep, diff --git a/plugins/brackets-completion/brackets-completion.vala b/plugins/brackets-completion/brackets-completion.vala index bf3f4cf15c..a252df5196 100644 --- a/plugins/brackets-completion/brackets-completion.vala +++ b/plugins/brackets-completion/brackets-completion.vala @@ -18,7 +18,7 @@ END LICENSE ***/ -public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Gee.HashMap brackets; Gee.HashMap keys; const string[] VALID_NEXT_CHARS = { @@ -278,6 +278,6 @@ public class Scratch.Plugins.BracketsCompletion : Peas.ExtensionBase, Peas.Activ [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.BracketsCompletion)); } diff --git a/plugins/detect-indent/detect-indent.vala b/plugins/detect-indent/detect-indent.vala index 9f079e4d4b..a055cf43c2 100644 --- a/plugins/detect-indent/detect-indent.vala +++ b/plugins/detect-indent/detect-indent.vala @@ -1,4 +1,4 @@ -public class Scratch.Plugins.DetectIndent: Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.DetectIndent: Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { const int MAX_LINES = 500; Scratch.Services.Interface plugins; @@ -79,7 +79,7 @@ public class Scratch.Plugins.DetectIndent: Peas.ExtensionBase, Peas.Activatable public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; objmodule.register_extension_type ( - typeof (Peas.Activatable), + typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.DetectIndent) ); } diff --git a/plugins/editorconfig/editorconfig.vala b/plugins/editorconfig/editorconfig.vala index 8a5b8f4285..936257d3d2 100644 --- a/plugins/editorconfig/editorconfig.vala +++ b/plugins/editorconfig/editorconfig.vala @@ -17,7 +17,7 @@ * Boston, MA 02110-1301 USA */ -public class Scratch.Plugins.EditorConfigPlugin: Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.EditorConfigPlugin: Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Scratch.Services.Interface plugins; public Object object { owned get; construct; } private Code.FormatBar format_bar; @@ -91,5 +91,5 @@ public class Scratch.Plugins.EditorConfigPlugin: Peas.ExtensionBase, Peas.Activa [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), typeof (Scratch.Plugins.EditorConfigPlugin)); + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.EditorConfigPlugin)); } diff --git a/plugins/fuzzy-search/fuzzy-search.vala b/plugins/fuzzy-search/fuzzy-search.vala index 2cff1cf2b7..f38f62f245 100644 --- a/plugins/fuzzy-search/fuzzy-search.vala +++ b/plugins/fuzzy-search/fuzzy-search.vala @@ -6,7 +6,7 @@ */ -public class Scratch.Plugins.FuzzySearch: Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.FuzzySearch: Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { public Object object { owned get; construct; } private const uint ACCEL_KEY = Gdk.Key.F; private const Gdk.ModifierType ACCEL_MODTYPE = Gdk.ModifierType.MOD1_MASK; @@ -158,7 +158,7 @@ public class Scratch.Plugins.FuzzySearch: Peas.ExtensionBase, Peas.Activatable { public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; objmodule.register_extension_type ( - typeof (Peas.Activatable), + typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.FuzzySearch) ); } diff --git a/plugins/highlight-word-selection/highlight-word-selection.vala b/plugins/highlight-word-selection/highlight-word-selection.vala index be17df4ac6..534c83bac9 100644 --- a/plugins/highlight-word-selection/highlight-word-selection.vala +++ b/plugins/highlight-word-selection/highlight-word-selection.vala @@ -18,7 +18,7 @@ END LICENSE ***/ -public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Scratch.Widgets.SourceView current_source; Scratch.MainWindow? main_window = null; Gtk.SourceSearchContext? current_search_context = null; @@ -151,6 +151,6 @@ public class Scratch.Plugins.HighlightSelectedWords : Peas.ExtensionBase, Peas.A [ModuleInit] public void peas_register_types (TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.HighlightSelectedWords)); } diff --git a/plugins/markdown-actions/markdown-actions.vala b/plugins/markdown-actions/markdown-actions.vala index 024e97c3b6..d53bf4fcd8 100644 --- a/plugins/markdown-actions/markdown-actions.vala +++ b/plugins/markdown-actions/markdown-actions.vala @@ -18,7 +18,7 @@ END LICENSE ***/ -public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable { +public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Scratch.Widgets.SourceView current_source; Scratch.Services.Interface plugins; @@ -243,6 +243,6 @@ public class Code.Plugins.MarkdownActions : Peas.ExtensionBase, Peas.Activatable [ModuleInit] public void peas_register_types (TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Code.Plugins.MarkdownActions)); } diff --git a/plugins/pastebin/meson.build b/plugins/pastebin/meson.build index f18e644d41..b426acff0e 100644 --- a/plugins/pastebin/meson.build +++ b/plugins/pastebin/meson.build @@ -5,7 +5,7 @@ module_files = [ 'pastebin.vala' ] -soup_dep = dependency('libsoup-2.4') +soup_dep = dependency('libsoup-3.0') module_deps = [ codecore_dep, diff --git a/plugins/pastebin/pastebin.vala b/plugins/pastebin/pastebin.vala index 3a4471dc21..2d32634904 100644 --- a/plugins/pastebin/pastebin.vala +++ b/plugins/pastebin/pastebin.vala @@ -34,6 +34,7 @@ namespace Scratch.Services { string paste_private, string paste_expire_date, string paste_format) { + link = null; if (paste_code.length == 0) { link = "No text to paste"; return false; } string api_url = "https://pastebin.com/api/api_post.php"; @@ -50,15 +51,21 @@ namespace Scratch.Services { "api_paste_expire_date", paste_expire_date, "api_paste_format", paste_format); - message.set_request ("application/x-www-form-urlencoded", Soup.MemoryUse.COPY, request.data); + message.set_request_body_from_bytes ("application/x-www-form-urlencoded", new Bytes (request.data)); message.set_flags (Soup.MessageFlags.NO_REDIRECT); - session.send_message (message); + Bytes output; + try { + output = session.send_and_read (message); + } catch (Error e) { + return false; + } + - var output = (string) message.response_body.data; - link = output; + var output_s = (string) output.get_data (); + link = output_s; - if (Uri.parse_scheme (output) == null || message.status_code != 200) { + if (Uri.parse_scheme (output_s) == null || message.status_code != 200) { // A URI was not returned return false; } @@ -68,7 +75,7 @@ namespace Scratch.Services { } } -public class Scratch.Plugins.Pastebin : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.Pastebin : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { GLib.MenuItem? menuitem = null; GLib.Menu? share_menu = null; public Object object { owned get; construct; } @@ -147,6 +154,6 @@ public class Scratch.Plugins.Pastebin : Peas.ExtensionBase, Peas.Activatable { [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.Pastebin)); } diff --git a/plugins/preserve-indent/preserve-indent.vala b/plugins/preserve-indent/preserve-indent.vala index 6f07e0c3d3..bfb8ff801b 100644 --- a/plugins/preserve-indent/preserve-indent.vala +++ b/plugins/preserve-indent/preserve-indent.vala @@ -18,7 +18,7 @@ END LICENSE ***/ -public class Scratch.Plugins.PreserveIndent : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.PreserveIndent : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { private Scratch.Services.Interface plugins; private Gee.TreeSet documents; @@ -244,6 +244,6 @@ public class Scratch.Plugins.PreserveIndent : Peas.ExtensionBase, Peas.Activatab [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.PreserveIndent)); } diff --git a/plugins/spell/spell.vala b/plugins/spell/spell.vala index 4c9d03e885..fccae7d032 100644 --- a/plugins/spell/spell.vala +++ b/plugins/spell/spell.vala @@ -13,7 +13,7 @@ * with this program. If not, see */ -public class Scratch.Plugins.Spell: Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.Spell: Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { Scratch.Services.Interface plugins; @@ -160,7 +160,7 @@ public class Scratch.Plugins.Spell: Peas.ExtensionBase, Peas.Activatable { public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; objmodule.register_extension_type ( - typeof (Peas.Activatable), + typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.Spell) ); } diff --git a/plugins/vim-emulation/vim-emulation.vala b/plugins/vim-emulation/vim-emulation.vala index 32ec3c397a..426737da21 100644 --- a/plugins/vim-emulation/vim-emulation.vala +++ b/plugins/vim-emulation/vim-emulation.vala @@ -18,7 +18,7 @@ END LICENSE ***/ -public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { public enum Mode { COMMAND, INSERT, @@ -298,6 +298,6 @@ public class Scratch.Plugins.VimEmulation : Peas.ExtensionBase, Peas.Activatable [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.VimEmulation)); } diff --git a/plugins/word-completion/plugin.vala b/plugins/word-completion/plugin.vala index d227d12a6a..0f45c14841 100644 --- a/plugins/word-completion/plugin.vala +++ b/plugins/word-completion/plugin.vala @@ -18,7 +18,7 @@ * */ -public class Scratch.Plugins.Completion : Peas.ExtensionBase, Peas.Activatable { +public class Scratch.Plugins.Completion : Peas.ExtensionBase, Scratch.Services.ActivatablePlugin { public Object object { owned get; construct; } private List text_view_list = new List (); @@ -185,6 +185,6 @@ public class Scratch.Plugins.Completion : Peas.ExtensionBase, Peas.Activatable { [ModuleInit] public void peas_register_types (GLib.TypeModule module) { var objmodule = module as Peas.ObjectModule; - objmodule.register_extension_type (typeof (Peas.Activatable), + objmodule.register_extension_type (typeof (Scratch.Services.ActivatablePlugin), typeof (Scratch.Plugins.Completion)); } diff --git a/src/Dialogs/PreferencesDialog.vala b/src/Dialogs/PreferencesDialog.vala index 96f2de4590..53288c3985 100644 --- a/src/Dialogs/PreferencesDialog.vala +++ b/src/Dialogs/PreferencesDialog.vala @@ -144,9 +144,9 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { main_box.add (stackswitcher); main_box.add (stack); - plugins.hook_preferences_dialog (this); + plugins.hook_preferences_dialog (this); // Unused? - if (Peas.Engine.get_default ().get_plugin_list ().length () > 0) { + if (plugins.get_n_plugins () > 0) { var pbox = plugins.get_view (); pbox.vexpand = true; @@ -160,6 +160,11 @@ public class Scratch.Dialogs.Preferences : Granite.Dialog { close_button.clicked.connect (() => { destroy (); }); + + //Ensure appearance correct after using libpeas-2 + realize.connect (() => { + stack.set_visible_child_name ("behavior"); + }); } private class SettingSwitch : Gtk.Grid { diff --git a/src/FolderManager/FileView.vala b/src/FolderManager/FileView.vala index c9efd85bbf..d06abc17b6 100644 --- a/src/FolderManager/FileView.vala +++ b/src/FolderManager/FileView.vala @@ -21,7 +21,7 @@ /** * SourceList that displays folders and their contents. */ -public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.PaneSwitcher { +public class Scratch.FolderManager.FileView : Code.Widgets.SourceList.Window, Code.PaneSwitcher { public const string ACTION_GROUP = "file-view"; public const string ACTION_PREFIX = ACTION_GROUP + "."; public const string ACTION_LAUNCH_APP_WITH_FILE_PATH = "launch-app-with-file-path"; diff --git a/src/FolderManager/Item.vala b/src/FolderManager/Item.vala index 19cb84f112..2116c9d03b 100644 --- a/src/FolderManager/Item.vala +++ b/src/FolderManager/Item.vala @@ -1,96 +1,96 @@ /*- - * Copyright (c) 2017 elementary LLC. (https://elementary.io), - * 2013 Julien Spautz - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * 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 warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 . - * - * Authored by: Julien Spautz , Andrei-Costin Zisu - */ +* Copyright (c) 2017 elementary LLC. (https://elementary.io), +* 2013 Julien Spautz +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* 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 warranties of +* MERCHANTABILITY, SATISFACTORY QUALITY, 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 . +* +* Authored by: Julien Spautz , Andrei-Costin Zisu +*/ namespace Scratch.FolderManager { - /** - * Common abstract class for file and folder items. - */ - public abstract class Item: Code.Widgets.SourceList.ExpandableItem, Code.Widgets.SourceListSortable { - public File file { get; construct; } +/** + * Common abstract class for file and folder items. + */ +public abstract class Item: Code.Widgets.SourceList.ExpandableItem, Code.Widgets.SourceList.Sortable { + public File file { get; construct; } - public FileView view { get; construct; } - public string path { - owned get { return file.path; } - set { file.path = value; } - } + public FileView view { get; construct; } + public string path { + owned get { return file.path; } + set { file.path = value; } + } - construct { - selectable = true; - editable = true; - name = file.name; - icon = file.icon; - edited.connect (rename); - tooltip = Scratch.Utils.replace_home_with_tilde (file.path); + construct { + selectable = true; + editable = true; + name = file.name; + icon = file.icon; + edited.connect (rename); + tooltip = Scratch.Utils.replace_home_with_tilde (file.path); - notify["activatable-tooltip"].connect (() => { - tooltip = ("%s\n" + Granite.TOOLTIP_SECONDARY_TEXT_MARKUP).printf ( - Scratch.Utils.replace_home_with_tilde (file.path), - activatable_tooltip - ); - }); - } + notify["activatable-tooltip"].connect (() => { + tooltip = ("%s\n" + Granite.TOOLTIP_SECONDARY_TEXT_MARKUP).printf ( + Scratch.Utils.replace_home_with_tilde (file.path), + activatable_tooltip + ); + }); + } - protected void rename (string new_name) { - file.rename (new_name); - } + protected void rename (string new_name) { + file.rename (new_name); + } - public void trash () { - file.trash (); + public void trash () { + file.trash (); + } + + public int compare (Code.Widgets.SourceList.Item a, Code.Widgets.SourceList.Item b) { + if (a is RenameItem) { + return -1; + } else if (b is RenameItem) { + return 1; } - public int compare (Code.Widgets.SourceList.Item a, Code.Widgets.SourceList.Item b) { - if (a is RenameItem) { - return -1; - } else if (b is RenameItem) { - return 1; - } + if (a is FolderItem && b is FileItem) { + return -1; + } else if (a is FileItem && b is FolderItem) { + return 1; + } - if (a is FolderItem && b is FileItem) { - return -1; - } else if (a is FileItem && b is FolderItem) { - return 1; - } + assert (a is Item && b is Item); //Ensure more informative error message - assert (a is Item && b is Item); //Ensure more informative error message + return File.compare (((Item)a).file, ((Item)b).file); + } - return File.compare (((Item)a).file, ((Item)b).file); - } + public bool allow_dnd_sorting () { + return false; + } - public bool allow_dnd_sorting () { - return false; + public ProjectFolderItem? get_root_folder (Code.Widgets.SourceList.ExpandableItem? start = null) { + if (start == null) { + start = this; } - public ProjectFolderItem? get_root_folder (Code.Widgets.SourceList.ExpandableItem? start = null) { - if (start == null) { - start = this; - } - - if (start is ProjectFolderItem) { - return start as ProjectFolderItem; - } else if (start.parent is ProjectFolderItem) { - return start.parent as ProjectFolderItem; - } else if (start.parent != null) { - return get_root_folder (start.parent); - } else { - return null; - } + if (start is ProjectFolderItem) { + return start as ProjectFolderItem; + } else if (start.parent is ProjectFolderItem) { + return start.parent as ProjectFolderItem; + } else if (start.parent != null) { + return get_root_folder (start.parent); + } else { + return null; } } } +} diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 7fdfa6acd9..4b2554657b 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -335,6 +335,8 @@ namespace Scratch { Unix.signal_add (Posix.Signal.INT, quit_source_func, Priority.HIGH); Unix.signal_add (Posix.Signal.TERM, quit_source_func, Priority.HIGH); + + close_request.connect (on_delete_event); } private void update_style () { @@ -721,7 +723,7 @@ namespace Scratch { return false; } - protected override bool delete_event (Gdk.EventAny event) { + protected override bool delete_event () { action_quit (); return true; } diff --git a/src/Services/PluginManager.vala b/src/Services/PluginManager.vala index 26729a2400..56fa429845 100644 --- a/src/Services/PluginManager.vala +++ b/src/Services/PluginManager.vala @@ -2,7 +2,9 @@ /*** BEGIN LICENSE - Copyright (C) 2013 Mario Guerriero + Copyright (C) 2019–2024 elementary, Inc. + 2013 Mario Guerriero + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, as published by the Free Software Foundation. @@ -19,10 +21,17 @@ ***/ namespace Scratch.Services { - public class Interface : GLib.Object { - - public PluginsManager manager; + // Interface implemented by all plugins + public interface ActivatablePlugin : Object { + // Migrated from Peas.Activatable + public abstract void activate (); + public abstract void deactivate (); + public virtual void update_state () {} + public abstract GLib.Object object { owned get; construct; } + } + // Object shared with plugins providing signals and methods to interface with application + public class Interface : GLib.Object { // Signals public signal void hook_window (Scratch.MainWindow window); public signal void hook_share_menu (GLib.MenuModel menu); @@ -31,11 +40,16 @@ namespace Scratch.Services { public signal void hook_preferences_dialog (Scratch.Dialogs.Preferences dialog); public signal void hook_folder_item_change (File file, File? other_file, FileMonitorEvent event_type); - public Scratch.TemplateManager template_manager { private set; get; } + public Scratch.TemplateManager template_manager { get; construct; } + public Scratch.Services.PluginsManager manager { get; construct; } - public Interface (PluginsManager manager) { - this.manager = manager; + public Interface (PluginsManager _manager) { + Object ( + manager: _manager + ); + } + construct { template_manager = new Scratch.TemplateManager (); } @@ -50,16 +64,12 @@ namespace Scratch.Services { } } - public class PluginsManager : GLib.Object { Peas.Engine engine; Peas.ExtensionSet exts; - string settings_field; - public Interface plugin_iface { private set; public get; } - - public weak MainWindow window; + public weak MainWindow window {get; construct; } // Signals public signal void hook_window (Scratch.MainWindow window); @@ -72,11 +82,13 @@ namespace Scratch.Services { public signal void extension_added (Peas.PluginInfo info); public signal void extension_removed (Peas.PluginInfo info); - public PluginsManager (MainWindow window) { - this.window = window; - - settings_field = "plugins-enabled"; + public PluginsManager (MainWindow _window) { + Object ( + window: _window + ); + } + construct { plugin_iface = new Interface (this); /* Let's init the engine */ @@ -86,19 +98,24 @@ namespace Scratch.Services { Scratch.settings.bind ("plugins-enabled", engine, "loaded-plugins", SettingsBindFlags.DEFAULT); /* Our extension set */ - exts = new Peas.ExtensionSet (engine, typeof (Peas.Activatable), "object", plugin_iface, null); + exts = new Peas.ExtensionSet.with_properties ( + engine, + typeof (ActivatablePlugin), + {"object"}, + {plugin_iface} + ); exts.extension_added.connect ((info, ext) => { - ((Peas.Activatable)ext).activate (); + ((ActivatablePlugin)ext).activate (); extension_added (info); }); exts.extension_removed.connect ((info, ext) => { - ((Peas.Activatable)ext).deactivate (); + ((ActivatablePlugin)ext).deactivate (); extension_removed (info); }); - exts.foreach (on_extension_foreach); + exts.@foreach ((Peas.ExtensionSetForeachFunc) on_extension_foreach, null); // Connect managers signals to interface's signals this.hook_window.connect ((w) => { @@ -126,15 +143,81 @@ namespace Scratch.Services { }); } - void on_extension_foreach (Peas.ExtensionSet set, Peas.PluginInfo info, Peas.Extension extension) { - ((Peas.Activatable)extension).activate (); + void on_extension_foreach (Peas.ExtensionSet exts, Peas.PluginInfo info, Object ext, void* data) { + ((ActivatablePlugin)ext).activate (); } + // Return an emulation of the discontinued libpeas-1.0 widget public Gtk.Widget get_view () { - var view = new PeasGtk.PluginManager (engine); - var bottom_box = view.get_children ().nth_data (1); - bottom_box.no_show_all = true; - return view; + var list_box = new Gtk.ListBox (); + var scrolled_window = new Gtk.ScrolledWindow (null, null) { + hscrollbar_policy = NEVER, + vscrollbar_policy = AUTOMATIC, + max_content_height = 300, + child = list_box + }; + var frame = new Gtk.Frame (null) { + child = scrolled_window + }; + + // Bind the engine ListModel and use a row factory + list_box.bind_model (engine, get_widget_for_plugin_info); + // Cannot sort a ListModel so sort the ListBox (is there a better way?) + // Gtk warns the function will be ignored but it does in fact work, at least + // on initial display. We know the model will not change while the view is used + // In Gtk4 could use SortListModel + list_box.set_sort_func ((r1, r2) => { + return strcmp ( + r1.get_child ().get_data ("name"), + r2.get_child ().get_data ("name") + ); + }); + frame.show_all (); + return frame; + } + + private Gtk.Widget get_widget_for_plugin_info (Object obj) { + var info = (Peas.PluginInfo)obj; + var content = new Gtk.Box (HORIZONTAL, 6); + var checkbox = new Gtk.CheckButton () { + valign = Gtk.Align.CENTER, + active = info.is_loaded (), + margin_start = 6 + }; + checkbox.toggled.connect (() => { + if (checkbox.active) { + engine.load_plugin (info); + } else { + engine.unload_plugin (info); + } + }); + var image = new Gtk.Image.from_icon_name (info.get_icon_name (), LARGE_TOOLBAR) { + valign = Gtk.Align.CENTER + }; + var description_box = new Gtk.Box (VERTICAL, 0); + var name_label = new Granite.HeaderLabel (info.name); + //TODO In Granite-7 we can use secondary text property but emulate for now + var description_label = new Gtk.Label (info.get_description ()) { + use_markup = true, + wrap = true, + xalign = 0, + margin_start = 6, + margin_bottom = 6 + }; + description_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + description_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + description_box.add (name_label); + description_box.add (description_label); + content.add (checkbox); + content.add (image); + content.add (description_box); + content.set_data ("name", info.get_name ()); + + return content; + } + + public uint get_n_plugins () { + return engine.get_n_items (); } } } diff --git a/src/SymbolPane/SymbolOutline.vala b/src/SymbolPane/SymbolOutline.vala index b6fc4b77ce..6982130ae7 100644 --- a/src/SymbolPane/SymbolOutline.vala +++ b/src/SymbolPane/SymbolOutline.vala @@ -75,7 +75,7 @@ public class Scratch.Services.SymbolOutline : Gtk.Box { protected Gee.HashMap checks; protected Gtk.SearchEntry search_entry; - protected Code.Widgets.SourceList store; + protected Code.Widgets.SourceList.Window store; protected Code.Widgets.SourceList.ExpandableItem root; protected Gtk.CssProvider source_list_style_provider; public Gtk.Widget get_widget () { return this; } diff --git a/src/SymbolPane/Vala/ValaSymbolItem.vala b/src/SymbolPane/Vala/ValaSymbolItem.vala index 96b5613a7f..f0895c3d06 100644 --- a/src/SymbolPane/Vala/ValaSymbolItem.vala +++ b/src/SymbolPane/Vala/ValaSymbolItem.vala @@ -16,7 +16,7 @@ * */ -public class Scratch.Services.ValaSymbolItem : Code.Widgets.SourceList.ExpandableItem, Code.Widgets.SourceListSortable, Scratch.Services.SymbolItem { +public class Scratch.Services.ValaSymbolItem : Code.Widgets.SourceList.ExpandableItem, Code.Widgets.SourceList.Sortable, Scratch.Services.SymbolItem { public Vala.Symbol symbol { get; set; } public SymbolType symbol_type { get; set; default = SymbolType.OTHER; } public ValaSymbolItem (Vala.Symbol symbol) { diff --git a/src/Widgets/SearchBar.vala b/src/Widgets/SearchBar.vala index 645ed19999..4c1130ab3e 100644 --- a/src/Widgets/SearchBar.vala +++ b/src/Widgets/SearchBar.vala @@ -191,17 +191,33 @@ namespace Scratch.Widgets { // Connecting to some signals search_entry.changed.connect (on_search_entry_text_changed); - search_entry.key_press_event.connect (on_search_entry_key_press); - search_entry.focus_in_event.connect (on_search_entry_focused_in); search_entry.search_changed.connect (update_search_widgets); search_entry.icon_release.connect ((p0, p1) => { if (p0 == Gtk.EntryIconPosition.PRIMARY) { search_next (); } }); + + // search_entry.key_press_event.connect (on_search_entry_key_press); + // search_entry.focus_in_event.connect (on_search_entry_focused_in); + + var search_key_controller = new Gtk.EventControllerKey () { + propagation_phase = CAPTURE + }; + search_entry.add_controller (search_key_controller); + search_key_controller.key_pressed.connect (on_search_entry_key_press); + replace_entry.activate.connect (on_replace_entry_activate); - replace_entry.key_press_event.connect (on_replace_entry_key_press); + search_replace_entry.key_press_event.connect (on_replace_entry_key_press); + var replace_key_controller = new Gtk.EventControllerKey () { + propagation_phase = CAPTURE + }; + replace_entry.add_controller (replace_key_controller); + replace_key_controller.key_pressed.connect (on_replace_entry_key_press); + var focus_controller = new Gtk.EventControllerFocus (); + add_controller (focus_controller); + focus_controller.enter.connect (on_search_entry_focused_in); var entry_path = new Gtk.WidgetPath (); entry_path.append_type (typeof (Gtk.Widget)); @@ -340,13 +356,12 @@ namespace Scratch.Widgets { } } - private bool on_search_entry_focused_in (Gdk.EventFocus event) { + private void on_search_entry_focused_in () { if (text_buffer == null) { - return false; + return; } update_search_widgets (); - return false; } public bool search () { @@ -477,13 +492,13 @@ namespace Scratch.Widgets { } } - private bool on_search_entry_key_press (Gdk.EventKey event) { + private bool on_search_entry_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { /* We don't need to perform search if there is nothing to search... */ if (search_entry.text == "") { - return false; + return Gdk.EVENT_PROPAGATE; } - string key = Gdk.keyval_name (event.keyval); + string key = Gdk.keyval_name (keyval); if (Gdk.ModifierType.SHIFT_MASK in event.state) { key = "" + key; } @@ -492,44 +507,44 @@ namespace Scratch.Widgets { case "Return": case "Up": search_previous (); - return true; + return Gdk.EVENT_STOP; case "Return": case "Down": search_next (); - return true; + return Gdk.EVENT_STOP; case "Tab": if (search_entry.is_focus) { replace_entry.grab_focus (); } - return true; + return Gdk.EVENT_STOP; } - return false; + return Gdk.EVENT_PROPAGATE; } - private bool on_replace_entry_key_press (Gdk.EventKey event) { + private bool on_replace_entry_key_press (uint keyval, uint keycode, Gdk.ModifierType state) { /* We don't need to perform search if there is nothing to search… */ if (search_entry.text == "") { - return false; + return Gdk.EVENT_PROPAGATE; } - switch (Gdk.keyval_name (event.keyval)) { + switch (Gdk.keyval_name (keyval)) { case "Up": search_previous (); - return true; + return Gdk.EVENT_STOP; case "Down": search_next (); - return true; + return Gdk.EVENT_STOP; case "Tab": if (replace_entry.is_focus) { search_entry.grab_focus (); } - return true; + return Gdk.EVENT_STOP; } - return false; + return Gdk.EVENT_PROPAGATE; } private void cancel_update_search_widgets () { diff --git a/src/Widgets/SourceList/CellRendererIcon.vala b/src/Widgets/SourceList/CellRendererIcon.vala new file mode 100644 index 0000000000..d41693c22b --- /dev/null +++ b/src/Widgets/SourceList/CellRendererIcon.vala @@ -0,0 +1,31 @@ + +/** + * Class responsible for rendering Item.icon and Item.activatable. It also + * notifies about clicks through the activated() signal. + */ +private class CellRendererIcon : Gtk.CellRendererPixbuf { + public signal void activated (string path); + + private const Gtk.IconSize ICON_SIZE = Gtk.IconSize.MENU; + + public CellRendererIcon () { + + } + + construct { + mode = Gtk.CellRendererMode.ACTIVATABLE; + stock_size = ICON_SIZE; + } + + public override bool activate ( + Gdk.Event event, + Gtk.Widget widget, + string path, + Gdk.Rectangle background_area, + Gdk.Rectangle cell_area, + Gtk.CellRendererState flags + ) { + activated (path); + return true; + } +} diff --git a/src/Widgets/SourceList/CellRendererSpacer.vala b/src/Widgets/SourceList/CellRendererSpacer.vala new file mode 100644 index 0000000000..6c90ef45d0 --- /dev/null +++ b/src/Widgets/SourceList/CellRendererSpacer.vala @@ -0,0 +1,36 @@ +/** + * A cell renderer that only adds space. + */ +private class CellRendererSpacer : Gtk.CellRenderer { + /** + * Indentation level represented by this cell renderer + */ + public int level { get; set; default = -1; } + + public override Gtk.SizeRequestMode get_request_mode () { + return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH; + } + + public override void get_preferred_width (Gtk.Widget widget, out int min_size, out int natural_size) { + min_size = natural_size = 2 * (int) xpad; + } + + public override void get_preferred_height_for_width ( + Gtk.Widget widget, + int width, + out int min_height, + out int natural_height + ) { + min_height = natural_height = 2 * (int) ypad; + } + + public override void render ( + Cairo.Context context, + Gtk.Widget widget, + Gdk.Rectangle bg_area, + Gdk.Rectangle cell_area, + Gtk.CellRendererState flags + ) { + // Nothing to do. This renderer only adds space. + } +} diff --git a/src/Widgets/SourceList/SourceList.vala b/src/Widgets/SourceList/SourceList.vala index 24fde8049a..104d5c70cf 100644 --- a/src/Widgets/SourceList/SourceList.vala +++ b/src/Widgets/SourceList/SourceList.vala @@ -4,2585 +4,150 @@ * SPDX-License-Identifier: LGPL-3.0-or-later */ -namespace Code.Widgets { - -/** - * An interface for sorting items. - * - * @since 0.3 - */ -public interface SourceListSortable : SourceList.ExpandableItem { - /** - * Emitted after a user has re-ordered an item via DnD. - * - * @param moved The item that was moved to a different position by the user. - * @since 0.3 - */ - public signal void user_moved_item (SourceList.Item moved); - - /** - * Whether this item will allow users to re-arrange its children via DnD. - * - * This feature can co-exist with a sort algorithm (implemented - * by {@link Code.Widgets.SourceListSortable.compare}), but - * the actual order of the items in the list will always - * honor that method. The sort function has to be compatible with - * the kind of DnD reordering the item wants to allow, since the user can - * only reorder those items for which //compare// returns 0. - * - * @return Whether the item's children can be re-arranged by users. - * @since 0.3 - */ - public abstract bool allow_dnd_sorting (); - - /** - * Should return a negative integer, zero, or a positive integer if ''a'' - * sorts //before// ''b'', ''a'' sorts //with// ''b'', or ''a'' sorts - * //after// ''b'' respectively. If two items compare as equal, their - * order in the sorted source list is undefined. - * - * In order to ensure that the source list behaves as expected, this - * method must define a partial order on the source list tree; i.e. it - * must be reflexive, antisymmetric and transitive. Not complying with - * those requirements could make the program fall into an infinite loop - * and freeze the user interface. - * - * Should return //0// to allow any pair of items to be sortable via DnD. - * - * @param a First item. - * @param b Second item. - * @return A //negative// integer if //a// sorts before //b//, - * //zero// if //a// equals //b//, or a //positive// - * integer if //a// sorts after //b//. - * @since 0.3 - */ - public abstract int compare (SourceList.Item a, SourceList.Item b); -} - -/** - * An interface for dragging items out of the source list widget. - * - * @since 0.3 - */ -public interface SourceListDragSource : SourceList.Item { - /** - * Determines whether this item can be dragged outside the source list widget. - * - * Even if this method returns //false//, the item could still be dragged around - * within the source list if its parent allows DnD reordering. This only happens - * when the parent implements {@link Code.Widgets.SourceListSortable}. - * - * @return //true// if the item can be dragged; //false// otherwise. - * @since 0.3 - * @see Code.Widgets.SourceListSortable - */ - public abstract bool draggable (); - - /** - * This method is called when the drop site requests the data which is dragged. - * - * It is the responsibility of this method to fill //selection_data// with the - * data in the format which is indicated by {@link Gtk.SelectionData.get_target}. - * - * @param selection_data {@link Gtk.SelectionData} containing source data. - * @since 0.3 - * @see Gtk.SelectionData.set - * @see Gtk.SelectionData.set_uris - * @see Gtk.SelectionData.set_text - */ - public abstract void prepare_selection_data (Gtk.SelectionData selection_data); -} - -/** - * An interface for receiving data from other widgets via drag-and-drop. - * - * @since 0.3 - */ -public interface SourceListDragDest : SourceList.Item { - /** - * Determines whether //data// can be dropped into this item. - * - * @param context The drag context. - * @param data {@link Gtk.SelectionData} containing source data. - * @return //true// if the drop is possible; //false// otherwise. - * @since 0.3 - */ - public abstract bool data_drop_possible (Gdk.Drag drag, Gtk.SelectionData data); - - /** - * If a data drop is deemed possible, then this method is called - * when the data is actually dropped into this item. Any actions - * consequence of the data received should be handled here. - * - * @param context The drag context. - * @param data {@link Gtk.SelectionData} containing source data. - * @return The action taken, or //0// to indicate that the dropped data was not accepted. - * @since 0.3 - */ - public abstract Gdk.DragAction data_received (Gdk.Drag drag, Gtk.SelectionData data); -} - -/** - * A widget that can display a list of items organized in categories. - * - * The source list widget consists of a collection of items, some of which are also expandable (and - * thus can contain more items). All the items displayed in the source list are children of the widget's - * root item. The API is meant to be used as follows: - * - * 1. Create the items you want to display in the source list, setting the appropriate values for their - * properties. The desired hierarchy is achieved by creating expandable items and adding items to them. - * These will be displayed as descendants in the widget's tree structure. The expandable items that are - * not nested inside any other item are considered to be at root level, and should be added to - * the widget's root item.<
> - * - * Expandable items located at the root level are treated as categories, and only support text. - * - * ''Example''<
> - * The final tree will have the following structure: - * {{{ - * Libraries - * Music - * Stores - * My Store - * Music - * Podcasts - * Devices - * Player 1 - * Player 2 - * }}} - * - * {{{ - * var library_category = new Code.Widgets.SourceList.ExpandableItem ("Libraries"); - * var store_category = new Code.Widgets.SourceList.ExpandableItem ("Stores"); - * var device_category = new Code.Widgets.SourceList.ExpandableItem ("Devices"); - * - * var music_item = new Code.Widgets.SourceList.Item ("Music"); - * - * // "Libraries" will be the parent category of "Music" - * library_category.add (music_item); - * - * // We plan to add sub-items to the store, so let's use an expandable item - * var my_store_item = new Code.Widgets.SourceList.ExpandableItem ("My Store"); - * store_category.add (my_store_item); - * - * var my_store_podcast_item = new Code.Widgets.SourceList.Item ("Podcasts"); - * var my_store_music_item = new Code.Widgets.SourceList.Item ("Music"); - * - * my_store_item.add (my_store_music_item); - * my_store_item.add (my_store_podcast_item); - * - * var player1_item = new Code.Widgets.SourceList.Item ("Player 1"); - * var player2_item = new Code.Widgets.SourceList.Item ("Player 2"); - * - * device_category.add (player1_item); - * device_category.add (player2_item); - * }}} - * - * 2. Create a source list widget.<
> - * {{{ - * var source_list = new Code.Widgets.SourceList (); - * }}} - * - * 3. Add root-level items to the {@link Code.Widgets.SourceList.root} item. - * This item only serves as a container, and all its properties are ignored by the widget. - * - * {{{ - * // This will add the main categories (including their children) to the source list. After - * // having being added to be widget, any other item added to any of these items - * // (or any other child item in a deeper level) will be automatically added too. - * // There's no need to deal with the source list widget directly. - * - * var root = source_list.root; - * - * root.add (library_category); - * root.add (store_category); - * root.add (device_category); - * }}} - * - * The steps mentioned above are enough for initializing the source list. Future changes to the items' - * properties are ''automatically'' reflected by the widget. - * - * Final steps would involve connecting handlers to the source list events, being - * {@link Code.Widgets.SourceList.item_selected} the most important, as it indicates that - * the selection was modified. - * - * Pack the source list into the GUI using the {@link Gtk.Paned} widget. - * This is usually done as follows: - * {{{ - * var pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); - * pane.pack1 (source_list, false, false); - * pane.pack2 (content_area, true, false); - * }}} - * - * @since 0.2 - * @see Gtk.Paned - */ -public class SourceList : Gtk.ScrolledWindow { - - /** - * = WORKING INTERNALS = - * - * In order to offer a transparent Item-based API, and avoid the need of providing methods - * to deal with items directly on the SourceList widget, it was decided to follow a monitor-like - * implementation, where the source list permanently monitors its root item and any other - * child item added to it. The task of monitoring the properties of the items has been - * divided among different objects, as shown below: - * - * Monitored by: Object::method that receives the signals indicating the property change. - * Applied by: Object::method that actually updates the tree to reflect the property changes - * (directly or indirectly, as in the case of the tree data model). - * - * --------------------------------------------------------------------------------------------- - * PROPERTY | MONITORED BY | APPLIED BY - * --------------------------------------------------------------------------------------------- - * + Item | | - * - parent | Not monitored | N/A - * - name | DataModel::on_item_prop_changed | Tree::name_cell_data_func - * - editable | DataModel::on_item_prop_changed | Queried when needed (See Tree::start_editing_item) - * - visible | DataModel::on_item_prop_changed | DataModel::filter_visible_func - * - icon | DataModel::on_item_prop_changed | Tree::icon_cell_data_func - * - activatable | Same as @icon | Same as @icon - * + ExpandableItem | | - * - collapsible | DataModel::on_item_prop_changed | Tree::update_expansion - * | | Tree::expander_cell_data_func - * - expanded | Same as @collapsible | Same as @collapsible - * --------------------------------------------------------------------------------------------- - * * Only automatic properties are monitored. ExpandableItem's additions/removals are handled by - * DataModel::add_item() and DataModel::remove_item() - * - * Other features: - * - Sorting: this happens on the tree-model level (DataModel). - */ - - - - /** - * A source list entry. - * - * Any change made to any of its properties will be ''automatically'' reflected - * by the {@link Code.Widgets.SourceList} widget. - * - * @since 0.2 - */ - public class Item : Object { - - /** - * Emitted when the user has finished editing the item's name. - * - * By default, if the name doesn't consist of white space, it is automatically assigned - * to the {@link Code.Widgets.SourceList.Item.name} property. The default behavior can - * be changed by overriding this signal. - * @param new_name The item's new name (result of editing.) - * @since 0.2 - */ - public virtual signal void edited (string new_name) { - if (editable && new_name.strip () != "") - this.name = new_name; - } - - /** - * The {@link Code.Widgets.SourceList.Item.activatable} icon was activated. - * - * @see Code.Widgets.SourceList.Item.activatable - * @since 0.2 - */ - public virtual signal void action_activated () { } - - /** - * Emitted when the item is double-clicked or when it is selected and one of the keys: - * Space, Shift+Space, Return or Enter is pressed. This signal is //also// for - * editable items. - * - * @since 0.2 - */ - public virtual signal void activated () { } - - /** - * Parent {@link Code.Widgets.SourceList.ExpandableItem} of the item. - * ''Must not'' be modified. - * - * @since 0.2 - */ - public ExpandableItem parent { get; internal set; } - - /** - * The item's name. Primary and most important information. - * - * @since 0.2 - */ - public string name { get; set; default = ""; } - - /** - * The item's tooltip. If set to null (default), the tooltip for the item will be the - * contents of the {@link Code.Widgets.SourceList.Item.name} property. - * - * @since 5.3 - */ - public string? tooltip { get; set; default = null; } - - /** - * Markup to be used instead of {@link Code.Widgets.SourceList.ExpandableItem.name} - * This would mean that &, <, etc have to be escaped in the text, but basic formatting - * can be done on the item with HTML style tags. - * - * Note: Only the {@link Code.Widgets.SourceList.ExpandableItem.name} property - * is modified for editable items. So this property will be need to updated and - * reformatted with editable items. - * - * @since 5.0 - */ - public string? markup { get; set; default = null; } - - /** - * A badge shown next to the item's name. - * - * It can be used for displaying the number of unread messages in the "Inbox" item, - * for instance. - * - * @since 0.2 - */ - public string badge { get; set; default = ""; } - - /** - * Whether the item's name can be edited from within the source list. - * - * When this property is set to //true//, users can edit the item by pressing - * the F2 key, or by double-clicking its name. - * - * ''This property only works for selectable items''. - * - * @see Code.Widgets.SourceList.Item.selectable - * @see Code.Widgets.SourceList.start_editing_item - * @since 0.2 - */ - public bool editable { get; set; default = false; } - - /** - * Whether the item should appear in the source list's tree or not. - * - * @since 0.2 - */ - public bool visible { get; set; default = true; } - - /** - * Whether the item can be selected or not. - * - * Setting this property to true doesn't guarantee that the item will actually be - * selectable, since there are other external factors to take into account, like the - * item's {@link Code.Widgets.SourceList.Item.visible} property; whether the item is - * a category; the parent item is collapsed, etc. - * - * @see Code.Widgets.SourceList.Item.visible - * @since 0.2 - */ - public bool selectable { get; set; default = true; } - - /** - * Primary icon. - * - * This property should be used to give the user an idea of what the item represents - * (i.e. content type.) - * - * @since 0.2 - */ - public Icon icon { get; set; } - - /** - * An activatable icon that works like a button. - * - * It can be used for e.g. showing an //"eject"// icon on a device's item. - * - * @see Code.Widgets.SourceList.Item.action_activated - * @since 0.2 - */ - public Icon activatable { get; set; } - - /** - * The tooltip for the activatable icon. - * - * @since 5.0 - */ - public string activatable_tooltip { get; set; default = ""; } - - /** - * Creates a new {@link Code.Widgets.SourceList.Item}. - * - * @param name Name of the item. - * @return (transfer full) A new {@link Code.Widgets.SourceList.Item}. - * @since 0.2 - */ - public Item (string name = "") { - this.name = name; - } - - /** - * Invoked when the item is secondary-clicked or when the usual menu keys are pressed. - * - * Note that since Granite 5.0, right clicking on an item no longer selects/activates it, so - * any context menu items should be actioned on the item instance rather than the selected item - * in the SourceList - * - * @return A {@link Gtk.Menu} or //null// if nothing should be displayed. - * @since 0.2 - */ - public virtual GLib.Menu? get_context_menu () { - return null; - } - } - - - - /** - * An item that can contain more items. - * - * It supports all the properties inherited from {@link Code.Widgets.SourceList.Item}, - * and behaves like a normal item, except when it is located at the root level; in that case, - * the following properties are ignored by the widget: - * - * * {@link Code.Widgets.SourceList.Item.selectable} - * * {@link Code.Widgets.SourceList.Item.editable} - * * {@link Code.Widgets.SourceList.Item.icon} - * * {@link Code.Widgets.SourceList.Item.activatable} - * * {@link Code.Widgets.SourceList.Item.badge} - * - * Root-level expandable items (i.e. Main Categories) are ''not'' displayed when they contain - * zero visible children. - * - * @since 0.2 - */ - public class ExpandableItem : Item { - - /** - * Emitted when an item is added. - * - * @param item Item added. - * @see Code.Widgets.SourceList.ExpandableItem.add - * @since 0.2 - */ - public signal void child_added (Item item); - - /** - * Emitted when an item is removed. - * - * @param item Item removed. - * @see Code.Widgets.SourceList.ExpandableItem.remove - * @since 0.2 - */ - public signal void child_removed (Item item); - - /** - * Emitted when the item is expanded or collapsed. - * - * @since 0.2 - */ - public virtual signal void toggled () { } - - /** - * Whether the item is collapsible or not. - * - * When set to //false//, the item is //always// expanded and the expander is - * not shown. Please note that this will also affect the value returned by the - * {@link Code.Widgets.SourceList.ExpandableItem.expanded} property. - * - * @see Code.Widgets.SourceList.ExpandableItem.expanded - * @since 0.2 - */ - public bool collapsible { get; set; default = true; } - - /** - * Whether the item is expanded or not. - * - * The source list widget will obey the value of this property when possible. - * - * This property has no effect when {@link Code.Widgets.SourceList.ExpandableItem.collapsible} - * is set to //false//. Also keep in mind that, __when set to //true//__, this property - * doesn't always represent the actual expansion state of an item. For example, it might - * be the case that an expandable item is collapsed because it has zero visible children, - * but its //expanded// property value is still //true//; in such case, once one of the - * item's children becomes visible, the item will be expanded again. Same applies to items - * hidden behind a collapsed parent item. - * - * If obtaining the ''actual'' expansion state of an item is important, - * use {@link Code.Widgets.SourceList.is_item_expanded} instead. - * - * @see Code.Widgets.SourceList.ExpandableItem.collapsible - * @see Code.Widgets.SourceList.is_item_expanded - * @since 0.2 - */ - private bool _expanded = false; - public bool expanded { - get { return _expanded || !collapsible; } // if not collapsible, always return true - set { - if (value != _expanded) { - _expanded = value; - toggled (); - } - } - } - - /** - * Number of children contained by the item. - * - * @since 0.2 - */ - public uint n_children { - get { return children_list.size; } - } - - /** - * The item's children. - * - * This returns a newly-created list containing the children. - * It's safe to iterate it while removing items with - * {@link Code.Widgets.SourceList.ExpandableItem.remove} - * - * @since 0.2 - */ - public Gee.Collection children { - owned get { - // Create a copy of the children so that it's safe to iterate it - // (e.g. by using foreach) while removing items. - var children_list_copy = new Gee.ArrayList (); - children_list_copy.add_all (children_list); - return children_list_copy; - } - } - - private Gee.Collection children_list = new Gee.ArrayList (); - - /** - * Creates a new {@link Code.Widgets.SourceList.ExpandableItem} - * - * @param name Title of the item. - * @return (transfer full) A new {@link Code.Widgets.SourceList.ExpandableItem}. - * @since 0.2 - */ - public ExpandableItem (string name = "") { - base (name); - } - - construct { - editable = false; - } - - /** - * Checks whether the item contains the specified child. - * - * This method only considers the item's immediate children. - * - * @param item Item to search. - * @return Whether the item was found or not. - * @since 0.2 - */ - public bool contains (Item item) { - return item in children_list; - } - - /** - * Adds an item. - * - * {@link Code.Widgets.SourceList.ExpandableItem.child_added} is fired after the item is added. - * - * While adding a child item, //the item it's being added to will set itself as the parent//. - * Please note that items are required to have their //parent// property set to //null// before - * being added, so make sure the item is removed from its previous parent before attempting - * to add it to another item. For instance: - * {{{ - * if (item.parent != null) - * item.parent.remove (item); // this will set item's parent to null - * new_parent.add (item); - * }}} - * - * @param item The item to add. Its parent __must__ be //null//. - * @see Code.Widgets.SourceList.ExpandableItem.child_added - * @see Code.Widgets.SourceList.ExpandableItem.remove - * @since 0.2 - */ - public void add (Item item) requires (item.parent == null) { - item.parent = this; - children_list.add (item); - child_added (item); - } - - /** - * Removes an item. - * - * The {@link Code.Widgets.SourceList.ExpandableItem.child_removed} signal is fired - * //after removing the item//. Finally (i.e. after all the handlers have been invoked), - * the item's {@link Code.Widgets.SourceList.Item.parent} property is set to //null//. - * This has the advantage of letting signal handlers know the parent from which //item// - * is being removed. - * - * @param item The item to remove. This will fail if item has a different parent. - * @see Code.Widgets.SourceList.ExpandableItem.child_removed - * @see Code.Widgets.SourceList.ExpandableItem.clear - * @since 0.2 - */ - public void remove (Item item) requires (item.parent == this) { - children_list.remove (item); - child_removed (item); - item.parent = null; - } - - /** - * Removes all the items contained by the item. It works similarly to - * {@link Code.Widgets.SourceList.ExpandableItem.remove}. - * - * @see Code.Widgets.SourceList.ExpandableItem.remove - * @see Code.Widgets.SourceList.ExpandableItem.child_removed - * @since 0.2 - */ - public void clear () { - foreach (var item in children) - remove (item); - } - - /** - * Expands the item and/or its children. - * - * @param inclusive Whether to also expand this item (true), or only its children (false). - * @param recursive Whether to recursively expand all the children (true), or only - * immediate children (false). - * @see Code.Widgets.SourceList.ExpandableItem.expanded - * @since 0.2 - */ - public void expand_all (bool inclusive = true, bool recursive = true) { - set_expansion (this, inclusive, recursive, true); - } - - /** - * Collapses the item and/or its children. - * - * @param inclusive Whether to also collapse this item (true), or only its children (false). - * @param recursive Whether to recursively collapse all the children (true), or only - * immediate children (false). - * @see Code.Widgets.SourceList.ExpandableItem.expanded - * @since 0.2 - */ - public void collapse_all (bool inclusive = true, bool recursive = true) { - set_expansion (this, inclusive, recursive, false); - } - - private static void set_expansion (ExpandableItem item, bool inclusive, bool recursive, bool expanded) { - if (inclusive) - item.expanded = expanded; - - foreach (var child_item in item.children) { - var child_expandable_item = child_item as ExpandableItem; - if (child_expandable_item != null) { - if (recursive) - set_expansion (child_expandable_item, true, true, expanded); - else - child_expandable_item.expanded = expanded; - } - } - } - - /** - * Recursively expands the item along with its parent(s). - * - * @see Code.Widgets.SourceList.ExpandableItem.expanded - * @since 0.2 - */ - public void expand_with_parents () { - // Update parent items first due to GtkTreeView's working internals: - // Expanding children before their parents would not always work, because - // they could be obscured behind a collapsed row by the time the treeview - // tries to expand them, obviously failing. - if (parent != null) - parent.expand_with_parents (); - expanded = true; - } - - /** - * Recursively collapses the item along with its parent(s). - * - * @see Code.Widgets.SourceList.ExpandableItem.expanded - * @since 0.2 - */ - public void collapse_with_parents () { - if (parent != null) - parent.collapse_with_parents (); - expanded = false; - } - } - - - - /** - * The model backing the SourceList tree. - * - * It monitors item property changes, and handles children additions and removals. It also controls - * the visibility of the items based on their "visible" property, and on their number of children, - * if they happen to be categories. Its main purpose is to provide an easy and practical interface - * for sorting, adding, removing and updating items, eliminating the need of repeatedly dealing with - * the Gtk.TreeModel API directly. - */ - private class DataModel : Gtk.TreeModelFilter, Gtk.TreeDragSource, Gtk.TreeDragDest { - - /** - * An object that references a particular row in a model. This class is a wrapper built around - * Gtk.TreeRowReference, and exists with the purpose of ensuring we never use invalid tree paths - * or iters in the model, since most of these errors provoke failures due to GTK+ assertions - * or, even worse, unexpected behavior. - */ - private class NodeWrapper { - - /** - * The actual reference to the node. If is is null, it is treated as invalid. - */ - private Gtk.TreeRowReference? row_reference; - - /** - * A newly-created Gtk.TreeIter pointing to the node if it exists; null otherwise. - */ - public Gtk.TreeIter? iter { - owned get { - Gtk.TreeIter? rv = null; - - if (valid) { - var _path = this.path; - if (_path != null) { - Gtk.TreeIter _iter; - if (row_reference.get_model ().get_iter (out _iter, _path)) - rv = _iter; - } - } - - return rv; - } - } - - /** - * A newly-created Gtk.TreePath pointing to the node if it exists; null otherwise. - */ - public Gtk.TreePath? path { - owned get { return valid ? row_reference.get_path () : null; } - } - - /** - * Whether the node is valid or not. When it is not valid, no valid references are - * returned by the object to avoid errors (null is returned instead). - */ - public bool valid { - get { return row_reference != null && row_reference.valid (); } - } - - public NodeWrapper (Gtk.TreeModel model, Gtk.TreeIter iter) { - row_reference = new Gtk.TreeRowReference (model, model.get_path (iter)); - } - } - - /** - * Helper object used to monitor item property changes. - */ - private class ItemMonitor { - public signal void changed (Item self, string prop_name); - private Item item; - - public ItemMonitor (Item item) { - this.item = item; - item.notify.connect_after (on_notify); - } - - ~ItemMonitor () { - item.notify.disconnect (on_notify); - } - - private void on_notify (ParamSpec prop) { - changed (item, prop.name); - } - } - - private enum Column { - ITEM, - N_COLUMNS; - - public Type type () { - switch (this) { - case ITEM: - return typeof (Item); - - default: - assert_not_reached (); // a Type must be returned for every valid column - } - } - } - - public signal void item_updated (Item item); - - /** - * Used by push_parent_update() as key to associate the respective data to the objects. - */ - private const string ITEM_PARENT_NEEDS_UPDATE = "item-parent-needs-update"; - - private ExpandableItem _root; - - /** - * Root item. - * - * This item is not actually part of the model. It's only used as a proxy - * for adding and removing items. - */ - public ExpandableItem root { - get { return _root; } - set { - if (_root != null) { - remove_children_monitor (_root); - foreach (var item in _root.children) - remove_item (item); - } - - _root = value; - - add_children_monitor (_root); - foreach (var item in _root.children) - add_item (item); - } - } - - // This hash map stores items and their respective child node references. For that reason, the - // references it contains should only be used on the child_tree model, or converted to filter - // iters/paths using convert_child_*_to_*() before using them with the filter (i.e. this) model. - private Gee.HashMap items = new Gee.HashMap (); - - private Gee.HashMap monitors = new Gee.HashMap (); - - private Gtk.TreeStore child_tree; - private unowned SourceList.VisibleFunc? filter_func; - - public DataModel () { - - } - - construct { - child_tree = new Gtk.TreeStore (Column.N_COLUMNS, Column.ITEM.type ()); - child_model = child_tree; - virtual_root = null; - - child_tree.set_default_sort_func (child_model_sort_func); - resort (); - - set_visible_func (filter_visible_func); - } - - public bool has_item (Item item) { - return items.has_key (item); - } - - public void update_item (Item item) requires (has_item (item)) { - assert (root != null); - - // Emitting row_changed() for this item's row in the child model causes the filter - // (i.e. this model) to re-evaluate whether a row is visible or not, calling - // filter_visible_func() for that row again, and that's exactly what we want. - var node_reference = items.get (item); - if (node_reference != null) { - var path = node_reference.path; - var iter = node_reference.iter; - if (path != null && iter != null) { - child_tree.row_changed (path, iter); - item_updated (item); - } - } - } - - private void add_item (Item item) requires (!has_item (item)) { - assert (root != null); - - // Find the parent iter - Gtk.TreeIter? parent_child_iter = null, child_iter; - var parent = item.parent; - - if (parent != null && parent != root) { - // Add parent if it hasn't been added yet - if (!has_item (parent)) - add_item (parent); - - // Try to find the parent's iter - parent_child_iter = get_item_child_iter (parent); - - // Parent must have been added prior to adding this item - assert (parent_child_iter != null); - } - - child_tree.append (out child_iter, parent_child_iter); - child_tree.set (child_iter, Column.ITEM, item, -1); - - items.set (item, new NodeWrapper (child_tree, child_iter)); - - // This is equivalent to a property change. The tree still needs to update - // some of the new item's properties through this signal's handler. - item_updated (item); - - add_property_monitor (item); - - push_parent_update (parent); - - // If the item is expandable, also add children - var expandable = item as ExpandableItem; - if (expandable != null) { - foreach (var child_item in expandable.children) - add_item (child_item); - - // Monitor future additions/removals through signal handlers - add_children_monitor (expandable); - } - } - - private void remove_item (Item item) requires (has_item (item)) { - assert (root != null); - - remove_property_monitor (item); - - // get_item_child_iter() depends on items.get(item) for retrieving the right reference, - // so don't unset the item from @items yet! We first get the child iter and then - // unset the value. - var child_iter = get_item_child_iter (item); - - // Now we remove the item from the table, because that way get_item_child_iter() and - // all the methods that depend on it won't return invalid iters or items when - // called. This is important because child_tree.remove() will emit row_deleted(), - // and its handlers could potentially depend on one of the methods mentioned above. - items.unset (item); - - if (child_iter != null) - child_tree.remove (ref child_iter); - - push_parent_update (item.parent); - - // If the item is expandable, also remove children - var expandable = item as ExpandableItem; - if (expandable != null) { - // No longer monitor future additions or removals - remove_children_monitor (expandable); - - foreach (var child_item in expandable.children) - remove_item (child_item); - } - } - - private void add_property_monitor (Item item) { - var wrapper = new ItemMonitor (item); - monitors[item] = wrapper; - wrapper.changed.connect (on_item_prop_changed); - } - - private void remove_property_monitor (Item item) { - var wrapper = monitors[item]; - if (wrapper != null) - wrapper.changed.disconnect (on_item_prop_changed); - monitors.unset (item); - } - - private void add_children_monitor (ExpandableItem item) { - item.child_added.connect_after (on_item_child_added); - item.child_removed.connect_after (on_item_child_removed); - } - - private void remove_children_monitor (ExpandableItem item) { - item.child_added.disconnect (on_item_child_added); - item.child_removed.disconnect (on_item_child_removed); - } - - private void on_item_child_added (Item item) { - add_item (item); - } - - private void on_item_child_removed (Item item) { - remove_item (item); - } - - private void on_item_prop_changed (Item item, string prop_name) { - if (prop_name != "parent") - update_item (item); - } - - /** - * Pushes a call to update_item() if //parent// is not //null//. - * - * This is needed because the visibility of categories depends on their n_children property, - * and also because item expansion should be updated after adding or removing items. - * If many updates are pushed, and the item has still not been updated, only one is processed. - * This guarantees efficiency as updating a category item could trigger expensive actions. - */ - private void push_parent_update (ExpandableItem? parent) { - if (parent == null) - return; - - bool needs_update = parent.get_data (ITEM_PARENT_NEEDS_UPDATE); - - // If an update is already waiting to be processed, just return, as we - // don't need to queue another one for the same item. - if (needs_update) - return; - - var path = get_item_path (parent); - - if (path != null) { - // Let's mark this item for update - parent.set_data (ITEM_PARENT_NEEDS_UPDATE, true); - - Idle.add (() => { - if (parent != null) { - update_item (parent); - - // Already updated. No longer needs an update. - parent.set_data (ITEM_PARENT_NEEDS_UPDATE, false); - } - - return false; - }); - } - } - - /** - * Returns the Item pointed by iter, or null if the iter doesn't refer to a valid item. - */ - public Item? get_item (Gtk.TreeIter iter) { - Item? item; - get (iter, Column.ITEM, out item, -1); - return item; - } - - /** - * Returns the Item pointed by path, or null if the path doesn't refer to a valid item. - */ - public Item? get_item_from_path (Gtk.TreePath path) { - Gtk.TreeIter iter; - if (get_iter (out iter, path)) - return get_item (iter); - - return null; - } - - /** - * Returns a newly-created path pointing to the item, or null in case a valid path - * is not found. - */ - public Gtk.TreePath? get_item_path (Item item) { - Gtk.TreePath? path = null, child_path = get_item_child_path (item); - - // We want a filter path, not a child_model path - if (child_path != null) - path = convert_child_path_to_path (child_path); - - return path; - } - - /** - * Returns a newly-created iterator pointing to the item, or null in case a valid iter - * was not found. - */ - public Gtk.TreeIter? get_item_iter (Item item) { - var child_iter = get_item_child_iter (item); - - if (child_iter != null) { - Gtk.TreeIter iter; - if (convert_child_iter_to_iter (out iter, child_iter)) - return iter; - } - - return null; - } - - /** - * External "extra" filter method. - */ - public void set_filter_func (SourceList.VisibleFunc? visible_func) { - this.filter_func = visible_func; - } - - /** - * Checks whether an item is a category (i.e. a root-level expandable item). - * The caller must pass an iter or path pointing to the item, but not both - * (one of them must be null.) - * - * TODO: instead of checking the position of the iter or path, we should simply - * check whether the item's parent is the root item and whether the item is - * expandable. We don't do so right now because vala still allows client code - * to access the Item.parent property, even though its setter is defined as internal. - */ - public bool is_category (Item item, Gtk.TreeIter? iter, Gtk.TreePath? path = null) { - bool is_category = false; - // either iter or path has to be null - if (item is ExpandableItem) { - if (iter != null) { - assert (path == null); - is_category = is_iter_at_root_level (iter); - } else { - assert (iter == null); - is_category = is_path_at_root_level (path); - } - } - return is_category; - } - - public bool is_iter_at_root_level (Gtk.TreeIter iter) { - return is_path_at_root_level (get_path (iter)); - } - - public bool is_path_at_root_level (Gtk.TreePath path) { - return path.get_depth () == 1; - } - - private void resort () { - child_tree.set_sort_column_id (Gtk.SortColumn.UNSORTED, Gtk.SortType.ASCENDING); - child_tree.set_sort_column_id (Gtk.SortColumn.DEFAULT, Gtk.SortType.ASCENDING); - } - - private int child_model_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { - int order = 0; - - Item? item_a, item_b; - child_tree.get (a, Column.ITEM, out item_a, -1); - child_tree.get (b, Column.ITEM, out item_b, -1); - - // code should only compare items at same hierarchy level - assert (item_a.parent == item_b.parent); - - var parent = item_a.parent as SourceListSortable; - if (parent != null) - order = parent.compare (item_a, item_b); - - return order; - } - - private Gtk.TreeIter? get_item_child_iter (Item item) { - Gtk.TreeIter? child_iter = null; - - var child_node_wrapper = items.get (item); - if (child_node_wrapper != null) - child_iter = child_node_wrapper.iter; - - return child_iter; - } - - private Gtk.TreePath? get_item_child_path (Item item) { - Gtk.TreePath? child_path = null; - - var child_node_wrapper = items.get (item); - if (child_node_wrapper != null) - child_path = child_node_wrapper.path; - - return child_path; - } - - /** - * Filters the child-tree items based on their "visible" property. - */ - private bool filter_visible_func (Gtk.TreeModel child_model, Gtk.TreeIter iter) { - bool item_visible = false; - - Item? item; - child_tree.get (iter, Column.ITEM, out item, -1); - - if (item != null) { - item_visible = item.visible; - - // If the item is a category, also query the number of visible children - // because empty categories should not be displayed. - var expandable = item as ExpandableItem; - if (expandable != null && child_tree.iter_depth (iter) == 0) { - uint n_visible_children = 0; - foreach (var child_item in expandable.children) { - if (child_item.visible) - n_visible_children++; - } - item_visible = item_visible && n_visible_children > 0; - } - } - - if (filter_func != null) - item_visible = item_visible && filter_func (item); - - return item_visible; - } - - /** - * TreeDragDest implementation - */ - - public bool drag_data_received (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - Gtk.TreeModel model; - Gtk.TreePath src_path; - - // Check if the user is dragging a row: - // - // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by - // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. - if (Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) && model == child_tree) { - // get a child path representation of dest - var child_dest = convert_path_to_child_path (dest); - - if (child_dest != null) { - // New GtkTreeIters will be assigned to the rows at child_dest and its children. - if (child_tree_drag_data_received (child_dest, src_path)) - return true; - } - } - - // no new row inserted - return false; - } - - private bool child_tree_drag_data_received (Gtk.TreePath dest, Gtk.TreePath src_path) { - bool retval = false; - Gtk.TreeIter src_iter, dest_iter; - - if (!child_tree.get_iter (out src_iter, src_path)) - return false; - - var prev = dest; - - // Get the path to insert _after_ (dest is the path to insert _before_) - if (!prev.prev ()) { - // dest was the first spot at the current depth; which means - // we are supposed to prepend. - - var parent = dest; - Gtk.TreeIter? dest_parent = null; - - if (parent.up () && parent.get_depth () > 0) - child_tree.get_iter (out dest_parent, parent); - - child_tree.prepend (out dest_iter, dest_parent); - retval = true; - } else if (child_tree.get_iter (out dest_iter, prev)) { - var tmp_iter = dest_iter; - child_tree.insert_after (out dest_iter, null, tmp_iter); - retval = true; - } - - // If we succeeded in creating dest_iter, walk src_iter tree branch, - // duplicating it below dest_iter. - if (retval) { - recursive_node_copy (src_iter, dest_iter); - - // notify that the item was moved - Item item; - child_tree.get (src_iter, Column.ITEM, out item, -1); - return_val_if_fail (item != null, retval); - - // XXX Workaround: - // GtkTreeView automatically collapses expanded items that - // are dragged to a new location. Oddly, GtkTreeView doesn't fire - // 'row-collapsed' for the respective path, so we cannot keep track - // of that behavior via standard means. For now we'll just have - // our tree view check the properties of item again and ensure - // they're honored - update_item (item); - - var parent = item.parent as SourceListSortable; - return_val_if_fail (parent != null, retval); - - parent.user_moved_item (item); - } - - return retval; - } - - private void recursive_node_copy (Gtk.TreeIter src_iter, Gtk.TreeIter dest_iter) { - move_item (src_iter, dest_iter); - - Gtk.TreeIter child; - if (child_tree.iter_children (out child, src_iter)) { - // Need to create children and recurse. Note our dependence on - // persistent iterators here. - do { - Gtk.TreeIter copy; - child_tree.append (out copy, dest_iter); - recursive_node_copy (child, copy); - } while (child_tree.iter_next (ref child)); - } - } - - private void move_item (Gtk.TreeIter src_iter, Gtk.TreeIter dest_iter) { - Item item; - child_tree.get (src_iter, Column.ITEM, out item, -1); - return_if_fail (item != null); - - // update the row reference of item with the new location - child_tree.set (dest_iter, Column.ITEM, item, -1); - items.set (item, new NodeWrapper (child_tree, dest_iter)); - } - - public bool row_drop_possible (Gtk.TreePath dest, Gtk.SelectionData selection_data) { - Gtk.TreeModel model; - Gtk.TreePath src_path; - - // Check if the user is dragging a row: - // Due to Gtk.TreeModelFilter's implementation of drag_data_get the values returned by - // tree_row_drag_data for GtkModel and GtkPath correspond to the child model and not the filter. - if (!Gtk.tree_get_row_drag_data (selection_data, out model, out src_path) || model != child_tree) - return false; - - // get a representation of dest in the child model - var child_dest = convert_path_to_child_path (dest); - - // don't allow dropping an item into itself - if (child_dest == null || src_path.compare (child_dest) == 0) - return false; - - // Only allow DnD between items at the same depth (indentation level) - // This doesn't mean their parent is the same. - int src_depth = src_path.get_depth (); - int dest_depth = child_dest.get_depth (); - - if (src_depth != dest_depth) - return false; - - // no need to check dest_depth since we know its equal to src_depth - if (src_depth < 1) - return false; - - Item? parent = null; - - // if the depth is 1, we're talking about the items at root level, - // and by definition they share the same parent (root). We don't - // need to verify anything else for that specific case - if (src_depth == 1) { - parent = root; - } else { - // we verified equality above. this must be true - assert (dest_depth > 1); - - // Only allow reordering between siblings, i.e. items with the same - // parent. We don't want items to change their parent through DnD - // because that would complicate our existing APIs, and may introduce - // unpredictable behavior. - var src_indices = src_path.get_indices (); - var dest_indices = child_dest.get_indices (); - - // parent index is given by indices[depth-2], where depth > 1 - int src_parent_index = src_indices[src_depth - 2]; - int dest_parent_index = dest_indices[dest_depth - 2]; - - if (src_parent_index != dest_parent_index) - return false; - - // get parent. Note that we don't use the child path for this - var dest_parent = dest; - - if (!dest_parent.up () || dest_parent.get_depth () < 1) - return false; - - parent = get_item_from_path (dest_parent); - } - - var sortable = parent as SourceListSortable; - - if (sortable == null || !sortable.allow_dnd_sorting ()) - return false; - - var dest_item = get_item_from_path (dest); - - if (dest_item == null) - return true; - - Item? source_item = null; - var filter_src_path = convert_child_path_to_path (src_path); - - if (filter_src_path != null) - source_item = get_item_from_path (filter_src_path); - - if (source_item == null) - return false; - - // If order isn't indifferent (=0), 'dest' has to sort before 'source'. - // Otherwise we'd allow the user to move the 'source_item' to a new - // location before 'dest_item', but that location would be changed - // later by the sort function, making the whole interaction poinless. - // We better prevent such reorderings from the start by giving the - // user a visual clue about the invalid drop location. - if (sortable.compare (dest_item, source_item) >= 0) { - if (!dest.prev ()) - return true; - - // 'source_item' also has to sort 'after' or 'equal' the item currently - // preceding 'dest_item' - var dest_item_prev = get_item_from_path (dest); - - return dest_item_prev != null - && dest_item_prev != source_item - && sortable.compare (dest_item_prev, source_item) <= 0; - } - - return false; - } - - /** - * Override default implementation of TreeDragSource - * - * drag_data_delete is not overriden because the default implementation - * does exactly what we need. - */ - - public bool drag_data_get (Gtk.TreePath path, Gtk.SelectionData selection_data) { - // If we're asked for a data about a row, just have the default implementation fill in - // selection_data. Please note that it will provide information relative to child_model. - if (selection_data.get_target () == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) - return base.drag_data_get (path, selection_data); - - // check if the item at path provides DnD source data - var drag_source_item = get_item_from_path (path) as SourceListDragSource; - if (drag_source_item != null && drag_source_item.draggable ()) { - drag_source_item.prepare_selection_data (selection_data); - return true; - } - - return false; - } - - public bool row_draggable (Gtk.TreePath path) { - if (!base.row_draggable (path)) - return false; - - var item = get_item_from_path (path); - - if (item != null) { - // check if the item's parent allows DnD sorting - var sortable_item = item.parent as SourceListSortable; - - if (sortable_item != null && sortable_item.allow_dnd_sorting ()) - return true; - - // Since the parent item does not allow DnD sorting, there's no - // reason to allow dragging it unless the row is actually draggable. - var drag_source_item = item as SourceListDragSource; - - if (drag_source_item != null && drag_source_item.draggable ()) - return true; - } - - return false; - } - } - - - /** - * Class responsible for rendering Item.icon and Item.activatable. It also - * notifies about clicks through the activated() signal. - */ - private class CellRendererIcon : Gtk.CellRendererPixbuf { - public signal void activated (string path); - - private const Gtk.IconSize ICON_SIZE = Gtk.IconSize.MENU; - - public CellRendererIcon () { - - } - - construct { - mode = Gtk.CellRendererMode.ACTIVATABLE; - stock_size = ICON_SIZE; - } - - public override bool activate ( - Gdk.Event event, - Gtk.Widget widget, - string path, - Gdk.Rectangle background_area, - Gdk.Rectangle cell_area, - Gtk.CellRendererState flags - ) { - activated (path); - return true; - } - } - - - - /** - * A cell renderer that only adds space. - */ - private class CellRendererSpacer : Gtk.CellRenderer { - /** - * Indentation level represented by this cell renderer - */ - public int level { get; set; default = -1; } - - public override Gtk.SizeRequestMode get_request_mode () { - return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH; - } - - public override void get_preferred_width (Gtk.Widget widget, out int min_size, out int natural_size) { - min_size = natural_size = 2 * (int) xpad; - } - - public override void get_preferred_height_for_width ( - Gtk.Widget widget, - int width, - out int min_height, - out int natural_height - ) { - min_height = natural_height = 2 * (int) ypad; - } - - public override void render ( - Cairo.Context context, - Gtk.Widget widget, - Gdk.Rectangle bg_area, - Gdk.Rectangle cell_area, - Gtk.CellRendererState flags - ) { - // Nothing to do. This renderer only adds space. - } - } - - - - /** - * The tree that actually displays the items. - * - * All the user interaction happens here. - */ - private class Tree : Gtk.TreeView { - - public DataModel data_model { get; construct set; } - - public signal void item_selected (Item? item); - - public Item? selected_item { - get { return selected; } - set { set_selected (value, true); } - } - - public bool editing { - get { return text_cell.editing; } - } - - public Pango.EllipsizeMode ellipsize_mode { - get { return text_cell.ellipsize; } - set { text_cell.ellipsize = value; } - } - - private enum Column { - ITEM, - N_COLS - } - - private Item? selected; - private unowned Item? edited; - - private Gtk.Entry? editable_entry; - private Gtk.CellRendererText text_cell; - private CellRendererIcon icon_cell; - private CellRendererIcon activatable_cell; - private CellRendererBadge badge_cell; - private CellRendererExpander primary_expander_cell; - private CellRendererExpander secondary_expander_cell; - private Gee.HashMap spacer_cells; // cells used for left spacing - private bool unselectable_item_clicked = false; - - private const string DEFAULT_STYLESHEET = """ - .sidebar.badge { - border-radius: 10px; - border-width: 0; - padding: 1px 2px 1px 2px; - font-weight: bold; - } - """; - - private const string STYLE_PROP_LEVEL_INDENTATION = "level-indentation"; - private const string STYLE_PROP_LEFT_PADDING = "left-padding"; - private const string STYLE_PROP_EXPANDER_SPACING = "expander-spacing"; - - static construct { - install_style_property (new ParamSpecInt ( - STYLE_PROP_LEVEL_INDENTATION, - "Level Indentation", - "Space to add at the beginning of every indentation level. Must be an even number.", - 1, - 50, - 6, - ParamFlags.READABLE - )); - - install_style_property (new ParamSpecInt ( - STYLE_PROP_LEFT_PADDING, - "Left Padding", - "Padding added to the left side of the tree. Must be an even number.", - 1, - 50, - 4, - ParamFlags.READABLE - )); - - install_style_property (new ParamSpecInt ( - STYLE_PROP_EXPANDER_SPACING, - "Expander Spacing", - "Space added between an item and its expander. Must be an even number.", - 1, - 50, - 4, - ParamFlags.READABLE - )); - } - - public Tree (DataModel data_model) { - Object (data_model: data_model); - } - - construct { - unowned Gtk.StyleContext style_context = get_style_context (); - style_context.add_class (Gtk.STYLE_CLASS_SIDEBAR); - style_context.add_class ("source-list"); - - var css_provider = new Gtk.CssProvider (); - try { - css_provider.load_from_data (DEFAULT_STYLESHEET, -1); - style_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); - } catch (Error e) { - warning ("Could not create CSS Provider: %s\nStylesheet:\n%s", e.message, DEFAULT_STYLESHEET); - } - - set_model (data_model); - - halign = valign = Gtk.Align.FILL; - expand = true; - - enable_search = false; - headers_visible = false; - enable_grid_lines = Gtk.TreeViewGridLines.NONE; - - // Deactivate GtkTreeView's built-in expander functionality - expander_column = null; - show_expanders = false; - - var item_column = new Gtk.TreeViewColumn (); - item_column.expand = true; - - insert_column (item_column, Column.ITEM); - - // Now pack the cell renderers. We insert them in reverse order (using pack_end) - // because we want to use TreeViewColumn.pack_start exclusively for inserting - // spacer cell renderers for level-indentation purposes. - // See add_spacer_cell_for_level() for more details. - - // Second expander. Used for main categories - secondary_expander_cell = new CellRendererExpander (); - secondary_expander_cell.is_category_expander = true; - secondary_expander_cell.xpad = 10; - item_column.pack_end (secondary_expander_cell, false); - item_column.set_cell_data_func (secondary_expander_cell, expander_cell_data_func); - - activatable_cell = new CellRendererIcon (); - activatable_cell.xpad = 6; - activatable_cell.activated.connect (on_activatable_activated); - item_column.pack_end (activatable_cell, false); - item_column.set_cell_data_func (activatable_cell, icon_cell_data_func); - - badge_cell = new CellRendererBadge (); - badge_cell.xpad = 1; - badge_cell.xalign = 1; - item_column.pack_end (badge_cell, false); - item_column.set_cell_data_func (badge_cell, badge_cell_data_func); - - text_cell = new Gtk.CellRendererText (); - text_cell.editable_set = true; - text_cell.editable = false; - text_cell.editing_started.connect (on_editing_started); - text_cell.editing_canceled.connect (on_editing_canceled); - text_cell.ellipsize = Pango.EllipsizeMode.END; - text_cell.xalign = 0; - item_column.pack_end (text_cell, true); - item_column.set_cell_data_func (text_cell, name_cell_data_func); - - icon_cell = new CellRendererIcon (); - icon_cell.xpad = 2; - item_column.pack_end (icon_cell, false); - item_column.set_cell_data_func (icon_cell, icon_cell_data_func); - - // First expander. Used for normal expandable items - primary_expander_cell = new CellRendererExpander (); - - int expander_spacing; - style_get (STYLE_PROP_EXPANDER_SPACING, out expander_spacing); - primary_expander_cell.xpad = expander_spacing / 2; - - item_column.pack_end (primary_expander_cell, false); - item_column.set_cell_data_func (primary_expander_cell, expander_cell_data_func); - - // Selection - var selection = get_selection (); - selection.mode = Gtk.SelectionMode.BROWSE; - selection.set_select_function (select_func); - - // Monitor item changes - enable_item_property_monitor (); - - // Add root-level indentation. New levels will be added by update_item_expansion() - add_spacer_cell_for_level (1); - - // Enable basic row drag and drop - configure_drag_source (null); - configure_drag_dest (null, 0); - - query_tooltip.connect_after (on_query_tooltip); - has_tooltip = true; - } - - ~Tree () { - disable_item_property_monitor (); - } - - public override bool drag_motion (Gdk.Drag drag) { - // call the base signal to get rows with children to spring open - if (!base.drag_motion (context, x, y, time)) - return false; - - Gtk.TreePath suggested_path, current_path; - Gtk.TreeViewDropPosition suggested_pos, current_pos; - - if (get_dest_row_at_pos (x, y, out suggested_path, out suggested_pos)) { - // the base implementation of drag_motion was likely to set a drop - // destination row. If that's the case, we configure the row position - // to only allow drops before or after it, but not into it - get_drag_dest_row (out current_path, out current_pos); - - if (current_path != null && suggested_path.compare (current_path) == 0) { - // If the source widget is this treeview, we assume we're - // just dragging rows around, because at the moment dragging - // rows into other rows (re-parenting) is not implemented. - var source_widget = Gtk.drag_get_source_widget (context); - bool dragging_treemodel_row = (source_widget == this); - - if (dragging_treemodel_row) { - // we don't allow DnD into other rows, only in between them - // (no row is highlighted) - if (current_pos != Gtk.TreeViewDropPosition.BEFORE) { - if (current_pos == Gtk.TreeViewDropPosition.INTO_OR_BEFORE) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.BEFORE); - else - set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); - } - } else { - // for DnD originated on a different widget, we don't want to insert - // between rows, only select the rows themselves - if (current_pos == Gtk.TreeViewDropPosition.BEFORE) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_BEFORE); - else if (current_pos == Gtk.TreeViewDropPosition.AFTER) - set_drag_dest_row (current_path, Gtk.TreeViewDropPosition.INTO_OR_AFTER); - - // determine if external DnD is supported by the item at destination - var dest = data_model.get_item_from_path (current_path) as SourceListDragDest; - - if (dest != null) { - var target_list = Gtk.drag_dest_get_target_list (this); - var target = Gtk.drag_dest_find_target (this, context, target_list); - - // have 'drag_get_data' call 'drag_data_received' to determine - // if the data can actually be dropped. - context.set_data ("suggested-dnd-action", context.get_suggested_action ()); - Gtk.drag_get_data (this, context, target, time); - } else { - // dropping data here is not supported. Unset dest row - set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); - } - } - } - } else { - // dropping into blank areas of SourceList is not allowed - set_drag_dest_row (null, Gtk.TreeViewDropPosition.AFTER); - return false; - } - - return true; - } - - public override void drag_data_received (Gdk.Drag drag) { - var target_list = Gtk.drag_dest_get_target_list (this); - var target = Gtk.drag_dest_find_target (this, context, target_list); - - if (target == Gdk.Atom.intern_static_string ("GTK_TREE_MODEL_ROW")) { - base.drag_data_received (context, x, y, selection_data, info, time); - return; - } - - Gtk.TreePath path; - Gtk.TreeViewDropPosition pos; - - if (context.get_data ("suggested-dnd-action") != 0) { - context.set_data ("suggested-dnd-action", 0); - - get_drag_dest_row (out path, out pos); - - if (path != null) { - // determine if external DnD is allowed by the item at destination - var dest = data_model.get_item_from_path (path) as SourceListDragDest; - - if (dest == null || !dest.data_drop_possible (context, selection_data)) { - // dropping data here is not allowed. unset any previously - // selected destination row - set_drag_dest_row (null, Gtk.TreeViewDropPosition.BEFORE); - Gdk.drag_status (context, 0, time); - return; - } - } - - Gdk.drag_status (context, context.get_suggested_action (), time); - } else { - if (get_dest_row_at_pos (x, y, out path, out pos)) { - // Data coming from external source/widget was dropped into this item. - // selection_data contains something other than a tree row; most likely - // we're dealing with a DnD not originated within the Source List tree. - // Let's pass the data to the corresponding item, if there's a handler. - - var drag_dest = data_model.get_item_from_path (path) as SourceListDragDest; - - if (drag_dest != null) { - var action = drag_dest.data_received (context, selection_data); - Gtk.drag_finish (context, action != 0, action == Gdk.DragAction.MOVE, time); - return; - } - } - - // failure - Gtk.drag_finish (context, false, false, time); - } - } - - public void configure_drag_source (GLib.Value[]? src_entries) { - // Append GTK_TREE_MODEL_ROW to src_entries and src_entries to enable row DnD. - var entries = append_row_target_entry (src_entries); - - unset_rows_drag_source (); - enable_model_drag_source (Gdk.ModifierType.BUTTON1_MASK, entries, Gdk.DragAction.MOVE); - } - - public void configure_drag_dest (GLib.Value[]? dest_entries, Gdk.DragAction actions) { - // Append GTK_TREE_MODEL_ROW to dest_entries and dest_entries to enable row DnD. - var entries = append_row_target_entry (dest_entries); - - unset_rows_drag_dest (); - - // DragAction.MOVE needs to be enabled for row drag-and-drop to work properly - enable_model_drag_dest (entries, Gdk.DragAction.MOVE | actions); - } - - private bool on_query_tooltip (int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip) { - Gtk.TreePath path; - Gtk.TreeViewColumn column = get_column (Column.ITEM); - - get_tooltip_context (ref x, ref y, keyboard_tooltip, null, out path, null); - if (path == null) { - return false; - } - - var item = data_model.get_item_from_path (path); - if (item != null) { - bool should_show = false; - - Gdk.Rectangle start_cell_area; - get_cell_area (path, column, out start_cell_area); - - set_tooltip_row (tooltip, path); - - if (item.tooltip == null) { - tooltip.set_markup (item.name); - should_show = true; - } else if (item.tooltip != "") { - tooltip.set_markup (item.tooltip); - should_show = true; - } - - if (keyboard_tooltip) { - return should_show; - } - - if (over_cell (column, path, text_cell, x - start_cell_area.x) || - over_cell (column, path, icon_cell, x - start_cell_area.x)) { - - return should_show; - } else if (over_cell (column, path, activatable_cell, x - start_cell_area.x)) { - if (item.activatable_tooltip == "") { - return false; - } else { - tooltip.set_markup (item.activatable_tooltip); - return true; - } - } - } - - return false; - } - - private static GLib.Value[] append_row_target_entry (GLib.Value[]? orig) { - const GLib.Value row_target_entry = { // vala-lint=naming-convention - "GTK_TREE_MODEL_ROW", - Gtk.TargetFlags.SAME_WIDGET, - 0 - }; - - var entries = new GLib.Value[0]; - entries += row_target_entry; - - if (orig != null) { - foreach (var target_entry in orig) - entries += target_entry; - } - - return entries; - } - - private void enable_item_property_monitor () { - data_model.item_updated.connect_after (on_model_item_updated); - } - - private void disable_item_property_monitor () { - data_model.item_updated.disconnect (on_model_item_updated); - } - - private void on_model_item_updated (Item item) { - // Currently, all the other properties are updated automatically by the - // cell-data functions after a change in the model. - var expandable_item = item as ExpandableItem; - if (expandable_item != null) - update_expansion (expandable_item); - } - - private void add_spacer_cell_for_level ( - int level, - bool check_previous = true - ) requires (level > 0) { - if (spacer_cells == null) - spacer_cells = new Gee.HashMap (); - - if (!spacer_cells.has_key (level)) { - var spacer_cell = new CellRendererSpacer (); - spacer_cell.level = level; - spacer_cells[level] = spacer_cell; - - uint cell_xpadding; - - // The primary expander is not visible for root-level (i.e. first level) - // items, so for the second level of indentation we use a low padding - // because the primary expander will add enough space. For the root level, - // we use left_padding, and level_indentation for the remaining levels. - // The value of cell_xpadding will be allocated *twice* by the cell renderer, - // so we set the value to a half of actual (desired) value. - switch (level) { - case 1: // root - int left_padding; - style_get (STYLE_PROP_LEFT_PADDING, out left_padding); - cell_xpadding = left_padding / 2; - break; - - case 2: // second level - cell_xpadding = 0; - break; - - default: // remaining levels - int level_indentation; - style_get (STYLE_PROP_LEVEL_INDENTATION, out level_indentation); - cell_xpadding = level_indentation / 2; - break; - } - - spacer_cell.xpad = cell_xpadding; - - var item_column = get_column (Column.ITEM); - item_column.pack_start (spacer_cell, false); - item_column.set_cell_data_func (spacer_cell, spacer_cell_data_func); - - // Make sure that the previous indentation levels also exist - if (check_previous) { - for (int i = level - 1; i > 0; i--) - add_spacer_cell_for_level (i, false); - } - } - } - - /** - * Evaluates whether the item at the specified path can be selected or not. - */ - private bool select_func ( - Gtk.TreeSelection selection, - Gtk.TreeModel model, - Gtk.TreePath path, - bool path_currently_selected - ) { - bool selectable = false; - var item = data_model.get_item_from_path (path); - - if (item != null) { - // Main categories ARE NOT selectable, so check for that - if (!data_model.is_category (item, null, path)) - selectable = item.selectable; - } - - return selectable; - } - - private Gtk.TreePath? get_selected_path () { - Gtk.TreePath? selected_path = null; - Gtk.TreeSelection? selection = get_selection (); - - if (selection != null) { - Gtk.TreeModel? model; - var selected_rows = selection.get_selected_rows (out model); - if (selected_rows.length () == 1) - selected_path = selected_rows.nth_data (0); - } - - return selected_path; - } - - private void set_selected (Item? item, bool scroll_to_item) { - if (item == null) { - Gtk.TreeSelection? selection = get_selection (); - if (selection != null) - selection.unselect_all (); - - // As explained in cursor_changed(), we cannot emit signals for this special - // case from there because that wouldn't allow us to implement the behavior - // we want (i.e. restoring the old selection after expanding a previously - // collapsed category) without emitting the undesired item_selected() signal - // along the way. This special case is handled manually, because it *should* - // only happen in response to client code requests and never in response to - // user interaction. We do that here because there's no way to determine - // whether the cursor change came from code (i.e. this method) or user - // interaction from cursor_changed(). - this.selected = null; - item_selected (null); - } else if (item.selectable) { - if (scroll_to_item) - this.scroll_to_item (item); - - var to_select = data_model.get_item_path (item); - if (to_select != null) - set_cursor_on_cell (to_select, get_column (Column.ITEM), text_cell, false); - } - } - - public override void cursor_changed () { - var path = get_selected_path (); - Item? new_item = path != null ? data_model.get_item_from_path (path) : null; - - // Don't do anything if @new_item is null. - // - // The only way 'this.selected' can be null is by setting it explicitly to - // that value from client code, and thus we handle that case in set_selected(). - // THIS CANNOT HAPPEN IN RESPONSE TO USER INTERACTION. For example, if an - // item is un-selected because its parent category has been collapsed, then it will - // remain as the current selected item (not in reality, just as the value of - // this.selected) and will be re-selected after the parent is expanded again. - // THIS ALL HAPPENS SILENTLY BEHIND THE SCENES, so client code will never know - // it ever happened; the value of selected_item remains unchanged and item_selected() - // is not emitted. - if (new_item != null && new_item != this.selected) { - this.selected = new_item; - item_selected (new_item); - } - } - - public bool scroll_to_item (Item item, bool use_align = false, float row_align = 0) { - bool scrolled = false; - - var path = data_model.get_item_path (item); - if (path != null) { - scroll_to_cell (path, null, use_align, row_align, 0); - scrolled = true; - } - - return scrolled; - } - - public bool start_editing_item (Item item) requires (item.editable) requires (item.selectable) { - if (editing && item == edited) // If same item again, simply return. - return false; - - var path = data_model.get_item_path (item); - if (path != null) { - edited = item; - text_cell.editable = true; - set_cursor_on_cell (path, get_column (Column.ITEM), text_cell, true); - } else { - warning ("Could not edit \"%s\": path not found", item.name); - } - - return editing; - } - - public void stop_editing () { - if (editing && edited != null) { - var path = data_model.get_item_path (edited); - - // Setting the cursor on the same cell without starting an edit cancels any - // editing operation going on. - if (path != null) - set_cursor_on_cell (path, get_column (Column.ITEM), text_cell, false); - } - } - - private void on_editing_started (Gtk.CellEditable editable, string path) { - editable_entry = editable as Gtk.Entry; - if (editable_entry != null) { - editable_entry.editing_done.connect (on_editing_done); - editable_entry.editable = true; - } - } - - private void on_editing_canceled () { - if (editable_entry != null) { - editable_entry.editable = false; - editable_entry.editing_done.disconnect (on_editing_done); - } - - text_cell.editable = false; - edited = null; - } - - private void on_editing_done () { - if (edited != null && edited.editable && editable_entry != null) - edited.edited (editable_entry.get_text ()); - - // Same actions as when canceling editing - on_editing_canceled (); - } - - private void on_activatable_activated (string item_path_str) { - var item = get_item_from_path_string (item_path_str); - if (item != null) - item.action_activated (); - } - - private Item? get_item_from_path_string (string item_path_str) { - var item_path = new Gtk.TreePath.from_string (item_path_str); - return data_model.get_item_from_path (item_path); - } - - private bool toggle_expansion (ExpandableItem item) { - if (item.collapsible) { - item.expanded = !item.expanded; - return true; - } - return false; - } - - /** - * Updates the tree to reflect the ''expanded'' property of expandable_item. - */ - public void update_expansion (ExpandableItem expandable_item) { - var path = data_model.get_item_path (expandable_item); - - if (path != null) { - // Make sure that the indentation cell for the item's level exists. - // We use +1 because the method will make sure that the previous - // indentation levels exist too. - add_spacer_cell_for_level (path.get_depth () + 1); - - if (expandable_item.expanded) { - expand_row (path, false); - - // Since collapsing an item un-selects any child item previously selected, - // we need to restore the selection. This will be done silently because - // set_selected checks for equality between the previously "selected" - // item and the newly selected, and only emits the item_selected() signal - // if they are different. See cursor_changed() for a better explanation - // of this behavior. - if (selected != null && selected.parent == expandable_item) - set_selected (selected, true); - - // Collapsing expandable_item's row also collapsed all its children, - // and thus we need to update the "expanded" property of each of them - // to reflect their previous state. - foreach (var child_item in expandable_item.children) { - var child_expandable_item = child_item as ExpandableItem; - if (child_expandable_item != null) - update_expansion (child_expandable_item); - } - } else { - collapse_row (path); - } - } - } - - public override void row_expanded (Gtk.TreeIter iter, Gtk.TreePath path) { - var item = data_model.get_item (iter) as ExpandableItem; - return_if_fail (item != null); - - disable_item_property_monitor (); - item.expanded = true; - enable_item_property_monitor (); - } - - public override void row_collapsed (Gtk.TreeIter iter, Gtk.TreePath path) { - var item = data_model.get_item (iter) as ExpandableItem; - return_if_fail (item != null); - - disable_item_property_monitor (); - item.expanded = false; - enable_item_property_monitor (); - } - - public override void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) { - if (column == get_column (Column.ITEM)) { - var item = data_model.get_item_from_path (path); - if (item != null) - item.activated (); - } - } - - public override bool key_release_event (Gdk.EventKey event) { - if (selected_item != null) { - switch (event.keyval) { - case Gdk.Key.F2: - var modifiers = Gtk.accelerator_get_default_mod_mask (); - // try to start editing selected item - if ((event.state & modifiers) == 0 && selected_item.editable) - start_editing_item (selected_item); - break; - } - } - - return base.key_release_event (event); - } - - public override bool button_release_event (Gdk.EventButton event) { - if (unselectable_item_clicked && event.window == get_bin_window ()) { - unselectable_item_clicked = false; - - Gtk.TreePath path; - Gtk.TreeViewColumn column; - int x = (int) event.x, y = (int) event.y, cell_x, cell_y; - - if (get_path_at_pos (x, y, out path, out column, out cell_x, out cell_y)) { - var item = data_model.get_item_from_path (path) as ExpandableItem; - - if (item != null) { - if (!item.selectable || data_model.is_category (item, null, path)) - toggle_expansion (item); - } - } - } - - return base.button_release_event (event); - } - - public override bool button_press_event (Gdk.EventButton event) { - if (event.window != get_bin_window ()) - return base.button_press_event (event); - - Gtk.TreePath path; - Gtk.TreeViewColumn column; - int x = (int) event.x, y = (int) event.y, cell_x, cell_y; - - if (get_path_at_pos (x, y, out path, out column, out cell_x, out cell_y)) { - var item = data_model.get_item_from_path (path); - - // This is needed because the treeview adds an offset at the beginning of every level - Gdk.Rectangle start_cell_area; - get_cell_area (path, get_column (0), out start_cell_area); - cell_x -= start_cell_area.x; - - if (item != null && column == get_column (Column.ITEM)) { - // Cancel any editing operation going on - stop_editing (); - - if (event.button == Gdk.BUTTON_SECONDARY) { - popup_context_menu (item, event); - return true; - } else if (event.button == Gdk.BUTTON_PRIMARY) { - // Check whether an expander (or an equivalent area) was clicked. - bool is_expandable = item is ExpandableItem; - bool is_category = is_expandable && data_model.is_category (item, null, path); - - if (event.type == Gdk.EventType.BUTTON_PRESS) { - if (is_expandable) { - // Checking for secondary_expander_cell is not necessary because the entire row - // serves for this purpose when the item is a category or when the item is a - // normal expandable item that is not selectable (special care is taken to - // not break the activatable/action icons for such cases). - // The expander only works like a visual indicator for these items. - unselectable_item_clicked = is_category - || (!item.selectable && !over_cell (column, path, activatable_cell, cell_x)); - - if (!unselectable_item_clicked - && over_primary_expander (column, path, cell_x) - && toggle_expansion (item as ExpandableItem)) - return true; - } - } else if ( - event.type == Gdk.EventType.2BUTTON_PRESS - && !is_category // Main categories are *not* editable - && item.editable - && item.selectable - && over_cell (column, path, text_cell, cell_x) - && start_editing_item (item) - ) { - // The user double-clicked over the text cell, and editing started successfully. - return true; - } - } - } - } - - return base.button_press_event (event); - } - - private bool over_primary_expander (Gtk.TreeViewColumn col, Gtk.TreePath path, int x) { - Gtk.TreeIter iter; - if (!model.get_iter (out iter, path)) - return false; - - // Call the cell-data function and make it assign the proper visibility state to the cell - expander_cell_data_func (col, primary_expander_cell, model, iter); - - if (!primary_expander_cell.visible) - return false; - - // We want to return false if the cell is not expandable (i.e. the arrow is hidden) - if (model.iter_n_children (iter) < 1) - return false; - - // Now that we're sure that the item is expandable, let's see if the user clicked - // over the expander area. We don't do so directly by querying the primary expander - // position because it's not fixed, yielding incorrect coordinates depending on whether - // a different area was re-drawn before this method was called. We know that the last - // spacer cell precedes (in a LTR fashion) the expander cell. Because the position - // of the spacer cell is fixed, we can safely query it. - int indentation_level = path.get_depth (); - var last_spacer_cell = spacer_cells[indentation_level]; - - if (last_spacer_cell != null) { - int cell_x, cell_width; - - if (col.cell_get_position (last_spacer_cell, out cell_x, out cell_width)) { - // Add a pixel so that the expander area is a bit wider - int expander_width = get_cell_width (primary_expander_cell) + 1; - - var dir = get_direction (); - if (dir == Gtk.TextDirection.NONE) { - dir = Gtk.Widget.get_default_direction (); - } - - if (dir == Gtk.TextDirection.LTR) { - int indentation_offset = cell_x + cell_width; - return x >= indentation_offset && x <= indentation_offset + expander_width; - } - - return x <= cell_x && x >= cell_x - expander_width; - } - } - - return false; - } - - private bool over_cell (Gtk.TreeViewColumn col, Gtk.TreePath path, Gtk.CellRenderer cell, int x) { - int cell_x, cell_width; - bool found = col.cell_get_position (cell, out cell_x, out cell_width); - return found && x > cell_x && x < cell_x + cell_width; - } - - private int get_cell_width (Gtk.CellRenderer cell_renderer) { - Gtk.Requisition min_req; - cell_renderer.get_preferred_size (this, out min_req, null); - return min_req.width; - } - - public override bool popup_menu () { - return popup_context_menu (null, null); - } - - private bool popup_context_menu (Item? item, Gdk.EventButton? event) { - if (item == null) - item = selected_item; - - if (item != null) { - var menu = item.get_context_menu (); - if (menu != null) { - menu.attach_widget = this; - menu.popup_at_pointer (event); - if (event == null) { - menu.select_first (false); - } - - return true; - } - } - - return false; - } - - private static Item? get_item_from_model (Gtk.TreeModel model, Gtk.TreeIter iter) { - var data_model = model as DataModel; - assert (data_model != null); - return data_model.get_item (iter); - } - - private static void spacer_cell_data_func ( - Gtk.CellLayout layout, - Gtk.CellRenderer renderer, - Gtk.TreeModel model, - Gtk.TreeIter iter - ) { - var spacer = renderer as CellRendererSpacer; - assert (spacer != null); - assert (spacer.level > 0); - - var path = model.get_path (iter); - - int level = -1; - if (path != null) - level = path.get_depth (); - - renderer.visible = spacer.level <= level; - } - - private void name_cell_data_func ( - Gtk.CellLayout layout, - Gtk.CellRenderer renderer, - Gtk.TreeModel model, - Gtk.TreeIter iter - ) { - var text_renderer = renderer as Gtk.CellRendererText; - assert (text_renderer != null); - - var text = new StringBuilder (); - var weight = Pango.Weight.NORMAL; - bool use_markup = false; - - var item = get_item_from_model (model, iter); - if (item != null) { - if (item.markup != null) { - text.append (item.markup); - use_markup = true; - } else { - text.append (item.name); - } - - if (data_model.is_category (item, iter)) - weight = Pango.Weight.BOLD; - } - - text_renderer.weight = weight; - if (use_markup) { - text_renderer.markup = text.str; - } else { - text_renderer.text = text.str; - } - } - - private void badge_cell_data_func ( - Gtk.CellLayout layout, - Gtk.CellRenderer renderer, - Gtk.TreeModel model, - Gtk.TreeIter iter - ) { - var badge_renderer = renderer as CellRendererBadge; - assert (badge_renderer != null); - - string text = ""; - bool visible = false; - - var item = get_item_from_model (model, iter); - if (item != null) { - // Badges are not displayed for main categories - visible = !data_model.is_category (item, iter) - && item.badge != null - && item.badge.strip () != ""; - - if (visible) - text = item.badge; - } - - badge_renderer.visible = visible; - badge_renderer.text = text; - } - - private void icon_cell_data_func ( - Gtk.CellLayout layout, - Gtk.CellRenderer renderer, - Gtk.TreeModel model, Gtk.TreeIter iter - ) { - var icon_renderer = renderer as CellRendererIcon; - assert (icon_renderer != null); - - bool visible = false; - Icon? icon = null; - - var item = get_item_from_model (model, iter); - if (item != null) { - // Icons are not displayed for main categories - visible = !data_model.is_category (item, iter); - - if (visible) { - if (icon_renderer == icon_cell) - icon = item.icon; - else if (icon_renderer == activatable_cell) - icon = item.activatable; - else - assert_not_reached (); - } - } - - visible = visible && icon != null; - - icon_renderer.visible = visible; - icon_renderer.gicon = visible ? icon : null; - } - - /** - * Controls expander visibility. - */ - private void expander_cell_data_func ( - Gtk.CellLayout layout, - Gtk.CellRenderer renderer, - Gtk.TreeModel model, - Gtk.TreeIter iter - ) { - var item = get_item_from_model (model, iter); - if (item != null) { - // Gtk.CellRenderer.is_expander takes into account whether the item has children or not. - // The tree-view checks for that and sets this property for us. It also sets - // Gtk.CellRenderer.is_expanded, and thus we don't need to check for that either. - var expandable_item = item as ExpandableItem; - if (expandable_item != null) - renderer.is_expander = renderer.is_expander && expandable_item.collapsible; - } - - if (renderer == primary_expander_cell) - renderer.visible = !data_model.is_iter_at_root_level (iter); - else if (renderer == secondary_expander_cell) - renderer.visible = data_model.is_category (item, iter); - else - assert_not_reached (); - } +namespace Code.Widgets.SourceList { +/** + * A widget that can display a list of items organized in categories. + * + * The source list widget consists of a collection of items, some of which are also expandable (and + * thus can contain more items). All the items displayed in the source list are children of the widget's + * root item. The API is meant to be used as follows: + * + * 1. Create the items you want to display in the source list, setting the appropriate values for their + * properties. The desired hierarchy is achieved by creating expandable items and adding items to them. + * These will be displayed as descendants in the widget's tree structure. The expandable items that are + * not nested inside any other item are considered to be at root level, and should be added to + * the widget's root item.<
> + * + * Expandable items located at the root level are treated as categories, and only support text. + * + * ''Example''<
> + * The final tree will have the following structure: + * {{{ + * Libraries + * Music + * Stores + * My Store + * Music + * Podcasts + * Devices + * Player 1 + * Player 2 + * }}} + * + * {{{ + * var library_category = new Code.Widgets.SourceList.ExpandableItem ("Libraries"); + * var store_category = new Code.Widgets.SourceList.ExpandableItem ("Stores"); + * var device_category = new Code.Widgets.SourceList.ExpandableItem ("Devices"); + * + * var music_item = new Code.Widgets.SourceList.Item ("Music"); + * + * // "Libraries" will be the parent category of "Music" + * library_category.add (music_item); + * + * // We plan to add sub-items to the store, so let's use an expandable item + * var my_store_item = new Code.Widgets.SourceList.ExpandableItem ("My Store"); + * store_category.add (my_store_item); + * + * var my_store_podcast_item = new Code.Widgets.SourceList.Item ("Podcasts"); + * var my_store_music_item = new Code.Widgets.SourceList.Item ("Music"); + * + * my_store_item.add (my_store_music_item); + * my_store_item.add (my_store_podcast_item); + * + * var player1_item = new Code.Widgets.SourceList.Item ("Player 1"); + * var player2_item = new Code.Widgets.SourceList.Item ("Player 2"); + * + * device_category.add (player1_item); + * device_category.add (player2_item); + * }}} + * + * 2. Create a source list widget.<
> + * {{{ + * var source_list = new Code.Widgets.SourceList (); + * }}} + * + * 3. Add root-level items to the {@link Code.Widgets.SourceList.root} item. + * This item only serves as a container, and all its properties are ignored by the widget. + * + * {{{ + * // This will add the main categories (including their children) to the source list. After + * // having being added to be widget, any other item added to any of these items + * // (or any other child item in a deeper level) will be automatically added too. + * // There's no need to deal with the source list widget directly. + * + * var root = source_list.root; + * + * root.add (library_category); + * root.add (store_category); + * root.add (device_category); + * }}} + * + * The steps mentioned above are enough for initializing the source list. Future changes to the items' + * properties are ''automatically'' reflected by the widget. + * + * Final steps would involve connecting handlers to the source list events, being + * {@link Code.Widgets.SourceList.item_selected} the most important, as it indicates that + * the selection was modified. + * + * Pack the source list into the GUI using the {@link Gtk.Paned} widget. + * This is usually done as follows: + * {{{ + * var pane = new Gtk.Paned (Gtk.Orientation.HORIZONTAL); + * pane.pack1 (source_list, false, false); + * pane.pack2 (content_area, true, false); + * }}} + * + * @since 0.2 + * @see Gtk.Paned + */ +public class Window : Gtk.Widget { + static construct { + set_layout_manager_type (typeof (Gtk.BinLayout)); } - - + private Gtk.ScrolledWindow scrolled_window; /** - * Emitted when the source list selection changes. + * = WORKING INTERNALS = * - * @param item Selected item; //null// if nothing is selected. - * @since 0.2 - */ - public virtual signal void item_selected (Item? item) { } - - /** - * A {@link Code.Widgets.SourceList.VisibleFunc} should return true if the item should be - * visible; false otherwise. If //item//'s {@link Code.Widgets.SourceList.Item.visible} - * property is set to //false//, then it won't be displayed even if this method returns //true//. + * In order to offer a transparent Item-based API, and avoid the need of providing methods + * to deal with items directly on the SourceList widget, it was decided to follow a monitor-like + * implementation, where the source list permanently monitors its root item and any other + * child item added to it. The task of monitoring the properties of the items has been + * divided among different objects, as shown below: * - * It is important to note that the method ''must not modify any property of //item//''. - * Doing so would result in an infinite loop, freezing the application's user interface. - * This happens because the source list invokes this method to "filter" an item after - * any of its properties changes, so by modifying a property this method would be invoking - * itself again. + * Monitored by: Object::method that receives the signals indicating the property change. + * Applied by: Object::method that actually updates the tree to reflect the property changes + * (directly or indirectly, as in the case of the tree data model). * - * For most use cases, modifying the {@link Code.Widgets.SourceList.Item.visible} property is enough. + * --------------------------------------------------------------------------------------------- + * PROPERTY | MONITORED BY | APPLIED BY + * --------------------------------------------------------------------------------------------- + * + Item | | + * - parent | Not monitored | N/A + * - name | DataModel::on_item_prop_changed | Tree::name_cell_data_func + * - editable | DataModel::on_item_prop_changed | Queried when needed (See Tree::start_editing_item) + * - visible | DataModel::on_item_prop_changed | DataModel::filter_visible_func + * - icon | DataModel::on_item_prop_changed | Tree::icon_cell_data_func + * - activatable | Same as @icon | Same as @icon + * + ExpandableItem | | + * - collapsible | DataModel::on_item_prop_changed | Tree::update_expansion + * | | Tree::expander_cell_data_func + * - expanded | Same as @collapsible | Same as @collapsible + * --------------------------------------------------------------------------------------------- + * * Only automatic properties are monitored. ExpandableItem's additions/removals are handled by + * DataModel::add_item() and DataModel::remove_item() * - * The advantage of using this method is that its nature is non-destructive, and the - * changes it makes can be easily reverted (see {@link Code.Widgets.SourceList.refilter}). + * Other features: + * - Sorting: this happens on the tree-model level (DataModel). + */ + + /** + * Emitted when the source list selection changes. * - * @param item Item to be checked. - * @return Whether //item// should be visible or not. + * @param item Selected item; //null// if nothing is selected. * @since 0.2 */ - public delegate bool VisibleFunc (Item item); + public virtual signal void item_selected (Item? item) { } /** * Root-level expandable item. @@ -2654,16 +219,21 @@ public class SourceList : Gtk.ScrolledWindow { * @return A new {@link Code.Widgets.SourceList}. * @since 0.2 */ - public SourceList (ExpandableItem root = new ExpandableItem ()) { + public Window (ExpandableItem root = new ExpandableItem ()) { this.root = root; } construct { + var lm = new Gtk.BinLayout (); + set_layout_manager (lm); + tree = new Tree (data_model); + scrolled_window = new Gtk.ScrolledWindow () { + child = tree + }; - set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); - add (tree); - show_all (); + scrolled_window.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); + this.child = scrolled_window; tree.item_selected.connect ((item) => item_selected (item)); } @@ -2745,59 +315,6 @@ public class SourceList : Gtk.ScrolledWindow { tree.stop_editing (); } - /** - * Turns Source List into a //drag source//. - * - * This enables items that implement {@link Code.Widgets.SourceListDragSource} - * to be dragged outside the Source List and drop data into external widgets. - * - * @param src_entries an array of {@link GLib.Value}s indicating the targets - * that the drag will support. - * @see Code.Widgets.SourceListDragSource - * @see Code.Widgets.SourceList.disable_drag_source - * @since 0.3 - */ - public void enable_drag_source (GLib.Value[] src_entries) { - tree.configure_drag_source (src_entries); - } - - /** - * Undoes the effect of {@link Code.Widgets.SourceList.enable_drag_source} - * - * @see Code.Widgets.SourceList.enable_drag_source - * @since 0.3 - */ - public void disable_drag_source () { - tree.configure_drag_source (null); - } - - /** - * Turns Source List into a //drop destination//. - * - * This enables items that implement {@link Code.Widgets.SourceListDragDest} - * to receive data from external widgets via drag-and-drop. - * - * @param dest_entries an array of {@link GLib.Value}s indicating the drop - * types that Source List items will accept. - * @param actions a bitmask of possible actions for a drop onto Source List items. - * @see Code.Widgets.SourceListDragDest - * @see Code.Widgets.SourceList.disable_drag_dest - * @since 0.3 - */ - public void enable_drag_dest (GLib.Value[] dest_entries, Gdk.DragAction actions) { - tree.configure_drag_dest (dest_entries, actions); - } - - /** - * Undoes the effect of {@link Code.Widgets.SourceList.enable_drag_dest} - * - * @see Code.Widgets.SourceList.enable_drag_dest - * @since 0.3 - */ - public void disable_drag_dest () { - tree.configure_drag_dest (null, 0); - } - /** * Scrolls the source list tree to make //item// visible. * diff --git a/src/Widgets/SourceList/SourceListDataModel.vala b/src/Widgets/SourceList/SourceListDataModel.vala new file mode 100644 index 0000000000..f66c7a72e8 --- /dev/null +++ b/src/Widgets/SourceList/SourceListDataModel.vala @@ -0,0 +1,525 @@ +/* + * Copyright 2019 elementary, Inc. (https://elementary.io) + * Copyright 2012-2014 Victor Martinez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +namespace Code.Widgets.SourceList { +/** + * The model backing the SourceList tree. + * + * It monitors item property changes, and handles children additions and removals. It also controls + * the visibility of the items based on their "visible" property, and on their number of children, + * if they happen to be categories. Its main purpose is to provide an easy and practical interface + * for sorting, adding, removing and updating items, eliminating the need of repeatedly dealing with + * the Gtk.TreeModel API directly. + */ + + //TODO Convert to FilterListModel + public class DataModel : Gtk.TreeModelFilter { + + /** + * An object that references a particular row in a model. This class is a wrapper built around + * Gtk.TreeRowReference, and exists with the purpose of ensuring we never use invalid tree paths + * or iters in the model, since most of these errors provoke failures due to GTK+ assertions + * or, even worse, unexpected behavior. + */ + private class NodeWrapper { + + /** + * The actual reference to the node. If is is null, it is treated as invalid. + */ + private Gtk.TreeRowReference? row_reference; + + /** + * A newly-created Gtk.TreeIter pointing to the node if it exists; null otherwise. + */ + public Gtk.TreeIter? iter { + owned get { + Gtk.TreeIter? rv = null; + + if (valid) { + var _path = this.path; + if (_path != null) { + Gtk.TreeIter _iter; + if (row_reference.get_model ().get_iter (out _iter, _path)) + rv = _iter; + } + } + + return rv; + } + } + + /** + * A newly-created Gtk.TreePath pointing to the node if it exists; null otherwise. + */ + public Gtk.TreePath? path { + owned get { return valid ? row_reference.get_path () : null; } + } + + /** + * Whether the node is valid or not. When it is not valid, no valid references are + * returned by the object to avoid errors (null is returned instead). + */ + public bool valid { + get { return row_reference != null && row_reference.valid (); } + } + + public NodeWrapper (Gtk.TreeModel model, Gtk.TreeIter iter) { + row_reference = new Gtk.TreeRowReference (model, model.get_path (iter)); + } + } + + /** + * Helper object used to monitor item property changes. + */ + private class ItemMonitor { + public signal void changed (Item self, string prop_name); + private Item item; + + public ItemMonitor (Item item) { + this.item = item; + item.notify.connect_after (on_notify); + } + + ~ItemMonitor () { + item.notify.disconnect (on_notify); + } + + private void on_notify (ParamSpec prop) { + changed (item, prop.name); + } + } + + private enum Column { + ITEM, + N_COLUMNS; + + public Type type () { + switch (this) { + case ITEM: + return typeof (Item); + + default: + assert_not_reached (); // a Type must be returned for every valid column + } + } + } + + public signal void item_updated (Item item); + + /** + * Used by push_parent_update() as key to associate the respective data to the objects. + */ + private const string ITEM_PARENT_NEEDS_UPDATE = "item-parent-needs-update"; + + private ExpandableItem _root; + + /** + * Root item. + * + * This item is not actually part of the model. It's only used as a proxy + * for adding and removing items. + */ + public ExpandableItem root { + get { return _root; } + set { + if (_root != null) { + remove_children_monitor (_root); + foreach (var item in _root.children) + remove_item (item); + } + + _root = value; + + add_children_monitor (_root); + foreach (var item in _root.children) + add_item (item); + } + } + + // This hash map stores items and their respective child node references. For that reason, the + // references it contains should only be used on the child_tree model, or converted to filter + // iters/paths using convert_child_*_to_*() before using them with the filter (i.e. this) model. + private Gee.HashMap items = new Gee.HashMap (); + + private Gee.HashMap monitors = new Gee.HashMap (); + + private Gtk.TreeStore child_tree; + private unowned VisibleFunc? filter_func; + + public DataModel () { + + } + + construct { + child_tree = new Gtk.TreeStore (Column.N_COLUMNS, Column.ITEM.type ()); + child_model = child_tree; + virtual_root = null; + + child_tree.set_default_sort_func (child_model_sort_func); + resort (); + + set_visible_func (filter_visible_func); + } + + public bool has_item (Item item) { + return items.has_key (item); + } + + public void update_item (Item item) requires (has_item (item)) { + assert (root != null); + + // Emitting row_changed() for this item's row in the child model causes the filter + // (i.e. this model) to re-evaluate whether a row is visible or not, calling + // filter_visible_func() for that row again, and that's exactly what we want. + var node_reference = items.get (item); + if (node_reference != null) { + var path = node_reference.path; + var iter = node_reference.iter; + if (path != null && iter != null) { + child_tree.row_changed (path, iter); + item_updated (item); + } + } + } + + private void add_item (Item item) requires (!has_item (item)) { + assert (root != null); + + // Find the parent iter + Gtk.TreeIter? parent_child_iter = null, child_iter; + var parent = item.parent; + + if (parent != null && parent != root) { + // Add parent if it hasn't been added yet + if (!has_item (parent)) + add_item (parent); + + // Try to find the parent's iter + parent_child_iter = get_item_child_iter (parent); + + // Parent must have been added prior to adding this item + assert (parent_child_iter != null); + } + + child_tree.append (out child_iter, parent_child_iter); + child_tree.set (child_iter, Column.ITEM, item, -1); + + items.set (item, new NodeWrapper (child_tree, child_iter)); + + // This is equivalent to a property change. The tree still needs to update + // some of the new item's properties through this signal's handler. + item_updated (item); + + add_property_monitor (item); + + push_parent_update (parent); + + // If the item is expandable, also add children + var expandable = item as ExpandableItem; + if (expandable != null) { + foreach (var child_item in expandable.children) + add_item (child_item); + + // Monitor future additions/removals through signal handlers + add_children_monitor (expandable); + } + } + + private void remove_item (Item item) requires (has_item (item)) { + assert (root != null); + + remove_property_monitor (item); + + // get_item_child_iter() depends on items.get(item) for retrieving the right reference, + // so don't unset the item from @items yet! We first get the child iter and then + // unset the value. + var child_iter = get_item_child_iter (item); + + // Now we remove the item from the table, because that way get_item_child_iter() and + // all the methods that depend on it won't return invalid iters or items when + // called. This is important because child_tree.remove() will emit row_deleted(), + // and its handlers could potentially depend on one of the methods mentioned above. + items.unset (item); + + if (child_iter != null) + child_tree.remove (ref child_iter); + + push_parent_update (item.parent); + + // If the item is expandable, also remove children + var expandable = item as ExpandableItem; + if (expandable != null) { + // No longer monitor future additions or removals + remove_children_monitor (expandable); + + foreach (var child_item in expandable.children) + remove_item (child_item); + } + } + + private void add_property_monitor (Item item) { + var wrapper = new ItemMonitor (item); + monitors[item] = wrapper; + wrapper.changed.connect (on_item_prop_changed); + } + + private void remove_property_monitor (Item item) { + var wrapper = monitors[item]; + if (wrapper != null) + wrapper.changed.disconnect (on_item_prop_changed); + monitors.unset (item); + } + + private void add_children_monitor (ExpandableItem item) { + item.child_added.connect_after (on_item_child_added); + item.child_removed.connect_after (on_item_child_removed); + } + + private void remove_children_monitor (ExpandableItem item) { + item.child_added.disconnect (on_item_child_added); + item.child_removed.disconnect (on_item_child_removed); + } + + private void on_item_child_added (Item item) { + add_item (item); + } + + private void on_item_child_removed (Item item) { + remove_item (item); + } + + private void on_item_prop_changed (Item item, string prop_name) { + if (prop_name != "parent") + update_item (item); + } + + /** + * Pushes a call to update_item() if //parent// is not //null//. + * + * This is needed because the visibility of categories depends on their n_children property, + * and also because item expansion should be updated after adding or removing items. + * If many updates are pushed, and the item has still not been updated, only one is processed. + * This guarantees efficiency as updating a category item could trigger expensive actions. + */ + private void push_parent_update (ExpandableItem? parent) { + if (parent == null) + return; + + bool needs_update = parent.get_data (ITEM_PARENT_NEEDS_UPDATE); + + // If an update is already waiting to be processed, just return, as we + // don't need to queue another one for the same item. + if (needs_update) + return; + + var path = get_item_path (parent); + + if (path != null) { + // Let's mark this item for update + parent.set_data (ITEM_PARENT_NEEDS_UPDATE, true); + + Idle.add (() => { + if (parent != null) { + update_item (parent); + + // Already updated. No longer needs an update. + parent.set_data (ITEM_PARENT_NEEDS_UPDATE, false); + } + + return false; + }); + } + } + + /** + * Returns the Item pointed by iter, or null if the iter doesn't refer to a valid item. + */ + public Item? get_item (Gtk.TreeIter iter) { + Item? item; + get (iter, Column.ITEM, out item, -1); + return item; + } + + /** + * Returns the Item pointed by path, or null if the path doesn't refer to a valid item. + */ + public Item? get_item_from_path (Gtk.TreePath path) { + Gtk.TreeIter iter; + if (get_iter (out iter, path)) + return get_item (iter); + + return null; + } + + /** + * Returns a newly-created path pointing to the item, or null in case a valid path + * is not found. + */ + public Gtk.TreePath? get_item_path (Item item) { + Gtk.TreePath? path = null, child_path = get_item_child_path (item); + + // We want a filter path, not a child_model path + if (child_path != null) + path = convert_child_path_to_path (child_path); + + return path; + } + + /** + * Returns a newly-created iterator pointing to the item, or null in case a valid iter + * was not found. + */ + public Gtk.TreeIter? get_item_iter (Item item) { + var child_iter = get_item_child_iter (item); + + if (child_iter != null) { + Gtk.TreeIter iter; + if (convert_child_iter_to_iter (out iter, child_iter)) + return iter; + } + + return null; + } + + /** + * External "extra" filter method. + */ + public void set_filter_func (VisibleFunc? visible_func) { + this.filter_func = visible_func; + } + + /** + * Checks whether an item is a category (i.e. a root-level expandable item). + * The caller must pass an iter or path pointing to the item, but not both + * (one of them must be null.) + * + * TODO: instead of checking the position of the iter or path, we should simply + * check whether the item's parent is the root item and whether the item is + * expandable. We don't do so right now because vala still allows client code + * to access the Item.parent property, even though its setter is defined as internal. + */ + public bool is_category (Item item, Gtk.TreeIter? iter, Gtk.TreePath? path = null) { + bool is_category = false; + // either iter or path has to be null + if (item is ExpandableItem) { + if (iter != null) { + assert (path == null); + is_category = is_iter_at_root_level (iter); + } else { + assert (iter == null); + is_category = is_path_at_root_level (path); + } + } + return is_category; + } + + public bool is_iter_at_root_level (Gtk.TreeIter iter) { + return is_path_at_root_level (get_path (iter)); + } + + public bool is_path_at_root_level (Gtk.TreePath path) { + return path.get_depth () == 1; + } + + private void resort () { + child_tree.set_sort_column_id (Gtk.SortColumn.UNSORTED, Gtk.SortType.ASCENDING); + child_tree.set_sort_column_id (Gtk.SortColumn.DEFAULT, Gtk.SortType.ASCENDING); + } + + private int child_model_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) { + int order = 0; + + Item? item_a, item_b; + child_tree.get (a, Column.ITEM, out item_a, -1); + child_tree.get (b, Column.ITEM, out item_b, -1); + + // code should only compare items at same hierarchy level + assert (item_a.parent == item_b.parent); + + var parent = item_a.parent as Sortable; + if (parent != null) + order = parent.compare (item_a, item_b); + + return order; + } + + private Gtk.TreeIter? get_item_child_iter (Item item) { + Gtk.TreeIter? child_iter = null; + + var child_node_wrapper = items.get (item); + if (child_node_wrapper != null) + child_iter = child_node_wrapper.iter; + + return child_iter; + } + + private Gtk.TreePath? get_item_child_path (Item item) { + Gtk.TreePath? child_path = null; + + var child_node_wrapper = items.get (item); + if (child_node_wrapper != null) + child_path = child_node_wrapper.path; + + return child_path; + } + + /** + * Filters the child-tree items based on their "visible" property. + */ + private bool filter_visible_func (Gtk.TreeModel child_model, Gtk.TreeIter iter) { + bool item_visible = false; + + Item? item; + child_tree.get (iter, Column.ITEM, out item, -1); + + if (item != null) { + item_visible = item.visible; + + // If the item is a category, also query the number of visible children + // because empty categories should not be displayed. + var expandable = item as ExpandableItem; + if (expandable != null && child_tree.iter_depth (iter) == 0) { + uint n_visible_children = 0; + foreach (var child_item in expandable.children) { + if (child_item.visible) + n_visible_children++; + } + item_visible = item_visible && n_visible_children > 0; + } + } + + if (filter_func != null) + item_visible = item_visible && filter_func (item); + + return item_visible; + } + + private void recursive_node_copy (Gtk.TreeIter src_iter, Gtk.TreeIter dest_iter) { + move_item (src_iter, dest_iter); + + Gtk.TreeIter child; + if (child_tree.iter_children (out child, src_iter)) { + // Need to create children and recurse. Note our dependence on + // persistent iterators here. + do { + Gtk.TreeIter copy; + child_tree.append (out copy, dest_iter); + recursive_node_copy (child, copy); + } while (child_tree.iter_next (ref child)); + } + } + + private void move_item (Gtk.TreeIter src_iter, Gtk.TreeIter dest_iter) { + Item item; + child_tree.get (src_iter, Column.ITEM, out item, -1); + return_if_fail (item != null); + + // update the row reference of item with the new location + child_tree.set (dest_iter, Column.ITEM, item, -1); + items.set (item, new NodeWrapper (child_tree, dest_iter)); + } +} +} diff --git a/src/Widgets/SourceList/SourceListExpandableItem.vala b/src/Widgets/SourceList/SourceListExpandableItem.vala new file mode 100644 index 0000000000..e3866dbc37 --- /dev/null +++ b/src/Widgets/SourceList/SourceListExpandableItem.vala @@ -0,0 +1,357 @@ +/* + * Copyright 2019 elementary, Inc. (https://elementary.io) + * Copyright 2012-2014 Victor Martinez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +namespace Code.Widgets.SourceList { +/** + * A {@link Code.Widgets.SourceList.VisibleFunc} should return true if the item should be + * visible; false otherwise. If //item//'s {@link Code.Widgets.SourceList.Item.visible} + * property is set to //false//, then it won't be displayed even if this method returns //true//. + * + * It is important to note that the method ''must not modify any property of //item//''. + * Doing so would result in an infinite loop, freezing the application's user interface. + * This happens because the source list invokes this method to "filter" an item after + * any of its properties changes, so by modifying a property this method would be invoking + * itself again. + * + * For most use cases, modifying the {@link Code.Widgets.SourceList.Item.visible} property is enough. + * + * The advantage of using this method is that its nature is non-destructive, and the + * changes it makes can be easily reverted (see {@link Code.Widgets.SourceList.refilter}). + * + * @param item Item to be checked. + * @return Whether //item// should be visible or not. + * @since 0.2 + */ +public delegate bool VisibleFunc (Item item); + +/** + * An item that can contain more items. + * + * It supports all the properties inherited from {@link Code.Widgets.SourceList.Item}, + * and behaves like a normal item, except when it is located at the root level; in that case, + * the following properties are ignored by the widget: + * + * * {@link Code.Widgets.SourceList.Item.selectable} + * * {@link Code.Widgets.SourceList.Item.editable} + * * {@link Code.Widgets.SourceList.Item.icon} + * * {@link Code.Widgets.SourceList.Item.activatable} + * * {@link Code.Widgets.SourceList.Item.badge} + * + * Root-level expandable items (i.e. Main Categories) are ''not'' displayed when they contain + * zero visible children. + * + * @since 0.2 + */ + + /** + * An interface for sorting items. + * + * @since 0.3 + */ +public interface Sortable : ExpandableItem { + /** + * Emitted after a user has re-ordered an item via DnD. + * + * @param moved The item that was moved to a different position by the user. + * @since 0.3 + */ + public signal void user_moved_item (SourceList.Item moved); + + /** + * Whether this item will allow users to re-arrange its children via DnD. + * + * This feature can co-exist with a sort algorithm (implemented + * by {@link Code.Widgets.SourceListSortable.compare}), but + * the actual order of the items in the list will always + * honor that method. The sort function has to be compatible with + * the kind of DnD reordering the item wants to allow, since the user can + * only reorder those items for which //compare// returns 0. + * + * @return Whether the item's children can be re-arranged by users. + * @since 0.3 + */ + public abstract bool allow_dnd_sorting (); + + /** + * Should return a negative integer, zero, or a positive integer if ''a'' + * sorts //before// ''b'', ''a'' sorts //with// ''b'', or ''a'' sorts + * //after// ''b'' respectively. If two items compare as equal, their + * order in the sorted source list is undefined. + * + * In order to ensure that the source list behaves as expected, this + * method must define a partial order on the source list tree; i.e. it + * must be reflexive, antisymmetric and transitive. Not complying with + * those requirements could make the program fall into an infinite loop + * and freeze the user interface. + * + * Should return //0// to allow any pair of items to be sortable via DnD. + * + * @param a First item. + * @param b Second item. + * @return A //negative// integer if //a// sorts before //b//, + * //zero// if //a// equals //b//, or a //positive// + * integer if //a// sorts after //b//. + * @since 0.3 + */ + public abstract int compare (SourceList.Item a, SourceList.Item b); +} + +public class ExpandableItem : Item { + /** + * Emitted when an item is added. + * + * @param item Item added. + * @see Code.Widgets.SourceList.ExpandableItem.add + * @since 0.2 + */ + public signal void child_added (Item item); + + /** + * Emitted when an item is removed. + * + * @param item Item removed. + * @see Code.Widgets.SourceList.ExpandableItem.remove + * @since 0.2 + */ + public signal void child_removed (Item item); + + /** + * Emitted when the item is expanded or collapsed. + * + * @since 0.2 + */ + public virtual signal void toggled () { } + + /** + * Whether the item is collapsible or not. + * + * When set to //false//, the item is //always// expanded and the expander is + * not shown. Please note that this will also affect the value returned by the + * {@link Code.Widgets.SourceList.ExpandableItem.expanded} property. + * + * @see Code.Widgets.SourceList.ExpandableItem.expanded + * @since 0.2 + */ + public bool collapsible { get; set; default = true; } + + /** + * Whether the item is expanded or not. + * + * The source list widget will obey the value of this property when possible. + * + * This property has no effect when {@link Code.Widgets.SourceList.ExpandableItem.collapsible} + * is set to //false//. Also keep in mind that, __when set to //true//__, this property + * doesn't always represent the actual expansion state of an item. For example, it might + * be the case that an expandable item is collapsed because it has zero visible children, + * but its //expanded// property value is still //true//; in such case, once one of the + * item's children becomes visible, the item will be expanded again. Same applies to items + * hidden behind a collapsed parent item. + * + * If obtaining the ''actual'' expansion state of an item is important, + * use {@link Code.Widgets.SourceList.is_item_expanded} instead. + * + * @see Code.Widgets.SourceList.ExpandableItem.collapsible + * @see Code.Widgets.SourceList.is_item_expanded + * @since 0.2 + */ + private bool _expanded = false; + public bool expanded { + get { return _expanded || !collapsible; } // if not collapsible, always return true + set { + if (value != _expanded) { + _expanded = value; + toggled (); + } + } + } + + /** + * Number of children contained by the item. + * + * @since 0.2 + */ + public uint n_children { + get { return children_list.size; } + } + + /** + * The item's children. + * + * This returns a newly-created list containing the children. + * It's safe to iterate it while removing items with + * {@link Code.Widgets.SourceList.ExpandableItem.remove} + * + * @since 0.2 + */ + public Gee.Collection children { + owned get { + // Create a copy of the children so that it's safe to iterate it + // (e.g. by using foreach) while removing items. + var children_list_copy = new Gee.ArrayList (); + children_list_copy.add_all (children_list); + return children_list_copy; + } + } + + private Gee.Collection children_list = new Gee.ArrayList (); + + /** + * Creates a new {@link Code.Widgets.SourceList.ExpandableItem} + * + * @param name Title of the item. + * @return (transfer full) A new {@link Code.Widgets.SourceList.ExpandableItem}. + * @since 0.2 + */ + public ExpandableItem (string name = "") { + base (name); + } + + construct { + editable = false; + } + + /** + * Checks whether the item contains the specified child. + * + * This method only considers the item's immediate children. + * + * @param item Item to search. + * @return Whether the item was found or not. + * @since 0.2 + */ + public bool contains (Item item) { + return item in children_list; + } + + /** + * Adds an item. + * + * {@link Code.Widgets.SourceList.ExpandableItem.child_added} is fired after the item is added. + * + * While adding a child item, //the item it's being added to will set itself as the parent//. + * Please note that items are required to have their //parent// property set to //null// before + * being added, so make sure the item is removed from its previous parent before attempting + * to add it to another item. For instance: + * {{{ + * if (item.parent != null) + * item.parent.remove (item); // this will set item's parent to null + * new_parent.add (item); + * }}} + * + * @param item The item to add. Its parent __must__ be //null//. + * @see Code.Widgets.SourceList.ExpandableItem.child_added + * @see Code.Widgets.SourceList.ExpandableItem.remove + * @since 0.2 + */ + public void add (Item item) requires (item.parent == null) { + item.parent = this; + children_list.add (item); + child_added (item); + } + + /** + * Removes an item. + * + * The {@link Code.Widgets.SourceList.ExpandableItem.child_removed} signal is fired + * //after removing the item//. Finally (i.e. after all the handlers have been invoked), + * the item's {@link Code.Widgets.SourceList.Item.parent} property is set to //null//. + * This has the advantage of letting signal handlers know the parent from which //item// + * is being removed. + * + * @param item The item to remove. This will fail if item has a different parent. + * @see Code.Widgets.SourceList.ExpandableItem.child_removed + * @see Code.Widgets.SourceList.ExpandableItem.clear + * @since 0.2 + */ + public void remove (Item item) requires (item.parent == this) { + children_list.remove (item); + child_removed (item); + item.parent = null; + } + + /** + * Removes all the items contained by the item. It works similarly to + * {@link Code.Widgets.SourceList.ExpandableItem.remove}. + * + * @see Code.Widgets.SourceList.ExpandableItem.remove + * @see Code.Widgets.SourceList.ExpandableItem.child_removed + * @since 0.2 + */ + public void clear () { + foreach (var item in children) + remove (item); + } + + /** + * Expands the item and/or its children. + * + * @param inclusive Whether to also expand this item (true), or only its children (false). + * @param recursive Whether to recursively expand all the children (true), or only + * immediate children (false). + * @see Code.Widgets.SourceList.ExpandableItem.expanded + * @since 0.2 + */ + public void expand_all (bool inclusive = true, bool recursive = true) { + set_expansion (this, inclusive, recursive, true); + } + + /** + * Collapses the item and/or its children. + * + * @param inclusive Whether to also collapse this item (true), or only its children (false). + * @param recursive Whether to recursively collapse all the children (true), or only + * immediate children (false). + * @see Code.Widgets.SourceList.ExpandableItem.expanded + * @since 0.2 + */ + public void collapse_all (bool inclusive = true, bool recursive = true) { + set_expansion (this, inclusive, recursive, false); + } + + private static void set_expansion (ExpandableItem item, bool inclusive, bool recursive, bool expanded) { + if (inclusive) + item.expanded = expanded; + + foreach (var child_item in item.children) { + var child_expandable_item = child_item as ExpandableItem; + if (child_expandable_item != null) { + if (recursive) + set_expansion (child_expandable_item, true, true, expanded); + else + child_expandable_item.expanded = expanded; + } + } + } + + /** + * Recursively expands the item along with its parent(s). + * + * @see Code.Widgets.SourceList.ExpandableItem.expanded + * @since 0.2 + */ + public void expand_with_parents () { + // Update parent items first due to GtkTreeView's working internals: + // Expanding children before their parents would not always work, because + // they could be obscured behind a collapsed row by the time the treeview + // tries to expand them, obviously failing. + if (parent != null) + parent.expand_with_parents (); + expanded = true; + } + + /** + * Recursively collapses the item along with its parent(s). + * + * @see Code.Widgets.SourceList.ExpandableItem.expanded + * @since 0.2 + */ + public void collapse_with_parents () { + if (parent != null) + parent.collapse_with_parents (); + expanded = false; + } +} +} diff --git a/src/Widgets/SourceList/SourceListItem.vala b/src/Widgets/SourceList/SourceListItem.vala new file mode 100644 index 0000000000..dfc3fb0a43 --- /dev/null +++ b/src/Widgets/SourceList/SourceListItem.vala @@ -0,0 +1,182 @@ +/* + * Copyright 2019 elementary, Inc. (https://elementary.io) + * Copyright 2012-2014 Victor Martinez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +namespace Code.Widgets.SourceList { +/** + * A source list entry. + * + * Any change made to any of its properties will be ''automatically'' reflected + * by the {@link Code.Widgets.SourceList} widget. + * + * @since 0.2 + */ + +public class Item : Object { + + /** + * Emitted when the user has finished editing the item's name. + * + * By default, if the name doesn't consist of white space, it is automatically assigned + * to the {@link Code.Widgets.SourceList.Item.name} property. The default behavior can + * be changed by overriding this signal. + * @param new_name The item's new name (result of editing.) + * @since 0.2 + */ + public virtual signal void edited (string new_name) { + if (editable && new_name.strip () != "") + this.name = new_name; + } + + /** + * The {@link Code.Widgets.SourceList.Item.activatable} icon was activated. + * + * @see Code.Widgets.SourceList.Item.activatable + * @since 0.2 + */ + public virtual signal void action_activated () { } + + /** + * Emitted when the item is double-clicked or when it is selected and one of the keys: + * Space, Shift+Space, Return or Enter is pressed. This signal is //also// for + * editable items. + * + * @since 0.2 + */ + public virtual signal void activated () { } + + /** + * Parent {@link Code.Widgets.SourceList.ExpandableItem} of the item. + * ''Must not'' be modified. + * + * @since 0.2 + */ + public ExpandableItem parent { get; internal set; } + + /** + * The item's name. Primary and most important information. + * + * @since 0.2 + */ + public string name { get; set; default = ""; } + + /** + * The item's tooltip. If set to null (default), the tooltip for the item will be the + * contents of the {@link Code.Widgets.SourceList.Item.name} property. + * + * @since 5.3 + */ + public string? tooltip { get; set; default = null; } + + /** + * Markup to be used instead of {@link Code.Widgets.SourceList.ExpandableItem.name} + * This would mean that &, <, etc have to be escaped in the text, but basic formatting + * can be done on the item with HTML style tags. + * + * Note: Only the {@link Code.Widgets.SourceList.ExpandableItem.name} property + * is modified for editable items. So this property will be need to updated and + * reformatted with editable items. + * + * @since 5.0 + */ + public string? markup { get; set; default = null; } + + /** + * A badge shown next to the item's name. + * + * It can be used for displaying the number of unread messages in the "Inbox" item, + * for instance. + * + * @since 0.2 + */ + public string badge { get; set; default = ""; } + + /** + * Whether the item's name can be edited from within the source list. + * + * When this property is set to //true//, users can edit the item by pressing + * the F2 key, or by double-clicking its name. + * + * ''This property only works for selectable items''. + * + * @see Code.Widgets.SourceList.Item.selectable + * @see Code.Widgets.SourceList.start_editing_item + * @since 0.2 + */ + public bool editable { get; set; default = false; } + + /** + * Whether the item should appear in the source list's tree or not. + * + * @since 0.2 + */ + public bool visible { get; set; default = true; } + + /** + * Whether the item can be selected or not. + * + * Setting this property to true doesn't guarantee that the item will actually be + * selectable, since there are other external factors to take into account, like the + * item's {@link Code.Widgets.SourceList.Item.visible} property; whether the item is + * a category; the parent item is collapsed, etc. + * + * @see Code.Widgets.SourceList.Item.visible + * @since 0.2 + */ + public bool selectable { get; set; default = true; } + + /** + * Primary icon. + * + * This property should be used to give the user an idea of what the item represents + * (i.e. content type.) + * + * @since 0.2 + */ + public Icon icon { get; set; } + + /** + * An activatable icon that works like a button. + * + * It can be used for e.g. showing an //"eject"// icon on a device's item. + * + * @see Code.Widgets.SourceList.Item.action_activated + * @since 0.2 + */ + public Icon activatable { get; set; } + + /** + * The tooltip for the activatable icon. + * + * @since 5.0 + */ + public string activatable_tooltip { get; set; default = ""; } + + /** + * Creates a new {@link Code.Widgets.SourceList.Item}. + * + * @param name Name of the item. + * @return (transfer full) A new {@link Code.Widgets.SourceList.Item}. + * @since 0.2 + */ + public Item (string name = "") { + this.name = name; + } + + /** + * Invoked when the item is secondary-clicked or when the usual menu keys are pressed. + * + * Note that since Granite 5.0, right clicking on an item no longer selects/activates it, so + * any context menu items should be actioned on the item instance rather than the selected item + * in the SourceList + * + * @return A {@link Gtk.Menu} or //null// if nothing should be displayed. + * @since 0.2 + */ + public virtual GLib.Menu? get_context_menu () { + return null; + } +} +} diff --git a/src/Widgets/SourceList/SourceListTree.vala b/src/Widgets/SourceList/SourceListTree.vala new file mode 100644 index 0000000000..b11097269d --- /dev/null +++ b/src/Widgets/SourceList/SourceListTree.vala @@ -0,0 +1,912 @@ +/* + * Copyright 2019 elementary, Inc. (https://elementary.io) + * Copyright 2012-2014 Victor Martinez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +namespace Code.Widgets.SourceList { +/** + * The tree that actually displays the items. + * + * All the user interaction happens here. + */ +private class Tree : Gtk.TreeView { + + public DataModel data_model { get; construct set; } + + public signal void item_selected (Item? item); + + public Item? selected_item { + get { return selected; } + set { set_selected (value, true); } + } + + public bool editing { + get { return text_cell.editing; } + } + + public Pango.EllipsizeMode ellipsize_mode { + get { return text_cell.ellipsize; } + set { text_cell.ellipsize = value; } + } + + private enum Column { + ITEM, + N_COLS + } + + private Item? selected; + private unowned Item? edited; + + private Gtk.Entry? editable_entry; + private Gtk.CellRendererText text_cell; + private CellRendererIcon icon_cell; + private CellRendererIcon activatable_cell; + private CellRendererBadge badge_cell; + private CellRendererExpander primary_expander_cell; + private CellRendererExpander secondary_expander_cell; + private Gee.HashMap spacer_cells; // cells used for left spacing + private bool unselectable_item_clicked = false; + + private const string DEFAULT_STYLESHEET = """ + .sidebar.badge { + border-radius: 10px; + border-width: 0; + padding: 1px 2px 1px 2px; + font-weight: bold; + } + """; + + private const string STYLE_PROP_LEVEL_INDENTATION = "level-indentation"; + private const string STYLE_PROP_LEFT_PADDING = "left-padding"; + private const string STYLE_PROP_EXPANDER_SPACING = "expander-spacing"; + + static construct { + install_style_property (new ParamSpecInt ( + STYLE_PROP_LEVEL_INDENTATION, + "Level Indentation", + "Space to add at the beginning of every indentation level. Must be an even number.", + 1, + 50, + 6, + ParamFlags.READABLE + )); + + install_style_property (new ParamSpecInt ( + STYLE_PROP_LEFT_PADDING, + "Left Padding", + "Padding added to the left side of the tree. Must be an even number.", + 1, + 50, + 4, + ParamFlags.READABLE + )); + + install_style_property (new ParamSpecInt ( + STYLE_PROP_EXPANDER_SPACING, + "Expander Spacing", + "Space added between an item and its expander. Must be an even number.", + 1, + 50, + 4, + ParamFlags.READABLE + )); + } + + public Tree (DataModel data_model) { + Object (data_model: data_model); + } + + construct { + unowned Gtk.StyleContext style_context = get_style_context (); + style_context.add_class (Gtk.STYLE_CLASS_SIDEBAR); + style_context.add_class ("source-list"); + + var css_provider = new Gtk.CssProvider (); + try { + css_provider.load_from_data (DEFAULT_STYLESHEET, -1); + style_context.add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_FALLBACK); + } catch (Error e) { + warning ("Could not create CSS Provider: %s\nStylesheet:\n%s", e.message, DEFAULT_STYLESHEET); + } + + set_model (data_model); + + halign = valign = Gtk.Align.FILL; + expand = true; + + enable_search = false; + headers_visible = false; + enable_grid_lines = Gtk.TreeViewGridLines.NONE; + + // Deactivate GtkTreeView's built-in expander functionality + expander_column = null; + show_expanders = false; + + var item_column = new Gtk.TreeViewColumn (); + item_column.expand = true; + + insert_column (item_column, Column.ITEM); + + // Now pack the cell renderers. We insert them in reverse order (using pack_end) + // because we want to use TreeViewColumn.pack_start exclusively for inserting + // spacer cell renderers for level-indentation purposes. + // See add_spacer_cell_for_level() for more details. + + // Second expander. Used for main categories + secondary_expander_cell = new CellRendererExpander (); + secondary_expander_cell.is_category_expander = true; + secondary_expander_cell.xpad = 10; + item_column.pack_end (secondary_expander_cell, false); + item_column.set_cell_data_func (secondary_expander_cell, expander_cell_data_func); + + activatable_cell = new CellRendererIcon (); + activatable_cell.xpad = 6; + activatable_cell.activated.connect (on_activatable_activated); + item_column.pack_end (activatable_cell, false); + item_column.set_cell_data_func (activatable_cell, icon_cell_data_func); + + badge_cell = new CellRendererBadge (); + badge_cell.xpad = 1; + badge_cell.xalign = 1; + item_column.pack_end (badge_cell, false); + item_column.set_cell_data_func (badge_cell, badge_cell_data_func); + + text_cell = new Gtk.CellRendererText (); + text_cell.editable_set = true; + text_cell.editable = false; + text_cell.editing_started.connect (on_editing_started); + text_cell.editing_canceled.connect (on_editing_canceled); + text_cell.ellipsize = Pango.EllipsizeMode.END; + text_cell.xalign = 0; + item_column.pack_end (text_cell, true); + item_column.set_cell_data_func (text_cell, name_cell_data_func); + + icon_cell = new CellRendererIcon (); + icon_cell.xpad = 2; + item_column.pack_end (icon_cell, false); + item_column.set_cell_data_func (icon_cell, icon_cell_data_func); + + // First expander. Used for normal expandable items + primary_expander_cell = new CellRendererExpander (); + + int expander_spacing; + style_get (STYLE_PROP_EXPANDER_SPACING, out expander_spacing); + primary_expander_cell.xpad = expander_spacing / 2; + + item_column.pack_end (primary_expander_cell, false); + item_column.set_cell_data_func (primary_expander_cell, expander_cell_data_func); + + // Selection + var selection = get_selection (); + selection.mode = Gtk.SelectionMode.BROWSE; + selection.set_select_function (select_func); + + // Monitor item changes + enable_item_property_monitor (); + + // Add root-level indentation. New levels will be added by update_item_expansion() + add_spacer_cell_for_level (1); + + unset_rows_drag_dest (); + unset_rows_drag_source (); + + var key_controller = new Gtk.EventControllerKey () { + propagation_phase = CAPTURE + }; + add_controller (key_controller); + key_controller.key_released.connect (on_key_release_event); + + var button_controller = new Gtk.GestureClick () { + propagation_phase = CAPTURE + }; + add_controller (button_controller); + button_controller.pressed.connect (on_button_press_event); + button_controller.released.connect (on_button_release_event); + query_tooltip.connect_after (on_query_tooltip); + has_tooltip = true; + } + + ~Tree () { + disable_item_property_monitor (); + } + + private bool on_query_tooltip (int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip) { + Gtk.TreePath path; + Gtk.TreeViewColumn column = get_column (Column.ITEM); + + get_tooltip_context (ref x, ref y, keyboard_tooltip, null, out path, null); + if (path == null) { + return false; + } + + var item = data_model.get_item_from_path (path); + if (item != null) { + bool should_show = false; + + Gdk.Rectangle start_cell_area; + get_cell_area (path, column, out start_cell_area); + + set_tooltip_row (tooltip, path); + + if (item.tooltip == null) { + tooltip.set_markup (item.name); + should_show = true; + } else if (item.tooltip != "") { + tooltip.set_markup (item.tooltip); + should_show = true; + } + + if (keyboard_tooltip) { + return should_show; + } + + if (over_cell (column, path, text_cell, x - start_cell_area.x) || + over_cell (column, path, icon_cell, x - start_cell_area.x)) { + + return should_show; + } else if (over_cell (column, path, activatable_cell, x - start_cell_area.x)) { + if (item.activatable_tooltip == "") { + return false; + } else { + tooltip.set_markup (item.activatable_tooltip); + return true; + } + } + } + + return false; + } + + private static GLib.Value[] append_row_target_entry (GLib.Value[]? orig) { + const GLib.Value row_target_entry = { // vala-lint=naming-convention + "GTK_TREE_MODEL_ROW", + Gtk.TargetFlags.SAME_WIDGET, + 0 + }; + + var entries = new GLib.Value[0]; + entries += row_target_entry; + + if (orig != null) { + foreach (var target_entry in orig) + entries += target_entry; + } + + return entries; + } + + private void enable_item_property_monitor () { + data_model.item_updated.connect_after (on_model_item_updated); + } + + private void disable_item_property_monitor () { + data_model.item_updated.disconnect (on_model_item_updated); + } + + private void on_model_item_updated (Item item) { + // Currently, all the other properties are updated automatically by the + // cell-data functions after a change in the model. + var expandable_item = item as ExpandableItem; + if (expandable_item != null) + update_expansion (expandable_item); + } + + private void add_spacer_cell_for_level ( + int level, + bool check_previous = true + ) requires (level > 0) { + if (spacer_cells == null) + spacer_cells = new Gee.HashMap (); + + if (!spacer_cells.has_key (level)) { + var spacer_cell = new CellRendererSpacer (); + spacer_cell.level = level; + spacer_cells[level] = spacer_cell; + + uint cell_xpadding; + + // The primary expander is not visible for root-level (i.e. first level) + // items, so for the second level of indentation we use a low padding + // because the primary expander will add enough space. For the root level, + // we use left_padding, and level_indentation for the remaining levels. + // The value of cell_xpadding will be allocated *twice* by the cell renderer, + // so we set the value to a half of actual (desired) value. + switch (level) { + case 1: // root + int left_padding; + style_get (STYLE_PROP_LEFT_PADDING, out left_padding); + cell_xpadding = left_padding / 2; + break; + + case 2: // second level + cell_xpadding = 0; + break; + + default: // remaining levels + int level_indentation; + style_get (STYLE_PROP_LEVEL_INDENTATION, out level_indentation); + cell_xpadding = level_indentation / 2; + break; + } + + spacer_cell.xpad = cell_xpadding; + + var item_column = get_column (Column.ITEM); + item_column.pack_start (spacer_cell, false); + item_column.set_cell_data_func (spacer_cell, spacer_cell_data_func); + + // Make sure that the previous indentation levels also exist + if (check_previous) { + for (int i = level - 1; i > 0; i--) + add_spacer_cell_for_level (i, false); + } + } + } + + /** + * Evaluates whether the item at the specified path can be selected or not. + */ + private bool select_func ( + Gtk.TreeSelection selection, + Gtk.TreeModel model, + Gtk.TreePath path, + bool path_currently_selected + ) { + bool selectable = false; + var item = data_model.get_item_from_path (path); + + if (item != null) { + // Main categories ARE NOT selectable, so check for that + if (!data_model.is_category (item, null, path)) + selectable = item.selectable; + } + + return selectable; + } + + private Gtk.TreePath? get_selected_path () { + Gtk.TreePath? selected_path = null; + Gtk.TreeSelection? selection = get_selection (); + + if (selection != null) { + Gtk.TreeModel? model; + var selected_rows = selection.get_selected_rows (out model); + if (selected_rows.length () == 1) + selected_path = selected_rows.nth_data (0); + } + + return selected_path; + } + + private void set_selected (Item? item, bool scroll_to_item) { + if (item == null) { + Gtk.TreeSelection? selection = get_selection (); + if (selection != null) + selection.unselect_all (); + + // As explained in cursor_changed(), we cannot emit signals for this special + // case from there because that wouldn't allow us to implement the behavior + // we want (i.e. restoring the old selection after expanding a previously + // collapsed category) without emitting the undesired item_selected() signal + // along the way. This special case is handled manually, because it *should* + // only happen in response to client code requests and never in response to + // user interaction. We do that here because there's no way to determine + // whether the cursor change came from code (i.e. this method) or user + // interaction from cursor_changed(). + this.selected = null; + item_selected (null); + } else if (item.selectable) { + if (scroll_to_item) + this.scroll_to_item (item); + + var to_select = data_model.get_item_path (item); + if (to_select != null) + set_cursor_on_cell (to_select, get_column (Column.ITEM), text_cell, false); + } + } + + public override void cursor_changed () { + var path = get_selected_path (); + Item? new_item = path != null ? data_model.get_item_from_path (path) : null; + + // Don't do anything if @new_item is null. + // + // The only way 'this.selected' can be null is by setting it explicitly to + // that value from client code, and thus we handle that case in set_selected(). + // THIS CANNOT HAPPEN IN RESPONSE TO USER INTERACTION. For example, if an + // item is un-selected because its parent category has been collapsed, then it will + // remain as the current selected item (not in reality, just as the value of + // this.selected) and will be re-selected after the parent is expanded again. + // THIS ALL HAPPENS SILENTLY BEHIND THE SCENES, so client code will never know + // it ever happened; the value of selected_item remains unchanged and item_selected() + // is not emitted. + if (new_item != null && new_item != this.selected) { + this.selected = new_item; + item_selected (new_item); + } + } + + public bool scroll_to_item (Item item, bool use_align = false, float row_align = 0) { + bool scrolled = false; + + var path = data_model.get_item_path (item); + if (path != null) { + scroll_to_cell (path, null, use_align, row_align, 0); + scrolled = true; + } + + return scrolled; + } + + public bool start_editing_item (Item item) requires (item.editable) requires (item.selectable) { + if (editing && item == edited) // If same item again, simply return. + return false; + + var path = data_model.get_item_path (item); + if (path != null) { + edited = item; + text_cell.editable = true; + set_cursor_on_cell (path, get_column (Column.ITEM), text_cell, true); + } else { + warning ("Could not edit \"%s\": path not found", item.name); + } + + return editing; + } + + public void stop_editing () { + if (editing && edited != null) { + var path = data_model.get_item_path (edited); + + // Setting the cursor on the same cell without starting an edit cancels any + // editing operation going on. + if (path != null) + set_cursor_on_cell (path, get_column (Column.ITEM), text_cell, false); + } + } + + private void on_editing_started (Gtk.CellEditable editable, string path) { + editable_entry = editable as Gtk.Entry; + if (editable_entry != null) { + editable_entry.editing_done.connect (on_editing_done); + editable_entry.editable = true; + } + } + + private void on_editing_canceled () { + if (editable_entry != null) { + editable_entry.editable = false; + editable_entry.editing_done.disconnect (on_editing_done); + } + + text_cell.editable = false; + edited = null; + } + + private void on_editing_done () { + if (edited != null && edited.editable && editable_entry != null) + edited.edited (editable_entry.get_text ()); + + // Same actions as when canceling editing + on_editing_canceled (); + } + + private void on_activatable_activated (string item_path_str) { + var item = get_item_from_path_string (item_path_str); + if (item != null) + item.action_activated (); + } + + private Item? get_item_from_path_string (string item_path_str) { + var item_path = new Gtk.TreePath.from_string (item_path_str); + return data_model.get_item_from_path (item_path); + } + + private bool toggle_expansion (ExpandableItem item) { + if (item.collapsible) { + item.expanded = !item.expanded; + return true; + } + return false; + } + + /** + * Updates the tree to reflect the ''expanded'' property of expandable_item. + */ + public void update_expansion (ExpandableItem expandable_item) { + var path = data_model.get_item_path (expandable_item); + + if (path != null) { + // Make sure that the indentation cell for the item's level exists. + // We use +1 because the method will make sure that the previous + // indentation levels exist too. + add_spacer_cell_for_level (path.get_depth () + 1); + + if (expandable_item.expanded) { + expand_row (path, false); + + // Since collapsing an item un-selects any child item previously selected, + // we need to restore the selection. This will be done silently because + // set_selected checks for equality between the previously "selected" + // item and the newly selected, and only emits the item_selected() signal + // if they are different. See cursor_changed() for a better explanation + // of this behavior. + if (selected != null && selected.parent == expandable_item) + set_selected (selected, true); + + // Collapsing expandable_item's row also collapsed all its children, + // and thus we need to update the "expanded" property of each of them + // to reflect their previous state. + foreach (var child_item in expandable_item.children) { + var child_expandable_item = child_item as ExpandableItem; + if (child_expandable_item != null) + update_expansion (child_expandable_item); + } + } else { + collapse_row (path); + } + } + } + + public override void row_expanded (Gtk.TreeIter iter, Gtk.TreePath path) { + var item = data_model.get_item (iter) as ExpandableItem; + return_if_fail (item != null); + + disable_item_property_monitor (); + item.expanded = true; + enable_item_property_monitor (); + } + + public override void row_collapsed (Gtk.TreeIter iter, Gtk.TreePath path) { + var item = data_model.get_item (iter) as ExpandableItem; + return_if_fail (item != null); + + disable_item_property_monitor (); + item.expanded = false; + enable_item_property_monitor (); + } + + public override void row_activated (Gtk.TreePath path, Gtk.TreeViewColumn column) { + if (column == get_column (Column.ITEM)) { + var item = data_model.get_item_from_path (path); + if (item != null) + item.activated (); + } + } + + public bool on_key_release_event (uint keyval, uint keycode, Gdk.ModifierType state) { + if (selected_item != null) { + switch (event.keyval) { + case Gdk.Key.F2: + var modifiers = Gtk.accelerator_get_default_mod_mask (); + // try to start editing selected item + if ((event.state & modifiers) == 0 && selected_item.editable) + start_editing_item (selected_item); + break; + + case Gdk.Key.Menu: + Gtk.TreePath? path; + int ix = (int) x; + int iy = (int) y; + if (get_treepath_at_pos ( + ix, + iy, + out path, + null, null, null + )) { + var item = data_model.get_item_from_path (path); + popup_context_menu ((ExpandableItem) item, ix, iy); + } + + break; + } + } + + return Gdk.EVENT_PROPAGATE; + // return base.key_release_event (event); + } + + public void on_button_release_event (uint n_press, double x, double y) { + if (unselectable_item_clicked && event.window == get_bin_window ()) { + unselectable_item_clicked = false; + + Gtk.TreePath path; + Gtk.TreeViewColumn column; + int x = (int) event.x, y = (int) event.y, cell_x, cell_y; + + if (get_path_at_pos (x, y, out path, out column, out cell_x, out cell_y)) { + var item = data_model.get_item_from_path (path) as ExpandableItem; + + if (item != null) { + if (!item.selectable || data_model.is_category (item, null, path)) + toggle_expansion (item); + } + } + } + } + + public void on_button_press_event (Gtk.GestureClick controller, uint n_press, double x, double y) { + Gtk.TreePath path; + Gtk.TreeViewColumn column; + int ix = (int) x, iy = (int) y, cell_x, cell_y; + + if (get_path_at_pos (ix, iy, out path, out column, out cell_x, out cell_y)) { + var item = data_model.get_item_from_path (path); + + // This is needed because the treeview adds an offset at the beginning of every level + Gdk.Rectangle start_cell_area; + get_cell_area (path, get_column (0), out start_cell_area); + cell_x -= start_cell_area.x; + + if (item != null && column == get_column (Column.ITEM)) { + // Cancel any editing operation going on + stop_editing (); + + if (controller.button == Gdk.BUTTON_SECONDARY) { + popup_context_menu (item, ix, iy); + return true; + } else if (controller.button == Gdk.BUTTON_PRIMARY) { + // Check whether an expander (or an equivalent area) was clicked. + bool is_expandable = item is ExpandableItem; + bool is_category = is_expandable && data_model.is_category (item, null, path); + + if (n_press == 1) { + if (is_expandable) { + // Checking for secondary_expander_cell is not necessary because the entire row + // serves for this purpose when the item is a category or when the item is a + // normal expandable item that is not selectable (special care is taken to + // not break the activatable/action icons for such cases). + // The expander only works like a visual indicator for these items. + unselectable_item_clicked = is_category + || (!item.selectable && !over_cell (column, path, activatable_cell, cell_x)); + + if (!unselectable_item_clicked + && over_primary_expander (column, path, cell_x) + && toggle_expansion (item as ExpandableItem)) + return true; + } + } else if ( + n_press == 2 + && !is_category // Main categories are *not* editable + && item.editable + && item.selectable + && over_cell (column, path, text_cell, cell_x) + && start_editing_item (item) + ) { + // The user double-clicked over the text cell, and editing started successfully. + return true; + } + } + } + } + } + + private bool over_primary_expander (Gtk.TreeViewColumn col, Gtk.TreePath path, int x) { + Gtk.TreeIter iter; + if (!model.get_iter (out iter, path)) + return false; + + // Call the cell-data function and make it assign the proper visibility state to the cell + expander_cell_data_func (col, primary_expander_cell, model, iter); + + if (!primary_expander_cell.visible) + return false; + + // We want to return false if the cell is not expandable (i.e. the arrow is hidden) + if (model.iter_n_children (iter) < 1) + return false; + + // Now that we're sure that the item is expandable, let's see if the user clicked + // over the expander area. We don't do so directly by querying the primary expander + // position because it's not fixed, yielding incorrect coordinates depending on whether + // a different area was re-drawn before this method was called. We know that the last + // spacer cell precedes (in a LTR fashion) the expander cell. Because the position + // of the spacer cell is fixed, we can safely query it. + int indentation_level = path.get_depth (); + var last_spacer_cell = spacer_cells[indentation_level]; + + if (last_spacer_cell != null) { + int cell_x, cell_width; + + if (col.cell_get_position (last_spacer_cell, out cell_x, out cell_width)) { + // Add a pixel so that the expander area is a bit wider + int expander_width = get_cell_width (primary_expander_cell) + 1; + + var dir = get_direction (); + if (dir == Gtk.TextDirection.NONE) { + dir = Gtk.Widget.get_default_direction (); + } + + if (dir == Gtk.TextDirection.LTR) { + int indentation_offset = cell_x + cell_width; + return x >= indentation_offset && x <= indentation_offset + expander_width; + } + + return x <= cell_x && x >= cell_x - expander_width; + } + } + + return false; + } + + private bool over_cell (Gtk.TreeViewColumn col, Gtk.TreePath path, Gtk.CellRenderer cell, int x) { + int cell_x, cell_width; + bool found = col.cell_get_position (cell, out cell_x, out cell_width); + return found && x > cell_x && x < cell_x + cell_width; + } + + private int get_cell_width (Gtk.CellRenderer cell_renderer) { + Gtk.Requisition min_req; + cell_renderer.get_preferred_size (this, out min_req, null); + return min_req.width; + } + + private bool popup_context_menu (Item? item, int x, int y) { + if (item == null) + item = selected_item; + + if (item != null) { + var menu = item.get_context_menu (); // GLib.Menu + if (menu == null) { + return; + } + // Taken from Terminal code + var new_context_menu = new Gtk.PopoverMenu.from_model (menu) { + has_arrow = false + }; + new_context_menu.set_parent (this); + new_context_menu.set_pointing_to ({x, y, 1, 1}); + new_context_menu.closed.connect (() => new_context_menu.destroy ()); + new_context_menu.popup (); + } + + return false; + } + + private static Item? get_item_from_model (Gtk.TreeModel model, Gtk.TreeIter iter) { + var data_model = model as DataModel; + assert (data_model != null); + return data_model.get_item (iter); + } + + private static void spacer_cell_data_func ( + Gtk.CellLayout layout, + Gtk.CellRenderer renderer, + Gtk.TreeModel model, + Gtk.TreeIter iter + ) { + var spacer = renderer as CellRendererSpacer; + assert (spacer != null); + assert (spacer.level > 0); + + var path = model.get_path (iter); + + int level = -1; + if (path != null) + level = path.get_depth (); + + renderer.visible = spacer.level <= level; + } + + private void name_cell_data_func ( + Gtk.CellLayout layout, + Gtk.CellRenderer renderer, + Gtk.TreeModel model, + Gtk.TreeIter iter + ) { + var text_renderer = renderer as Gtk.CellRendererText; + assert (text_renderer != null); + + var text = new StringBuilder (); + var weight = Pango.Weight.NORMAL; + bool use_markup = false; + + var item = get_item_from_model (model, iter); + if (item != null) { + if (item.markup != null) { + text.append (item.markup); + use_markup = true; + } else { + text.append (item.name); + } + + if (data_model.is_category (item, iter)) + weight = Pango.Weight.BOLD; + } + + text_renderer.weight = weight; + if (use_markup) { + text_renderer.markup = text.str; + } else { + text_renderer.text = text.str; + } + } + + private void badge_cell_data_func ( + Gtk.CellLayout layout, + Gtk.CellRenderer renderer, + Gtk.TreeModel model, + Gtk.TreeIter iter + ) { + var badge_renderer = renderer as CellRendererBadge; + assert (badge_renderer != null); + + string text = ""; + bool visible = false; + + var item = get_item_from_model (model, iter); + if (item != null) { + // Badges are not displayed for main categories + visible = !data_model.is_category (item, iter) + && item.badge != null + && item.badge.strip () != ""; + + if (visible) + text = item.badge; + } + + badge_renderer.visible = visible; + badge_renderer.text = text; + } + + private void icon_cell_data_func ( + Gtk.CellLayout layout, + Gtk.CellRenderer renderer, + Gtk.TreeModel model, Gtk.TreeIter iter + ) { + var icon_renderer = renderer as CellRendererIcon; + assert (icon_renderer != null); + + bool visible = false; + Icon? icon = null; + + var item = get_item_from_model (model, iter); + if (item != null) { + // Icons are not displayed for main categories + visible = !data_model.is_category (item, iter); + + if (visible) { + if (icon_renderer == icon_cell) + icon = item.icon; + else if (icon_renderer == activatable_cell) + icon = item.activatable; + else + assert_not_reached (); + } + } + + visible = visible && icon != null; + + icon_renderer.visible = visible; + icon_renderer.gicon = visible ? icon : null; + } + + /** + * Controls expander visibility. + */ + private void expander_cell_data_func ( + Gtk.CellLayout layout, + Gtk.CellRenderer renderer, + Gtk.TreeModel model, + Gtk.TreeIter iter + ) { + var item = get_item_from_model (model, iter); + if (item != null) { + // Gtk.CellRenderer.is_expander takes into account whether the item has children or not. + // The tree-view checks for that and sets this property for us. It also sets + // Gtk.CellRenderer.is_expanded, and thus we don't need to check for that either. + var expandable_item = item as ExpandableItem; + if (expandable_item != null) + renderer.is_expander = renderer.is_expander && expandable_item.collapsible; + } + + if (renderer == primary_expander_cell) + renderer.visible = !data_model.is_iter_at_root_level (iter); + else if (renderer == secondary_expander_cell) + renderer.visible = data_model.is_category (item, iter); + else + assert_not_reached (); + } +} +} diff --git a/src/meson.build b/src/meson.build index 08497a1100..e2760b451a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -49,7 +49,13 @@ code_files = files( 'Widgets/SearchBar.vala', 'Widgets/SourceList/CellRendererBadge.vala', 'Widgets/SourceList/CellRendererExpander.vala', + 'Widgets/SourceList/CellRendererIcon.vala', + 'Widgets/SourceList/CellRendererSpacer.vala', 'Widgets/SourceList/SourceList.vala', + 'Widgets/SourceList/SourceListDataModel.vala', + 'Widgets/SourceList/SourceListExpandableItem.vala', + 'Widgets/SourceList/SourceListItem.vala', + 'Widgets/SourceList/SourceListTree.vala', 'Widgets/SourceView.vala', 'Widgets/Terminal.vala', 'Widgets/WelcomeView.vala', diff --git a/vapi/libpeas-2.vapi b/vapi/libpeas-2.vapi new file mode 100644 index 0000000000..c870b6a04b --- /dev/null +++ b/vapi/libpeas-2.vapi @@ -0,0 +1,136 @@ +/* libpeas-2.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "Peas", gir_namespace = "Peas", gir_version = "2", lower_case_cprefix = "peas_")] +namespace Peas { + [CCode (cheader_filename = "libpeas.h", type_id = "peas_engine_get_type ()")] + public sealed class Engine : GLib.Object, GLib.ListModel { + [CCode (has_construct_function = false)] + public Engine (); + public void add_search_path (string module_dir, string? data_dir); + public GLib.Object create_extension_with_properties (Peas.PluginInfo info, GLib.Type extension_type, [CCode (array_length_cname = "n_properties", array_length_pos = 2.5, array_length_type = "guint")] string[] prop_names, [CCode (array_length_cname = "n_properties", array_length_pos = 2.5, array_length_type = "guint")] GLib.Value[] prop_values); + [CCode (array_length = false, array_null_terminated = true)] + public string[] dup_loaded_plugins (); + public void enable_loader (string loader_name); + public void garbage_collect (); + public static unowned Peas.Engine get_default (); + public unowned Peas.PluginInfo get_plugin_info (string plugin_name); + public bool provides_extension (Peas.PluginInfo info, GLib.Type extension_type); + public void rescan_plugins (); + public void set_loaded_plugins ([CCode (array_length = false, array_null_terminated = true)] string[]? plugin_names); + [CCode (has_construct_function = false)] + public Engine.with_nonglobal_loaders (); + [CCode (array_length = false, array_null_terminated = true)] + [NoAccessorMethod] + public string[] loaded_plugins { owned get; set; } + [NoAccessorMethod] + public bool nonglobal_loaders { get; construct; } + [HasEmitter] + public signal void load_plugin (Peas.PluginInfo info); + [HasEmitter] + public signal void unload_plugin (Peas.PluginInfo info); + } + [CCode (cheader_filename = "libpeas.h", type_id = "peas_extension_base_get_type ()")] + public abstract class ExtensionBase : GLib.Object { + [CCode (has_construct_function = false)] + protected ExtensionBase (); + public string get_data_dir (); + public unowned Peas.PluginInfo get_plugin_info (); + public string data_dir { owned get; } + public Peas.PluginInfo plugin_info { get; construct; } + } + [CCode (cheader_filename = "libpeas.h", type_id = "peas_extension_set_get_type ()")] + public sealed class ExtensionSet : GLib.Object, GLib.ListModel { + [CCode (has_construct_function = false)] + protected ExtensionSet (); + public void @foreach (Peas.ExtensionSetForeachFunc func, void* data); + public unowned GLib.Object? get_extension (Peas.PluginInfo info); + [CCode (has_construct_function = false)] + public ExtensionSet.with_properties (Peas.Engine? engine, GLib.Type exten_type, [CCode (array_length_cname = "n_properties", array_length_pos = 2.5, array_length_type = "guint")] string[] prop_names, [CCode (array_length_cname = "n_properties", array_length_pos = 2.5, array_length_type = "guint")] GLib.Value[] prop_values); + [NoAccessorMethod] + public void* construct_properties { construct; } + [NoAccessorMethod] + public Peas.Engine engine { owned get; construct; } + [NoAccessorMethod] + public GLib.Type extension_type { get; construct; } + public signal void extension_added (Peas.PluginInfo info, GLib.Object extension); + public signal void extension_removed (Peas.PluginInfo info, GLib.Object extension); + } + [CCode (cheader_filename = "libpeas.h", type_id = "peas_object_module_get_type ()")] + public class ObjectModule : GLib.TypeModule, GLib.TypePlugin { + [CCode (has_construct_function = false)] + protected ObjectModule (); + public void register_extension_factory (GLib.Type exten_type, owned Peas.FactoryFunc factory_func); + public void register_extension_type (GLib.Type exten_type, GLib.Type impl_type); + [NoAccessorMethod] + public bool local_linkage { get; construct; } + [NoAccessorMethod] + public string module_name { owned get; construct; } + [NoAccessorMethod] + public string path { owned get; construct; } + [NoAccessorMethod] + public bool resident { get; construct; } + [NoAccessorMethod] + public string symbol { owned get; construct; } + } + [CCode (cheader_filename = "libpeas.h", type_id = "peas_plugin_info_get_type ()")] + public sealed class PluginInfo : GLib.Object { + [CCode (has_construct_function = false)] + protected PluginInfo (); + public static GLib.Quark error_quark (); + [CCode (array_length = false, array_null_terminated = true)] + public unowned string[] get_authors (); + public unowned string get_copyright (); + public unowned string get_data_dir (); + [CCode (array_length = false, array_null_terminated = true)] + public unowned string[] get_dependencies (); + public unowned string get_description (); + [Version (since = "1.6")] + public unowned string? get_external_data (string key); + public unowned string get_help_uri (); + public unowned string get_icon_name (); + public unowned string get_module_dir (); + public unowned string get_module_name (); + public unowned string get_name (); + public GLib.Resource get_resource (string? filename) throws GLib.Error; + [Version (since = "1.4")] + public GLib.Settings? get_settings (string? schema_id); + public unowned string get_version (); + public unowned string get_website (); + public bool has_dependency (string module_name); + public bool is_available () throws GLib.Error; + public bool is_builtin (); + public bool is_hidden (); + public bool is_loaded (); + public void load_resource (string? filename) throws GLib.Error; + [CCode (array_length = false, array_null_terminated = true)] + public string[] authors { get; } + [NoAccessorMethod] + public bool builtin { get; } + public string copyright { get; } + [CCode (array_length = false, array_null_terminated = true)] + public string[] dependencies { get; } + public string description { get; } + public string help_uri { get; } + [NoAccessorMethod] + public bool hidden { get; } + public string icon_name { get; } + [NoAccessorMethod] + public bool loaded { get; } + public string module_dir { get; } + public string module_name { get; } + public string name { get; } + public string version { get; } + public string website { get; } + } + [CCode (cheader_filename = "libpeas.h", cprefix = "PEAS_PLUGIN_INFO_ERROR_", has_type_id = false)] + public enum PluginInfoError { + LOADING_FAILED, + LOADER_NOT_FOUND, + DEP_NOT_FOUND, + DEP_LOADING_FAILED + } + [CCode (cheader_filename = "libpeas.h", has_target = false)] + public delegate void ExtensionSetForeachFunc (Peas.ExtensionSet @set, Peas.PluginInfo info, GLib.Object extension, void* data); + [CCode (cheader_filename = "libpeas.h", instance_pos = 1.9)] + public delegate GLib.Object FactoryFunc ([CCode (array_length_cname = "n_parameters", array_length_pos = 0.5, array_length_type = "guint")] GLib.Parameter[] parameters); +}