From 5ded9cba8563f336939400303d6a841d5089b107 Mon Sep 17 00:00:00 2001 From: Perberos Date: Mon, 7 Nov 2011 19:52:18 -0300 Subject: renaming from gedit to pluma --- plugins/changecase/Makefile.am | 18 +- .../changecase/changecase.gedit-plugin.desktop.in | 8 - .../changecase/changecase.pluma-plugin.desktop.in | 8 + plugins/changecase/gedit-changecase-plugin.c | 395 --- plugins/changecase/gedit-changecase-plugin.h | 72 - plugins/changecase/pluma-changecase-plugin.c | 395 +++ plugins/changecase/pluma-changecase-plugin.h | 72 + plugins/checkupdate/Makefile.am | 20 +- .../checkupdate.gedit-plugin.desktop.in | 9 - .../checkupdate.pluma-plugin.desktop.in | 9 + plugins/checkupdate/gedit-check-update-plugin.c | 697 ---- plugins/checkupdate/gedit-check-update-plugin.h | 74 - plugins/checkupdate/gedit-check-update.schemas.in | 13 - plugins/checkupdate/pluma-check-update-plugin.c | 697 ++++ plugins/checkupdate/pluma-check-update-plugin.h | 74 + plugins/checkupdate/pluma-check-update.schemas.in | 13 + plugins/docinfo/Makefile.am | 18 +- plugins/docinfo/docinfo.gedit-plugin.desktop.in | 7 - plugins/docinfo/docinfo.pluma-plugin.desktop.in | 7 + plugins/docinfo/gedit-docinfo-plugin.c | 580 ---- plugins/docinfo/gedit-docinfo-plugin.h | 75 - plugins/docinfo/pluma-docinfo-plugin.c | 580 ++++ plugins/docinfo/pluma-docinfo-plugin.h | 75 + plugins/externaltools/Makefile.am | 8 +- plugins/externaltools/data/Makefile.am | 4 +- plugins/externaltools/data/build.desktop.in | 2 +- plugins/externaltools/data/build.tool.in | 2 +- .../data/open-terminal-here-osx.desktop.in | 2 +- .../data/open-terminal-here-osx.tool.in | 2 +- .../data/open-terminal-here.desktop.in | 2 +- .../externaltools/data/open-terminal-here.tool.in | 2 +- .../data/remove-trailing-spaces.desktop.in | 2 +- plugins/externaltools/data/run-command.desktop.in | 2 +- plugins/externaltools/data/run-command.tool.in | 2 +- .../externaltools.gedit-plugin.desktop.in | 9 - .../externaltools.pluma-plugin.desktop.in | 9 + plugins/externaltools/scripts/Makefile.am | 2 +- plugins/externaltools/scripts/gedit-tool-merge.pl | 78 - plugins/externaltools/scripts/pluma-tool-merge.pl | 78 + plugins/externaltools/tools/Makefile.am | 4 +- plugins/externaltools/tools/__init__.py | 10 +- plugins/externaltools/tools/capture.py | 2 +- plugins/externaltools/tools/filelookup.py | 6 +- plugins/externaltools/tools/functions.py | 38 +- plugins/externaltools/tools/library.py | 20 +- plugins/externaltools/tools/manager.py | 12 +- plugins/externaltools/tools/outputpanel.py | 6 +- plugins/externaltools/tools/tools.ui | 4 +- plugins/filebrowser/Makefile.am | 84 +- .../filebrowser.gedit-plugin.desktop.in | 10 - .../filebrowser.pluma-plugin.desktop.in | 10 + plugins/filebrowser/gedit-file-bookmarks-store.c | 879 ----- plugins/filebrowser/gedit-file-bookmarks-store.h | 90 - .../gedit-file-browser-enum-register.c.template | 20 - .../gedit-file-browser-enum-types.c.template | 45 - .../gedit-file-browser-enum-types.h.template | 29 - plugins/filebrowser/gedit-file-browser-error.h | 41 - .../filebrowser/gedit-file-browser-marshal.list | 5 - plugins/filebrowser/gedit-file-browser-messages.c | 1033 ------ plugins/filebrowser/gedit-file-browser-messages.h | 35 - plugins/filebrowser/gedit-file-browser-plugin.c | 1254 ------- plugins/filebrowser/gedit-file-browser-plugin.h | 71 - plugins/filebrowser/gedit-file-browser-store.c | 3625 -------------------- plugins/filebrowser/gedit-file-browser-store.h | 200 -- plugins/filebrowser/gedit-file-browser-utils.c | 198 -- plugins/filebrowser/gedit-file-browser-utils.h | 27 - plugins/filebrowser/gedit-file-browser-view.c | 1256 ------- plugins/filebrowser/gedit-file-browser-view.h | 84 - .../filebrowser/gedit-file-browser-widget-ui.xml | 54 - plugins/filebrowser/gedit-file-browser-widget.c | 3143 ----------------- plugins/filebrowser/gedit-file-browser-widget.h | 121 - plugins/filebrowser/gedit-file-browser.schemas.in | 97 - plugins/filebrowser/pluma-file-bookmarks-store.c | 879 +++++ plugins/filebrowser/pluma-file-bookmarks-store.h | 90 + .../pluma-file-browser-enum-register.c.template | 20 + .../pluma-file-browser-enum-types.c.template | 45 + .../pluma-file-browser-enum-types.h.template | 29 + plugins/filebrowser/pluma-file-browser-error.h | 41 + .../filebrowser/pluma-file-browser-marshal.list | 5 + plugins/filebrowser/pluma-file-browser-messages.c | 1033 ++++++ plugins/filebrowser/pluma-file-browser-messages.h | 35 + plugins/filebrowser/pluma-file-browser-plugin.c | 1254 +++++++ plugins/filebrowser/pluma-file-browser-plugin.h | 71 + plugins/filebrowser/pluma-file-browser-store.c | 3625 ++++++++++++++++++++ plugins/filebrowser/pluma-file-browser-store.h | 200 ++ plugins/filebrowser/pluma-file-browser-utils.c | 198 ++ plugins/filebrowser/pluma-file-browser-utils.h | 27 + plugins/filebrowser/pluma-file-browser-view.c | 1256 +++++++ plugins/filebrowser/pluma-file-browser-view.h | 84 + .../filebrowser/pluma-file-browser-widget-ui.xml | 54 + plugins/filebrowser/pluma-file-browser-widget.c | 3143 +++++++++++++++++ plugins/filebrowser/pluma-file-browser-widget.h | 121 + plugins/filebrowser/pluma-file-browser.schemas.in | 97 + plugins/modelines/Makefile.am | 18 +- plugins/modelines/gedit-modeline-plugin.c | 248 -- plugins/modelines/gedit-modeline-plugin.h | 48 - plugins/modelines/modeline-parser.c | 38 +- plugins/modelines/modeline-parser.h | 2 +- .../modelines/modelines.gedit-plugin.desktop.in | 8 - .../modelines/modelines.pluma-plugin.desktop.in | 8 + plugins/modelines/pluma-modeline-plugin.c | 248 ++ plugins/modelines/pluma-modeline-plugin.h | 48 + plugins/pythonconsole/Makefile.am | 8 +- .../pythonconsole.gedit-plugin.desktop.in | 10 - .../pythonconsole.pluma-plugin.desktop.in | 10 + plugins/pythonconsole/pythonconsole/Makefile.am | 4 +- plugins/pythonconsole/pythonconsole/__init__.py | 14 +- plugins/pythonconsole/pythonconsole/config.py | 4 +- plugins/pythonconsole/pythonconsole/console.py | 2 +- plugins/quickopen/Makefile.am | 8 +- .../quickopen/quickopen.gedit-plugin.desktop.in | 10 - .../quickopen/quickopen.pluma-plugin.desktop.in | 10 + plugins/quickopen/quickopen/Makefile.am | 2 +- plugins/quickopen/quickopen/__init__.py | 6 +- plugins/quickopen/quickopen/popup.py | 4 +- plugins/quickopen/quickopen/virtualdirs.py | 2 +- plugins/quickopen/quickopen/windowhelper.py | 10 +- plugins/snippets/Makefile.am | 8 +- plugins/snippets/data/Makefile.am | 2 +- plugins/snippets/data/c.xml | 4 +- plugins/snippets/data/chdr.xml | 4 +- plugins/snippets/data/cpp.xml | 4 +- plugins/snippets/data/docbook.xml | 4 +- plugins/snippets/data/html.xml | 8 +- plugins/snippets/data/java.xml | 2 +- plugins/snippets/data/lang/Makefile.am | 2 +- plugins/snippets/data/latex.xml | 2 +- plugins/snippets/data/python.xml | 4 +- plugins/snippets/data/snippets.xml | 56 +- plugins/snippets/data/xslt.xml | 4 +- plugins/snippets/snippets.gedit-plugin.desktop.in | 9 - plugins/snippets/snippets.pluma-plugin.desktop.in | 9 + plugins/snippets/snippets/Completion.py | 4 +- plugins/snippets/snippets/Document.py | 54 +- plugins/snippets/snippets/Helper.py | 8 +- plugins/snippets/snippets/Library.py | 2 +- plugins/snippets/snippets/Makefile.am | 4 +- plugins/snippets/snippets/Manager.py | 12 +- plugins/snippets/snippets/Parser.py | 2 +- plugins/snippets/snippets/Placeholder.py | 8 +- plugins/snippets/snippets/Snippet.py | 2 +- plugins/snippets/snippets/SubstitutionParser.py | 2 +- plugins/snippets/snippets/WindowHelper.py | 20 +- plugins/snippets/snippets/__init__.py | 18 +- plugins/snippets/snippets/snippets.ui | 4 +- plugins/sort/Makefile.am | 18 +- plugins/sort/gedit-sort-plugin.c | 588 ---- plugins/sort/gedit-sort-plugin.h | 73 - plugins/sort/pluma-sort-plugin.c | 588 ++++ plugins/sort/pluma-sort-plugin.h | 73 + plugins/sort/sort.gedit-plugin.desktop.in | 9 - plugins/sort/sort.pluma-plugin.desktop.in | 9 + plugins/spell/Makefile.am | 58 +- plugins/spell/gedit-automatic-spell-checker.c | 1015 ------ plugins/spell/gedit-automatic-spell-checker.h | 67 - plugins/spell/gedit-spell-checker-dialog.c | 722 ---- plugins/spell/gedit-spell-checker-dialog.h | 92 - plugins/spell/gedit-spell-checker-language.c | 439 --- plugins/spell/gedit-spell-checker-language.h | 51 - plugins/spell/gedit-spell-checker.c | 520 --- plugins/spell/gedit-spell-checker.h | 109 - plugins/spell/gedit-spell-language-dialog.c | 309 -- plugins/spell/gedit-spell-language-dialog.h | 67 - plugins/spell/gedit-spell-marshal.list | 6 - plugins/spell/gedit-spell-plugin.c | 1217 ------- plugins/spell/gedit-spell-plugin.h | 75 - plugins/spell/gedit-spell-utils.c | 94 - plugins/spell/gedit-spell-utils.h | 37 - plugins/spell/pluma-automatic-spell-checker.c | 1015 ++++++ plugins/spell/pluma-automatic-spell-checker.h | 67 + plugins/spell/pluma-spell-checker-dialog.c | 722 ++++ plugins/spell/pluma-spell-checker-dialog.h | 92 + plugins/spell/pluma-spell-checker-language.c | 439 +++ plugins/spell/pluma-spell-checker-language.h | 51 + plugins/spell/pluma-spell-checker.c | 520 +++ plugins/spell/pluma-spell-checker.h | 109 + plugins/spell/pluma-spell-language-dialog.c | 309 ++ plugins/spell/pluma-spell-language-dialog.h | 67 + plugins/spell/pluma-spell-marshal.list | 6 + plugins/spell/pluma-spell-plugin.c | 1217 +++++++ plugins/spell/pluma-spell-plugin.h | 75 + plugins/spell/pluma-spell-utils.c | 94 + plugins/spell/pluma-spell-utils.h | 37 + plugins/spell/spell.gedit-plugin.desktop.in | 9 - plugins/spell/spell.pluma-plugin.desktop.in | 9 + plugins/taglist/HTML.tags.xml.in | 2 +- plugins/taglist/Latex.tags.xml.in | 2 +- plugins/taglist/Makefile.am | 26 +- plugins/taglist/XSLT.tags.xml.in | 4 +- plugins/taglist/XUL.tags.xml.in | 2 +- plugins/taglist/gedit-taglist-plugin-panel.c | 776 ----- plugins/taglist/gedit-taglist-plugin-panel.h | 89 - plugins/taglist/gedit-taglist-plugin-parser.c | 655 ---- plugins/taglist/gedit-taglist-plugin-parser.h | 68 - plugins/taglist/gedit-taglist-plugin.c | 160 - plugins/taglist/gedit-taglist-plugin.h | 85 - plugins/taglist/pluma-taglist-plugin-panel.c | 776 +++++ plugins/taglist/pluma-taglist-plugin-panel.h | 89 + plugins/taglist/pluma-taglist-plugin-parser.c | 655 ++++ plugins/taglist/pluma-taglist-plugin-parser.h | 68 + plugins/taglist/pluma-taglist-plugin.c | 160 + plugins/taglist/pluma-taglist-plugin.h | 85 + plugins/taglist/taglist.gedit-plugin.desktop.in | 8 - plugins/taglist/taglist.pluma-plugin.desktop.in | 8 + plugins/time/Makefile.am | 22 +- plugins/time/gedit-time-dialog.ui | 297 -- plugins/time/gedit-time-plugin.c | 1272 ------- plugins/time/gedit-time-plugin.h | 78 - plugins/time/gedit-time-setup-dialog.ui | 330 -- plugins/time/pluma-time-dialog.ui | 297 ++ plugins/time/pluma-time-plugin.c | 1272 +++++++ plugins/time/pluma-time-plugin.h | 78 + plugins/time/pluma-time-setup-dialog.ui | 330 ++ plugins/time/time.gedit-plugin.desktop.in | 8 - plugins/time/time.pluma-plugin.desktop.in | 8 + 215 files changed, 24379 insertions(+), 24379 deletions(-) delete mode 100755 plugins/changecase/changecase.gedit-plugin.desktop.in create mode 100755 plugins/changecase/changecase.pluma-plugin.desktop.in delete mode 100755 plugins/changecase/gedit-changecase-plugin.c delete mode 100755 plugins/changecase/gedit-changecase-plugin.h create mode 100755 plugins/changecase/pluma-changecase-plugin.c create mode 100755 plugins/changecase/pluma-changecase-plugin.h delete mode 100755 plugins/checkupdate/checkupdate.gedit-plugin.desktop.in create mode 100755 plugins/checkupdate/checkupdate.pluma-plugin.desktop.in delete mode 100755 plugins/checkupdate/gedit-check-update-plugin.c delete mode 100755 plugins/checkupdate/gedit-check-update-plugin.h delete mode 100755 plugins/checkupdate/gedit-check-update.schemas.in create mode 100755 plugins/checkupdate/pluma-check-update-plugin.c create mode 100755 plugins/checkupdate/pluma-check-update-plugin.h create mode 100755 plugins/checkupdate/pluma-check-update.schemas.in delete mode 100755 plugins/docinfo/docinfo.gedit-plugin.desktop.in create mode 100755 plugins/docinfo/docinfo.pluma-plugin.desktop.in delete mode 100755 plugins/docinfo/gedit-docinfo-plugin.c delete mode 100755 plugins/docinfo/gedit-docinfo-plugin.h create mode 100755 plugins/docinfo/pluma-docinfo-plugin.c create mode 100755 plugins/docinfo/pluma-docinfo-plugin.h delete mode 100755 plugins/externaltools/externaltools.gedit-plugin.desktop.in create mode 100755 plugins/externaltools/externaltools.pluma-plugin.desktop.in delete mode 100755 plugins/externaltools/scripts/gedit-tool-merge.pl create mode 100755 plugins/externaltools/scripts/pluma-tool-merge.pl delete mode 100755 plugins/filebrowser/filebrowser.gedit-plugin.desktop.in create mode 100755 plugins/filebrowser/filebrowser.pluma-plugin.desktop.in delete mode 100755 plugins/filebrowser/gedit-file-bookmarks-store.c delete mode 100755 plugins/filebrowser/gedit-file-bookmarks-store.h delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-register.c.template delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-types.c.template delete mode 100755 plugins/filebrowser/gedit-file-browser-enum-types.h.template delete mode 100755 plugins/filebrowser/gedit-file-browser-error.h delete mode 100755 plugins/filebrowser/gedit-file-browser-marshal.list delete mode 100755 plugins/filebrowser/gedit-file-browser-messages.c delete mode 100755 plugins/filebrowser/gedit-file-browser-messages.h delete mode 100755 plugins/filebrowser/gedit-file-browser-plugin.c delete mode 100755 plugins/filebrowser/gedit-file-browser-plugin.h delete mode 100755 plugins/filebrowser/gedit-file-browser-store.c delete mode 100755 plugins/filebrowser/gedit-file-browser-store.h delete mode 100755 plugins/filebrowser/gedit-file-browser-utils.c delete mode 100755 plugins/filebrowser/gedit-file-browser-utils.h delete mode 100755 plugins/filebrowser/gedit-file-browser-view.c delete mode 100755 plugins/filebrowser/gedit-file-browser-view.h delete mode 100755 plugins/filebrowser/gedit-file-browser-widget-ui.xml delete mode 100755 plugins/filebrowser/gedit-file-browser-widget.c delete mode 100755 plugins/filebrowser/gedit-file-browser-widget.h delete mode 100755 plugins/filebrowser/gedit-file-browser.schemas.in create mode 100755 plugins/filebrowser/pluma-file-bookmarks-store.c create mode 100755 plugins/filebrowser/pluma-file-bookmarks-store.h create mode 100755 plugins/filebrowser/pluma-file-browser-enum-register.c.template create mode 100755 plugins/filebrowser/pluma-file-browser-enum-types.c.template create mode 100755 plugins/filebrowser/pluma-file-browser-enum-types.h.template create mode 100755 plugins/filebrowser/pluma-file-browser-error.h create mode 100755 plugins/filebrowser/pluma-file-browser-marshal.list create mode 100755 plugins/filebrowser/pluma-file-browser-messages.c create mode 100755 plugins/filebrowser/pluma-file-browser-messages.h create mode 100755 plugins/filebrowser/pluma-file-browser-plugin.c create mode 100755 plugins/filebrowser/pluma-file-browser-plugin.h create mode 100755 plugins/filebrowser/pluma-file-browser-store.c create mode 100755 plugins/filebrowser/pluma-file-browser-store.h create mode 100755 plugins/filebrowser/pluma-file-browser-utils.c create mode 100755 plugins/filebrowser/pluma-file-browser-utils.h create mode 100755 plugins/filebrowser/pluma-file-browser-view.c create mode 100755 plugins/filebrowser/pluma-file-browser-view.h create mode 100755 plugins/filebrowser/pluma-file-browser-widget-ui.xml create mode 100755 plugins/filebrowser/pluma-file-browser-widget.c create mode 100755 plugins/filebrowser/pluma-file-browser-widget.h create mode 100755 plugins/filebrowser/pluma-file-browser.schemas.in delete mode 100755 plugins/modelines/gedit-modeline-plugin.c delete mode 100755 plugins/modelines/gedit-modeline-plugin.h delete mode 100755 plugins/modelines/modelines.gedit-plugin.desktop.in create mode 100755 plugins/modelines/modelines.pluma-plugin.desktop.in create mode 100755 plugins/modelines/pluma-modeline-plugin.c create mode 100755 plugins/modelines/pluma-modeline-plugin.h delete mode 100755 plugins/pythonconsole/pythonconsole.gedit-plugin.desktop.in create mode 100755 plugins/pythonconsole/pythonconsole.pluma-plugin.desktop.in delete mode 100755 plugins/quickopen/quickopen.gedit-plugin.desktop.in create mode 100755 plugins/quickopen/quickopen.pluma-plugin.desktop.in delete mode 100755 plugins/snippets/snippets.gedit-plugin.desktop.in create mode 100755 plugins/snippets/snippets.pluma-plugin.desktop.in delete mode 100755 plugins/sort/gedit-sort-plugin.c delete mode 100755 plugins/sort/gedit-sort-plugin.h create mode 100755 plugins/sort/pluma-sort-plugin.c create mode 100755 plugins/sort/pluma-sort-plugin.h delete mode 100755 plugins/sort/sort.gedit-plugin.desktop.in create mode 100755 plugins/sort/sort.pluma-plugin.desktop.in delete mode 100755 plugins/spell/gedit-automatic-spell-checker.c delete mode 100755 plugins/spell/gedit-automatic-spell-checker.h delete mode 100755 plugins/spell/gedit-spell-checker-dialog.c delete mode 100755 plugins/spell/gedit-spell-checker-dialog.h delete mode 100755 plugins/spell/gedit-spell-checker-language.c delete mode 100755 plugins/spell/gedit-spell-checker-language.h delete mode 100755 plugins/spell/gedit-spell-checker.c delete mode 100755 plugins/spell/gedit-spell-checker.h delete mode 100755 plugins/spell/gedit-spell-language-dialog.c delete mode 100755 plugins/spell/gedit-spell-language-dialog.h delete mode 100755 plugins/spell/gedit-spell-marshal.list delete mode 100755 plugins/spell/gedit-spell-plugin.c delete mode 100755 plugins/spell/gedit-spell-plugin.h delete mode 100755 plugins/spell/gedit-spell-utils.c delete mode 100755 plugins/spell/gedit-spell-utils.h create mode 100755 plugins/spell/pluma-automatic-spell-checker.c create mode 100755 plugins/spell/pluma-automatic-spell-checker.h create mode 100755 plugins/spell/pluma-spell-checker-dialog.c create mode 100755 plugins/spell/pluma-spell-checker-dialog.h create mode 100755 plugins/spell/pluma-spell-checker-language.c create mode 100755 plugins/spell/pluma-spell-checker-language.h create mode 100755 plugins/spell/pluma-spell-checker.c create mode 100755 plugins/spell/pluma-spell-checker.h create mode 100755 plugins/spell/pluma-spell-language-dialog.c create mode 100755 plugins/spell/pluma-spell-language-dialog.h create mode 100755 plugins/spell/pluma-spell-marshal.list create mode 100755 plugins/spell/pluma-spell-plugin.c create mode 100755 plugins/spell/pluma-spell-plugin.h create mode 100755 plugins/spell/pluma-spell-utils.c create mode 100755 plugins/spell/pluma-spell-utils.h delete mode 100755 plugins/spell/spell.gedit-plugin.desktop.in create mode 100755 plugins/spell/spell.pluma-plugin.desktop.in delete mode 100755 plugins/taglist/gedit-taglist-plugin-panel.c delete mode 100755 plugins/taglist/gedit-taglist-plugin-panel.h delete mode 100755 plugins/taglist/gedit-taglist-plugin-parser.c delete mode 100755 plugins/taglist/gedit-taglist-plugin-parser.h delete mode 100755 plugins/taglist/gedit-taglist-plugin.c delete mode 100755 plugins/taglist/gedit-taglist-plugin.h create mode 100755 plugins/taglist/pluma-taglist-plugin-panel.c create mode 100755 plugins/taglist/pluma-taglist-plugin-panel.h create mode 100755 plugins/taglist/pluma-taglist-plugin-parser.c create mode 100755 plugins/taglist/pluma-taglist-plugin-parser.h create mode 100755 plugins/taglist/pluma-taglist-plugin.c create mode 100755 plugins/taglist/pluma-taglist-plugin.h delete mode 100755 plugins/taglist/taglist.gedit-plugin.desktop.in create mode 100755 plugins/taglist/taglist.pluma-plugin.desktop.in delete mode 100755 plugins/time/gedit-time-dialog.ui delete mode 100755 plugins/time/gedit-time-plugin.c delete mode 100755 plugins/time/gedit-time-plugin.h delete mode 100755 plugins/time/gedit-time-setup-dialog.ui create mode 100755 plugins/time/pluma-time-dialog.ui create mode 100755 plugins/time/pluma-time-plugin.c create mode 100755 plugins/time/pluma-time-plugin.h create mode 100755 plugins/time/pluma-time-setup-dialog.ui delete mode 100755 plugins/time/time.gedit-plugin.desktop.in create mode 100755 plugins/time/time.pluma-plugin.desktop.in (limited to 'plugins') diff --git a/plugins/changecase/Makefile.am b/plugins/changecase/Makefile.am index 1f165f9e..3886dc86 100755 --- a/plugins/changecase/Makefile.am +++ b/plugins/changecase/Makefile.am @@ -1,29 +1,29 @@ # changecase plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) plugin_LTLIBRARIES = libchangecase.la libchangecase_la_SOURCES = \ - gedit-changecase-plugin.h \ - gedit-changecase-plugin.c + pluma-changecase-plugin.h \ + pluma-changecase-plugin.c libchangecase_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libchangecase_la_LIBADD = $(GEDIT_LIBS) +libchangecase_la_LIBADD = $(PLUMA_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/changecase +uidir = $(PLUMA_PLUGINS_DATA_DIR)/changecase ui_DATA = -plugin_in_files = changecase.gedit-plugin.desktop.in +plugin_in_files = changecase.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(ui_DATA) $(plugin_in_files) diff --git a/plugins/changecase/changecase.gedit-plugin.desktop.in b/plugins/changecase/changecase.gedit-plugin.desktop.in deleted file mode 100755 index 52a226f4..00000000 --- a/plugins/changecase/changecase.gedit-plugin.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Gedit Plugin] -Module=changecase -IAge=2 -_Name=Change Case -_Description=Changes the case of selected text. -Authors=Paolo Borelli -Copyright=Copyright © 2004-2005 Paolo Borelli -Website=http://www.gedit.org diff --git a/plugins/changecase/changecase.pluma-plugin.desktop.in b/plugins/changecase/changecase.pluma-plugin.desktop.in new file mode 100755 index 00000000..d049a9c1 --- /dev/null +++ b/plugins/changecase/changecase.pluma-plugin.desktop.in @@ -0,0 +1,8 @@ +[Pluma Plugin] +Module=changecase +IAge=2 +_Name=Change Case +_Description=Changes the case of selected text. +Authors=Paolo Borelli +Copyright=Copyright © 2004-2005 Paolo Borelli +Website=http://www.pluma.org diff --git a/plugins/changecase/gedit-changecase-plugin.c b/plugins/changecase/gedit-changecase-plugin.c deleted file mode 100755 index 8544aeb0..00000000 --- a/plugins/changecase/gedit-changecase-plugin.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * gedit-changecase-plugin.c - * - * Copyright (C) 2004-2005 - Paolo Borelli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-changecase-plugin.h" - -#include -#include - -#include - -#define WINDOW_DATA_KEY "GeditChangecasePluginWindowData" - -GEDIT_PLUGIN_REGISTER_TYPE(GeditChangecasePlugin, gedit_changecase_plugin) - -typedef enum { - TO_UPPER_CASE, - TO_LOWER_CASE, - INVERT_CASE, - TO_TITLE_CASE, -} ChangeCaseChoice; - -static void -do_upper_case (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end) -{ - GString *s = g_string_new (NULL); - - while (!gtk_text_iter_is_end (start) && - !gtk_text_iter_equal (start, end)) - { - gunichar c, nc; - - c = gtk_text_iter_get_char (start); - nc = g_unichar_toupper (c); - g_string_append_unichar (s, nc); - - gtk_text_iter_forward_char (start); - } - - gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); - gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); - - g_string_free (s, TRUE); -} - -static void -do_lower_case (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end) -{ - GString *s = g_string_new (NULL); - - while (!gtk_text_iter_is_end (start) && - !gtk_text_iter_equal (start, end)) - { - gunichar c, nc; - - c = gtk_text_iter_get_char (start); - nc = g_unichar_tolower (c); - g_string_append_unichar (s, nc); - - gtk_text_iter_forward_char (start); - } - - gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); - gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); - - g_string_free (s, TRUE); -} - -static void -do_invert_case (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end) -{ - GString *s = g_string_new (NULL); - - while (!gtk_text_iter_is_end (start) && - !gtk_text_iter_equal (start, end)) - { - gunichar c, nc; - - c = gtk_text_iter_get_char (start); - if (g_unichar_islower (c)) - nc = g_unichar_toupper (c); - else - nc = g_unichar_tolower (c); - g_string_append_unichar (s, nc); - - gtk_text_iter_forward_char (start); - } - - gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); - gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); - - g_string_free (s, TRUE); -} - -static void -do_title_case (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end) -{ - GString *s = g_string_new (NULL); - - while (!gtk_text_iter_is_end (start) && - !gtk_text_iter_equal (start, end)) - { - gunichar c, nc; - - c = gtk_text_iter_get_char (start); - if (gtk_text_iter_starts_word (start)) - nc = g_unichar_totitle (c); - else - nc = g_unichar_tolower (c); - g_string_append_unichar (s, nc); - - gtk_text_iter_forward_char (start); - } - - gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); - gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); - - g_string_free (s, TRUE); -} - -static void -change_case (GeditWindow *window, - ChangeCaseChoice choice) -{ - GeditDocument *doc; - GtkTextIter start, end; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (window); - g_return_if_fail (doc != NULL); - - if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), - &start, &end)) - { - return; - } - - gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (doc)); - - switch (choice) - { - case TO_UPPER_CASE: - do_upper_case (GTK_TEXT_BUFFER (doc), &start, &end); - break; - case TO_LOWER_CASE: - do_lower_case (GTK_TEXT_BUFFER (doc), &start, &end); - break; - case INVERT_CASE: - do_invert_case (GTK_TEXT_BUFFER (doc), &start, &end); - break; - case TO_TITLE_CASE: - do_title_case (GTK_TEXT_BUFFER (doc), &start, &end); - break; - default: - g_return_if_reached (); - } - - gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (doc)); -} - -static void -upper_case_cb (GtkAction *action, - GeditWindow *window) -{ - change_case (window, TO_UPPER_CASE); -} - -static void -lower_case_cb (GtkAction *action, - GeditWindow *window) -{ - change_case (window, TO_LOWER_CASE); -} - -static void -invert_case_cb (GtkAction *action, - GeditWindow *window) -{ - change_case (window, INVERT_CASE); -} - -static void -title_case_cb (GtkAction *action, - GeditWindow *window) -{ - change_case (window, TO_TITLE_CASE); -} - -static const GtkActionEntry action_entries[] = -{ - { "ChangeCase", NULL, N_("C_hange Case") }, - { "UpperCase", NULL, N_("All _Upper Case"), NULL, - N_("Change selected text to upper case"), - G_CALLBACK (upper_case_cb) }, - { "LowerCase", NULL, N_("All _Lower Case"), NULL, - N_("Change selected text to lower case"), - G_CALLBACK (lower_case_cb) }, - { "InvertCase", NULL, N_("_Invert Case"), NULL, - N_("Invert the case of selected text"), - G_CALLBACK (invert_case_cb) }, - { "TitleCase", NULL, N_("_Title Case"), NULL, - N_("Capitalize the first letter of each selected word"), - G_CALLBACK (title_case_cb) } -}; - -const gchar submenu[] = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - -static void -gedit_changecase_plugin_init (GeditChangecasePlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditChangecasePlugin initializing"); -} - -static void -gedit_changecase_plugin_finalize (GObject *object) -{ - G_OBJECT_CLASS (gedit_changecase_plugin_parent_class)->finalize (object); - - gedit_debug_message (DEBUG_PLUGINS, "GeditChangecasePlugin finalizing"); -} - -typedef struct -{ - GtkActionGroup *action_group; - guint ui_id; -} WindowData; - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - g_slice_free (WindowData, data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GtkTextView *view; - GtkAction *action; - gboolean sensitive = FALSE; - - gedit_debug (DEBUG_PLUGINS); - - view = GTK_TEXT_VIEW (gedit_window_get_active_view (window)); - - if (view != NULL) - { - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (view); - sensitive = (gtk_text_view_get_editable (view) && - gtk_text_buffer_get_has_selection (buffer)); - } - - action = gtk_action_group_get_action (data->action_group, - "ChangeCase"); - gtk_action_set_sensitive (action, sensitive); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - GError *error = NULL; - - gedit_debug (DEBUG_PLUGINS); - - data = g_slice_new (WindowData); - - manager = gedit_window_get_ui_manager (window); - - data->action_group = gtk_action_group_new ("GeditChangecasePluginActions"); - gtk_action_group_set_translation_domain (data->action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions (data->action_group, - action_entries, - G_N_ELEMENTS (action_entries), - window); - - gtk_ui_manager_insert_action_group (manager, data->action_group, -1); - - data->ui_id = gtk_ui_manager_add_ui_from_string (manager, - submenu, - -1, - &error); - if (data->ui_id == 0) - { - g_warning ("%s", error->message); - free_window_data (data); - return; - } - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - update_ui_real (window, data); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, data->ui_id); - gtk_ui_manager_remove_action_group (manager, data->action_group); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, data); -} - -static void -gedit_changecase_plugin_class_init (GeditChangecasePluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_changecase_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; -} diff --git a/plugins/changecase/gedit-changecase-plugin.h b/plugins/changecase/gedit-changecase-plugin.h deleted file mode 100755 index 9587928c..00000000 --- a/plugins/changecase/gedit-changecase-plugin.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * gedit-changecase-plugin.h - * - * Copyright (C) 2004-2005 - Paolo Borelli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_CHANGECASE_PLUGIN_H__ -#define __GEDIT_CHANGECASE_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_CHANGECASE_PLUGIN (gedit_changecase_plugin_get_type ()) -#define GEDIT_CHANGECASE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_CHANGECASE_PLUGIN, GeditChangecasePlugin)) -#define GEDIT_CHANGECASE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_CHANGECASE_PLUGIN, GeditChangecasePluginClass)) -#define GEDIT_IS_CHANGECASE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_CHANGECASE_PLUGIN)) -#define GEDIT_IS_CHANGECASE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_CHANGECASE_PLUGIN)) -#define GEDIT_CHANGECASE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_CHANGECASE_PLUGIN, GeditChangecasePluginClass)) - -/* - * Main object structure - */ -typedef struct _GeditChangecasePlugin GeditChangecasePlugin; - -struct _GeditChangecasePlugin -{ - GeditPlugin parent_instance; -}; - -/* - * Class definition - */ -typedef struct _GeditChangecasePluginClass GeditChangecasePluginClass; - -struct _GeditChangecasePluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_changecase_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_CHANGECASE_PLUGIN_H__ */ diff --git a/plugins/changecase/pluma-changecase-plugin.c b/plugins/changecase/pluma-changecase-plugin.c new file mode 100755 index 00000000..735a6be1 --- /dev/null +++ b/plugins/changecase/pluma-changecase-plugin.c @@ -0,0 +1,395 @@ +/* + * pluma-changecase-plugin.c + * + * Copyright (C) 2004-2005 - Paolo Borelli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-changecase-plugin.h" + +#include +#include + +#include + +#define WINDOW_DATA_KEY "PlumaChangecasePluginWindowData" + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaChangecasePlugin, pluma_changecase_plugin) + +typedef enum { + TO_UPPER_CASE, + TO_LOWER_CASE, + INVERT_CASE, + TO_TITLE_CASE, +} ChangeCaseChoice; + +static void +do_upper_case (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end) +{ + GString *s = g_string_new (NULL); + + while (!gtk_text_iter_is_end (start) && + !gtk_text_iter_equal (start, end)) + { + gunichar c, nc; + + c = gtk_text_iter_get_char (start); + nc = g_unichar_toupper (c); + g_string_append_unichar (s, nc); + + gtk_text_iter_forward_char (start); + } + + gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); + gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); + + g_string_free (s, TRUE); +} + +static void +do_lower_case (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end) +{ + GString *s = g_string_new (NULL); + + while (!gtk_text_iter_is_end (start) && + !gtk_text_iter_equal (start, end)) + { + gunichar c, nc; + + c = gtk_text_iter_get_char (start); + nc = g_unichar_tolower (c); + g_string_append_unichar (s, nc); + + gtk_text_iter_forward_char (start); + } + + gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); + gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); + + g_string_free (s, TRUE); +} + +static void +do_invert_case (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end) +{ + GString *s = g_string_new (NULL); + + while (!gtk_text_iter_is_end (start) && + !gtk_text_iter_equal (start, end)) + { + gunichar c, nc; + + c = gtk_text_iter_get_char (start); + if (g_unichar_islower (c)) + nc = g_unichar_toupper (c); + else + nc = g_unichar_tolower (c); + g_string_append_unichar (s, nc); + + gtk_text_iter_forward_char (start); + } + + gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); + gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); + + g_string_free (s, TRUE); +} + +static void +do_title_case (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end) +{ + GString *s = g_string_new (NULL); + + while (!gtk_text_iter_is_end (start) && + !gtk_text_iter_equal (start, end)) + { + gunichar c, nc; + + c = gtk_text_iter_get_char (start); + if (gtk_text_iter_starts_word (start)) + nc = g_unichar_totitle (c); + else + nc = g_unichar_tolower (c); + g_string_append_unichar (s, nc); + + gtk_text_iter_forward_char (start); + } + + gtk_text_buffer_delete_selection (buffer, TRUE, TRUE); + gtk_text_buffer_insert_at_cursor (buffer, s->str, s->len); + + g_string_free (s, TRUE); +} + +static void +change_case (PlumaWindow *window, + ChangeCaseChoice choice) +{ + PlumaDocument *doc; + GtkTextIter start, end; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (window); + g_return_if_fail (doc != NULL); + + if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &start, &end)) + { + return; + } + + gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (doc)); + + switch (choice) + { + case TO_UPPER_CASE: + do_upper_case (GTK_TEXT_BUFFER (doc), &start, &end); + break; + case TO_LOWER_CASE: + do_lower_case (GTK_TEXT_BUFFER (doc), &start, &end); + break; + case INVERT_CASE: + do_invert_case (GTK_TEXT_BUFFER (doc), &start, &end); + break; + case TO_TITLE_CASE: + do_title_case (GTK_TEXT_BUFFER (doc), &start, &end); + break; + default: + g_return_if_reached (); + } + + gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (doc)); +} + +static void +upper_case_cb (GtkAction *action, + PlumaWindow *window) +{ + change_case (window, TO_UPPER_CASE); +} + +static void +lower_case_cb (GtkAction *action, + PlumaWindow *window) +{ + change_case (window, TO_LOWER_CASE); +} + +static void +invert_case_cb (GtkAction *action, + PlumaWindow *window) +{ + change_case (window, INVERT_CASE); +} + +static void +title_case_cb (GtkAction *action, + PlumaWindow *window) +{ + change_case (window, TO_TITLE_CASE); +} + +static const GtkActionEntry action_entries[] = +{ + { "ChangeCase", NULL, N_("C_hange Case") }, + { "UpperCase", NULL, N_("All _Upper Case"), NULL, + N_("Change selected text to upper case"), + G_CALLBACK (upper_case_cb) }, + { "LowerCase", NULL, N_("All _Lower Case"), NULL, + N_("Change selected text to lower case"), + G_CALLBACK (lower_case_cb) }, + { "InvertCase", NULL, N_("_Invert Case"), NULL, + N_("Invert the case of selected text"), + G_CALLBACK (invert_case_cb) }, + { "TitleCase", NULL, N_("_Title Case"), NULL, + N_("Capitalize the first letter of each selected word"), + G_CALLBACK (title_case_cb) } +}; + +const gchar submenu[] = +"" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +""; + +static void +pluma_changecase_plugin_init (PlumaChangecasePlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaChangecasePlugin initializing"); +} + +static void +pluma_changecase_plugin_finalize (GObject *object) +{ + G_OBJECT_CLASS (pluma_changecase_plugin_parent_class)->finalize (object); + + pluma_debug_message (DEBUG_PLUGINS, "PlumaChangecasePlugin finalizing"); +} + +typedef struct +{ + GtkActionGroup *action_group; + guint ui_id; +} WindowData; + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + g_slice_free (WindowData, data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + GtkTextView *view; + GtkAction *action; + gboolean sensitive = FALSE; + + pluma_debug (DEBUG_PLUGINS); + + view = GTK_TEXT_VIEW (pluma_window_get_active_view (window)); + + if (view != NULL) + { + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer (view); + sensitive = (gtk_text_view_get_editable (view) && + gtk_text_buffer_get_has_selection (buffer)); + } + + action = gtk_action_group_get_action (data->action_group, + "ChangeCase"); + gtk_action_set_sensitive (action, sensitive); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + GError *error = NULL; + + pluma_debug (DEBUG_PLUGINS); + + data = g_slice_new (WindowData); + + manager = pluma_window_get_ui_manager (window); + + data->action_group = gtk_action_group_new ("PlumaChangecasePluginActions"); + gtk_action_group_set_translation_domain (data->action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions (data->action_group, + action_entries, + G_N_ELEMENTS (action_entries), + window); + + gtk_ui_manager_insert_action_group (manager, data->action_group, -1); + + data->ui_id = gtk_ui_manager_add_ui_from_string (manager, + submenu, + -1, + &error); + if (data->ui_id == 0) + { + g_warning ("%s", error->message); + free_window_data (data); + return; + } + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + update_ui_real (window, data); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, data->ui_id); + gtk_ui_manager_remove_action_group (manager, data->action_group); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, data); +} + +static void +pluma_changecase_plugin_class_init (PlumaChangecasePluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_changecase_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; +} diff --git a/plugins/changecase/pluma-changecase-plugin.h b/plugins/changecase/pluma-changecase-plugin.h new file mode 100755 index 00000000..56604352 --- /dev/null +++ b/plugins/changecase/pluma-changecase-plugin.h @@ -0,0 +1,72 @@ +/* + * pluma-changecase-plugin.h + * + * Copyright (C) 2004-2005 - Paolo Borelli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_CHANGECASE_PLUGIN_H__ +#define __PLUMA_CHANGECASE_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_CHANGECASE_PLUGIN (pluma_changecase_plugin_get_type ()) +#define PLUMA_CHANGECASE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_CHANGECASE_PLUGIN, PlumaChangecasePlugin)) +#define PLUMA_CHANGECASE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_CHANGECASE_PLUGIN, PlumaChangecasePluginClass)) +#define PLUMA_IS_CHANGECASE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_CHANGECASE_PLUGIN)) +#define PLUMA_IS_CHANGECASE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_CHANGECASE_PLUGIN)) +#define PLUMA_CHANGECASE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_CHANGECASE_PLUGIN, PlumaChangecasePluginClass)) + +/* + * Main object structure + */ +typedef struct _PlumaChangecasePlugin PlumaChangecasePlugin; + +struct _PlumaChangecasePlugin +{ + PlumaPlugin parent_instance; +}; + +/* + * Class definition + */ +typedef struct _PlumaChangecasePluginClass PlumaChangecasePluginClass; + +struct _PlumaChangecasePluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_changecase_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_CHANGECASE_PLUGIN_H__ */ diff --git a/plugins/checkupdate/Makefile.am b/plugins/checkupdate/Makefile.am index 551b7eee..a49666ca 100755 --- a/plugins/checkupdate/Makefile.am +++ b/plugins/checkupdate/Makefile.am @@ -1,10 +1,10 @@ -# gedit win32 updater +# pluma win32 updater -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(LIBSOUP_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) @@ -12,20 +12,20 @@ INCLUDES = \ plugin_LTLIBRARIES = libcheckupdate.la libcheckupdate_la_SOURCES = \ - gedit-check-update-plugin.h \ - gedit-check-update-plugin.c + pluma-check-update-plugin.h \ + pluma-check-update-plugin.c libcheckupdate_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libcheckupdate_la_LIBADD = $(GEDIT_LIBS) $(LIBSOUP_LIBS) +libcheckupdate_la_LIBADD = $(PLUMA_LIBS) $(LIBSOUP_LIBS) -plugin_in_files = checkupdate.gedit-plugin.desktop.in +plugin_in_files = checkupdate.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) schemasdir = $(MATECONF_SCHEMA_FILE_DIR) -schemas_in_files = gedit-check-update.schemas.in +schemas_in_files = pluma-check-update.schemas.in schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) @INTLTOOL_SCHEMAS_RULE@ diff --git a/plugins/checkupdate/checkupdate.gedit-plugin.desktop.in b/plugins/checkupdate/checkupdate.gedit-plugin.desktop.in deleted file mode 100755 index 4699b6a2..00000000 --- a/plugins/checkupdate/checkupdate.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Module=checkupdate -IAge=2 -_Name=Check update -_Description=Check for latest version of gedit -Icon=gedit-plugin -Authors=Ignacio Casal Quinteiro -Copyright=Copyright © 2009 Ignacio Casal Quinteiro -Website=http://www.gedit.org diff --git a/plugins/checkupdate/checkupdate.pluma-plugin.desktop.in b/plugins/checkupdate/checkupdate.pluma-plugin.desktop.in new file mode 100755 index 00000000..9373ee47 --- /dev/null +++ b/plugins/checkupdate/checkupdate.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Module=checkupdate +IAge=2 +_Name=Check update +_Description=Check for latest version of pluma +Icon=pluma-plugin +Authors=Ignacio Casal Quinteiro +Copyright=Copyright © 2009 Ignacio Casal Quinteiro +Website=http://www.pluma.org diff --git a/plugins/checkupdate/gedit-check-update-plugin.c b/plugins/checkupdate/gedit-check-update-plugin.c deleted file mode 100755 index aa9f7a5e..00000000 --- a/plugins/checkupdate/gedit-check-update-plugin.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2009 - Ignacio Casal Quinteiro - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-check-update-plugin.h" - -#include -#include -#include -#include -#include -#include - -#include - -#if !GTK_CHECK_VERSION(2, 17, 1) -#include -#endif - -#define MATECONF_KEY_BASE "/apps/gedit-2/plugins/checkupdate" -#define MATECONF_KEY_IGNORE_VERSION MATECONF_KEY_BASE "/ignore_version" - -#define WINDOW_DATA_KEY "GeditCheckUpdatePluginWindowData" - -#define VERSION_PLACE "" - -#ifdef G_OS_WIN32 -#define GEDIT_URL "http://ftp.acc.umu.se/pub/mate/binaries/win32/gedit/" -#define FILE_REGEX "gedit\\-setup\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.exe" -#else -#define GEDIT_URL "http://ftp.acc.umu.se/pub/mate/binaries/mac/gedit/" -#define FILE_REGEX "gedit\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.dmg" -#endif - -#ifdef OS_OSX -#include "gedit/osx/gedit-osx.h" -#endif - -#define GEDIT_CHECK_UPDATE_PLUGIN_GET_PRIVATE(object) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GEDIT_TYPE_CHECK_UPDATE_PLUGIN, \ - GeditCheckUpdatePluginPrivate)) - -GEDIT_PLUGIN_REGISTER_TYPE (GeditCheckUpdatePlugin, gedit_check_update_plugin) - -struct _GeditCheckUpdatePluginPrivate -{ - SoupSession *session; - - MateConfClient *mateconf_client; -}; - -typedef struct -{ - GeditCheckUpdatePlugin *plugin; - - gchar *url; - gchar *version; -} WindowData; - -static void -free_window_data (gpointer data) -{ - WindowData *window_data; - - if (data == NULL) - return; - - window_data = (WindowData *)data; - - g_free (window_data->url); - g_free (window_data->version); - g_slice_free (WindowData, data); -} - -static void -gedit_check_update_plugin_init (GeditCheckUpdatePlugin *plugin) -{ - plugin->priv = GEDIT_CHECK_UPDATE_PLUGIN_GET_PRIVATE (plugin); - - gedit_debug_message (DEBUG_PLUGINS, - "GeditCheckUpdatePlugin initializing"); - - plugin->priv->session = soup_session_async_new (); - - plugin->priv->mateconf_client = mateconf_client_get_default (); - - mateconf_client_add_dir (plugin->priv->mateconf_client, - MATECONF_KEY_BASE, - MATECONF_CLIENT_PRELOAD_ONELEVEL, - NULL); -} - -static void -gedit_check_update_plugin_dispose (GObject *object) -{ - GeditCheckUpdatePlugin *plugin = GEDIT_CHECK_UPDATE_PLUGIN (object); - - if (plugin->priv->session != NULL) - { - g_object_unref (plugin->priv->session); - plugin->priv->session = NULL; - } - - if (plugin->priv->mateconf_client != NULL) - { - mateconf_client_suggest_sync (plugin->priv->mateconf_client, NULL); - - g_object_unref (G_OBJECT (plugin->priv->mateconf_client)); - - plugin->priv->mateconf_client = NULL; - } - - gedit_debug_message (DEBUG_PLUGINS, - "GeditCheckUpdatePlugin disposing"); - - G_OBJECT_CLASS (gedit_check_update_plugin_parent_class)->dispose (object); -} - -static void -gedit_check_update_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, - "GeditCheckUpdatePlugin finalizing"); - - G_OBJECT_CLASS (gedit_check_update_plugin_parent_class)->finalize (object); -} - -static void -set_contents (GtkWidget *infobar, - GtkWidget *contents) -{ -#if !GTK_CHECK_VERSION (2, 17, 1) - gedit_message_area_set_contents (GEDIT_MESSAGE_AREA (infobar), - contents); -#else - GtkWidget *content_area; - - content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar)); - gtk_container_add (GTK_CONTAINER (content_area), contents); -#endif -} - -static void -set_message_area_text_and_icon (GtkWidget *message_area, - const gchar *icon_stock_id, - const gchar *primary_text, - const gchar *secondary_text) -{ - GtkWidget *hbox_content; - GtkWidget *image; - GtkWidget *vbox; - gchar *primary_markup; - gchar *secondary_markup; - GtkWidget *primary_label; - GtkWidget *secondary_label; - - hbox_content = gtk_hbox_new (FALSE, 8); - gtk_widget_show (hbox_content); - - image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); - - primary_markup = g_strdup_printf ("%s", primary_text); - primary_label = gtk_label_new (primary_markup); - g_free (primary_markup); - gtk_widget_show (primary_label); - gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); - gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); - gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); - GTK_WIDGET_SET_FLAGS (primary_label, GTK_CAN_FOCUS); - gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE); - - if (secondary_text != NULL) - { - secondary_markup = g_strdup_printf ("%s", - secondary_text); - secondary_label = gtk_label_new (secondary_markup); - g_free (secondary_markup); - gtk_widget_show (secondary_label); - gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); - GTK_WIDGET_SET_FLAGS (secondary_label, GTK_CAN_FOCUS); - gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); - gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE); - gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); - } - - set_contents (message_area, hbox_content); -} - -static void -on_response_cb (GtkWidget *infobar, - gint response_id, - GeditWindow *window) -{ - if (response_id == GTK_RESPONSE_YES) - { - GError *error = NULL; - WindowData *data; - - data = g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - -#ifdef OS_OSX - gedit_osx_show_url (data->url); -#else - gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (window)), - data->url, - GDK_CURRENT_TIME, - &error); -#endif - if (error != NULL) - { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("There was an error displaying the URI.")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); - - g_signal_connect (G_OBJECT (dialog), - "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - - gtk_widget_show (dialog); - - g_error_free (error); - } - } - else if (response_id == GTK_RESPONSE_NO) - { - WindowData *data; - - data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - - mateconf_client_set_string (data->plugin->priv->mateconf_client, - MATECONF_KEY_IGNORE_VERSION, - data->version, - NULL); - } - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); - - gtk_widget_destroy (infobar); -} - -static GtkWidget * -create_infobar (GeditWindow *window, - const gchar *version) -{ - GtkWidget *infobar; - gchar *message; - -#if !GTK_CHECK_VERSION (2, 17, 1) - infobar = gedit_message_area_new (); - - gedit_message_area_add_stock_button_with_text (GEDIT_MESSAGE_AREA (infobar), - _("_Download"), - GTK_STOCK_SAVE, - GTK_RESPONSE_YES); - gedit_message_area_add_stock_button_with_text (GEDIT_MESSAGE_AREA (infobar), - _("_Ignore Version"), - GTK_STOCK_DISCARD, - GTK_RESPONSE_NO); - gedit_message_area_add_button (GEDIT_MESSAGE_AREA (infobar), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL); -#else - GtkWidget *button; - - infobar = gtk_info_bar_new (); - - button = gedit_gtk_button_new_with_stock_icon (_("_Download"), - GTK_STOCK_SAVE); - gtk_widget_show (button); - - gtk_info_bar_add_action_widget (GTK_INFO_BAR (infobar), - button, - GTK_RESPONSE_YES); - - button = gedit_gtk_button_new_with_stock_icon (_("_Ignore Version"), - GTK_STOCK_DISCARD); - gtk_widget_show (button); - - gtk_info_bar_add_action_widget (GTK_INFO_BAR (infobar), - button, - GTK_RESPONSE_NO); - - gtk_info_bar_add_button (GTK_INFO_BAR (infobar), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL); - - gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), - GTK_MESSAGE_INFO); -#endif - - message = g_strdup_printf ("%s (%s)", _("There is a new version of gedit"), version); - set_message_area_text_and_icon (infobar, - "gtk-dialog-info", - message, - _("You can download the new version of gedit" - " by clicking on the download button or" - " ignore that version and wait for a new one")); - - g_free (message); - - g_signal_connect (infobar, "response", - G_CALLBACK (on_response_cb), - window); - - return infobar; -} - -static void -pack_infobar (GtkWidget *window, - GtkWidget *infobar) -{ - GtkWidget *vbox; - - vbox = gtk_bin_get_child (GTK_BIN (window)); - - gtk_box_pack_start (GTK_BOX (vbox), infobar, FALSE, FALSE, 0); - gtk_box_reorder_child (GTK_BOX (vbox), infobar, 2); -} - -static gchar * -get_file (const gchar *text, - const gchar *regex_place) -{ - GRegex *regex; - GMatchInfo *match_info; - gchar *word = NULL; - - regex = g_regex_new (regex_place, 0, 0, NULL); - g_regex_match (regex, text, 0, &match_info); - while (g_match_info_matches (match_info)) - { - g_free (word); - - word = g_match_info_fetch (match_info, 0); - - g_match_info_next (match_info, NULL); - } - g_match_info_free (match_info); - g_regex_unref (regex); - - return word; -} - -static void -get_numbers (const gchar *version, - gint *major, - gint *minor, - gint *micro) -{ - gchar **split; - gint num = 2; - - if (micro != NULL) - num = 3; - - split = g_strsplit (version, ".", num); - *major = atoi (split[0]); - *minor = atoi (split[1]); - if (micro != NULL) - *micro = atoi (split[2]); - - g_strfreev (split); -} - -static gboolean -newer_version (const gchar *v1, - const gchar *v2, - gboolean with_micro) -{ - gboolean newer = FALSE; - gint major1, minor1, micro1; - gint major2, minor2, micro2; - - if (v1 == NULL || v2 == NULL) - return FALSE; - - if (with_micro) - { - get_numbers (v1, &major1, &minor1, µ1); - get_numbers (v2, &major2, &minor2, µ2); - } - else - { - get_numbers (v1, &major1, &minor1, NULL); - get_numbers (v2, &major2, &minor2, NULL); - } - - if (major1 > major2) - { - newer = TRUE; - } - else if (minor1 > minor2 && major1 == major2) - { - newer = TRUE; - } - else if (with_micro && micro1 > micro2 && minor1 == minor2) - { - newer = TRUE; - } - - return newer; -} - -static gchar * -parse_file_version (const gchar *file) -{ - gchar *p, *aux; - - p = (gchar *)file; - - while (*p != '\0' && !g_ascii_isdigit (*p)) - { - p++; - } - - if (*p == '\0') - return NULL; - - aux = g_strrstr (p, "-"); - if (aux == NULL) - aux = g_strrstr (p, "."); - - return g_strndup (p, aux - p); -} - -static gchar * -get_ignore_version (GeditCheckUpdatePlugin *plugin) -{ - return mateconf_client_get_string (plugin->priv->mateconf_client, - MATECONF_KEY_IGNORE_VERSION, - NULL); -} - -static void -parse_page_file (SoupSession *session, - SoupMessage *msg, - GeditWindow *window) -{ - if (msg->status_code == SOUP_STATUS_OK) - { - gchar *file; - gchar *file_version; - gchar *ignore_version; - WindowData *data; - - data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - - file = get_file (msg->response_body->data, FILE_REGEX); - file_version = parse_file_version (file); - ignore_version = get_ignore_version (data->plugin); - - if (newer_version (file_version, VERSION, TRUE) && - (ignore_version == NULL || *ignore_version == '\0' || - newer_version (file_version, ignore_version, TRUE))) - { - GtkWidget *infobar; - WindowData *data; - gchar *file_url; - - data = g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - - file_url = g_strconcat (data->url, file, NULL); - - g_free (data->url); - data->url = file_url; - data->version = g_strdup (file_version); - - infobar = create_infobar (window, file_version); - pack_infobar (GTK_WIDGET (window), infobar); - gtk_widget_show (infobar); - } - - g_free (ignore_version); - g_free (file_version); - g_free (file); - } - else - { - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); - } -} - -static gboolean -is_unstable (const gchar *version) -{ - gchar **split; - gint minor; - gboolean unstable = TRUE;; - - split = g_strsplit (version, ".", 2); - minor = atoi (split[1]); - g_strfreev (split); - - if ((minor % 2) == 0) - unstable = FALSE; - - return unstable; -} - -static gchar * -get_file_page_version (const gchar *text, - const gchar *regex_place) -{ - GRegex *regex; - GMatchInfo *match_info; - GString *string = NULL; - gchar *unstable = NULL; - gchar *stable = NULL; - - regex = g_regex_new (regex_place, 0, 0, NULL); - g_regex_match (regex, text, 0, &match_info); - while (g_match_info_matches (match_info)) - { - gint end; - gint i; - - g_match_info_fetch_pos (match_info, 0, NULL, &end); - - string = g_string_new (""); - - i = end; - while (text[i] != '/') - { - string = g_string_append_c (string, text[i]); - i++; - } - - if (is_unstable (string->str)) - { - g_free (unstable); - unstable = g_string_free (string, FALSE); - } - else - { - g_free (stable); - stable = g_string_free (string, FALSE); - } - - g_match_info_next (match_info, NULL); - } - g_match_info_free (match_info); - g_regex_unref (regex); - - if ((GEDIT_MINOR_VERSION % 2) == 0) - { - g_free (unstable); - - return stable; - } - else - { - /* We need to check that stable isn't newer than unstable */ - if (newer_version (stable, unstable, FALSE)) - { - g_free (unstable); - - return stable; - } - else - { - g_free (stable); - - return unstable; - } - } -} - -static void -parse_page_version (SoupSession *session, - SoupMessage *msg, - GeditWindow *window) -{ - if (msg->status_code == SOUP_STATUS_OK) - { - gchar *version; - SoupMessage *msg2; - WindowData *data; - - data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - - version = get_file_page_version (msg->response_body->data, - VERSION_PLACE); - - data->url = g_strconcat (GEDIT_URL, version, "/", NULL); - g_free (version); - msg2 = soup_message_new ("GET", data->url); - - soup_session_queue_message (session, msg2, - (SoupSessionCallback)parse_page_file, - window); - } - else - { - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); - } -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - SoupMessage *msg; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = g_slice_new (WindowData); - data->plugin = GEDIT_CHECK_UPDATE_PLUGIN (plugin); - data->url = NULL; - data->version = NULL; - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - free_window_data); - - msg = soup_message_new ("GET", GEDIT_URL); - - soup_session_queue_message (GEDIT_CHECK_UPDATE_PLUGIN (plugin)->priv->session, msg, - (SoupSessionCallback)parse_page_version, - window); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - - gedit_debug (DEBUG_PLUGINS); - - soup_session_abort (GEDIT_CHECK_UPDATE_PLUGIN (plugin)->priv->session); - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); -} - -static void -gedit_check_update_plugin_class_init (GeditCheckUpdatePluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (GeditCheckUpdatePluginPrivate)); - - object_class->finalize = gedit_check_update_plugin_finalize; - object_class->dispose = gedit_check_update_plugin_dispose; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; -} diff --git a/plugins/checkupdate/gedit-check-update-plugin.h b/plugins/checkupdate/gedit-check-update-plugin.h deleted file mode 100755 index 68dc7f97..00000000 --- a/plugins/checkupdate/gedit-check-update-plugin.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2009 - Ignacio Casal Quinteiro - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_CHECK_UPDATE_PLUGIN_H__ -#define __GEDIT_CHECK_UPDATE_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_CHECK_UPDATE_PLUGIN (gedit_check_update_plugin_get_type ()) -#define GEDIT_CHECK_UPDATE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_CHECK_UPDATE_PLUGIN, GeditCheckUpdatePlugin)) -#define GEDIT_CHECK_UPDATE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_CHECK_UPDATE_PLUGIN, GeditCheckUpdatePluginClass)) -#define IS_GEDIT_CHECK_UPDATE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_CHECK_UPDATE_PLUGIN)) -#define IS_GEDIT_CHECK_UPDATE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_CHECK_UPDATE_PLUGIN)) -#define GEDIT_CHECK_UPDATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_CHECK_UPDATE_PLUGIN, GeditCheckUpdatePluginClass)) - -/* Private structure type */ -typedef struct _GeditCheckUpdatePluginPrivate GeditCheckUpdatePluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditCheckUpdatePlugin GeditCheckUpdatePlugin; - -struct _GeditCheckUpdatePlugin -{ - GeditPlugin parent_instance; - - /*< private >*/ - GeditCheckUpdatePluginPrivate *priv; -}; - -/* - * Class definition - */ -typedef struct _GeditCheckUpdatePluginClass GeditCheckUpdatePluginClass; - -struct _GeditCheckUpdatePluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_check_update_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_CHECK_UPDATE_PLUGIN_H__ */ diff --git a/plugins/checkupdate/gedit-check-update.schemas.in b/plugins/checkupdate/gedit-check-update.schemas.in deleted file mode 100755 index 67bc892b..00000000 --- a/plugins/checkupdate/gedit-check-update.schemas.in +++ /dev/null @@ -1,13 +0,0 @@ - - - - /schemas/apps/gedit-2/plugins/checkupdate/ignore_version - /apps/gedit-2/plugins/checkupdate/ignore_version - gedit - string - - Version to ignore until the next version is released - - - - diff --git a/plugins/checkupdate/pluma-check-update-plugin.c b/plugins/checkupdate/pluma-check-update-plugin.c new file mode 100755 index 00000000..bf30181c --- /dev/null +++ b/plugins/checkupdate/pluma-check-update-plugin.c @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2009 - Ignacio Casal Quinteiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-check-update-plugin.h" + +#include +#include +#include +#include +#include +#include + +#include + +#if !GTK_CHECK_VERSION(2, 17, 1) +#include +#endif + +#define MATECONF_KEY_BASE "/apps/pluma-2/plugins/checkupdate" +#define MATECONF_KEY_IGNORE_VERSION MATECONF_KEY_BASE "/ignore_version" + +#define WINDOW_DATA_KEY "PlumaCheckUpdatePluginWindowData" + +#define VERSION_PLACE "" + +#ifdef G_OS_WIN32 +#define PLUMA_URL "http://ftp.acc.umu.se/pub/mate/binaries/win32/pluma/" +#define FILE_REGEX "pluma\\-setup\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.exe" +#else +#define PLUMA_URL "http://ftp.acc.umu.se/pub/mate/binaries/mac/pluma/" +#define FILE_REGEX "pluma\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.dmg" +#endif + +#ifdef OS_OSX +#include "pluma/osx/pluma-osx.h" +#endif + +#define PLUMA_CHECK_UPDATE_PLUGIN_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + PLUMA_TYPE_CHECK_UPDATE_PLUGIN, \ + PlumaCheckUpdatePluginPrivate)) + +PLUMA_PLUGIN_REGISTER_TYPE (PlumaCheckUpdatePlugin, pluma_check_update_plugin) + +struct _PlumaCheckUpdatePluginPrivate +{ + SoupSession *session; + + MateConfClient *mateconf_client; +}; + +typedef struct +{ + PlumaCheckUpdatePlugin *plugin; + + gchar *url; + gchar *version; +} WindowData; + +static void +free_window_data (gpointer data) +{ + WindowData *window_data; + + if (data == NULL) + return; + + window_data = (WindowData *)data; + + g_free (window_data->url); + g_free (window_data->version); + g_slice_free (WindowData, data); +} + +static void +pluma_check_update_plugin_init (PlumaCheckUpdatePlugin *plugin) +{ + plugin->priv = PLUMA_CHECK_UPDATE_PLUGIN_GET_PRIVATE (plugin); + + pluma_debug_message (DEBUG_PLUGINS, + "PlumaCheckUpdatePlugin initializing"); + + plugin->priv->session = soup_session_async_new (); + + plugin->priv->mateconf_client = mateconf_client_get_default (); + + mateconf_client_add_dir (plugin->priv->mateconf_client, + MATECONF_KEY_BASE, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); +} + +static void +pluma_check_update_plugin_dispose (GObject *object) +{ + PlumaCheckUpdatePlugin *plugin = PLUMA_CHECK_UPDATE_PLUGIN (object); + + if (plugin->priv->session != NULL) + { + g_object_unref (plugin->priv->session); + plugin->priv->session = NULL; + } + + if (plugin->priv->mateconf_client != NULL) + { + mateconf_client_suggest_sync (plugin->priv->mateconf_client, NULL); + + g_object_unref (G_OBJECT (plugin->priv->mateconf_client)); + + plugin->priv->mateconf_client = NULL; + } + + pluma_debug_message (DEBUG_PLUGINS, + "PlumaCheckUpdatePlugin disposing"); + + G_OBJECT_CLASS (pluma_check_update_plugin_parent_class)->dispose (object); +} + +static void +pluma_check_update_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, + "PlumaCheckUpdatePlugin finalizing"); + + G_OBJECT_CLASS (pluma_check_update_plugin_parent_class)->finalize (object); +} + +static void +set_contents (GtkWidget *infobar, + GtkWidget *contents) +{ +#if !GTK_CHECK_VERSION (2, 17, 1) + pluma_message_area_set_contents (PLUMA_MESSAGE_AREA (infobar), + contents); +#else + GtkWidget *content_area; + + content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar)); + gtk_container_add (GTK_CONTAINER (content_area), contents); +#endif +} + +static void +set_message_area_text_and_icon (GtkWidget *message_area, + const gchar *icon_stock_id, + const gchar *primary_text, + const gchar *secondary_text) +{ + GtkWidget *hbox_content; + GtkWidget *image; + GtkWidget *vbox; + gchar *primary_markup; + gchar *secondary_markup; + GtkWidget *primary_label; + GtkWidget *secondary_label; + + hbox_content = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox_content); + + image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG); + gtk_widget_show (image); + gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); + + primary_markup = g_strdup_printf ("%s", primary_text); + primary_label = gtk_label_new (primary_markup); + g_free (primary_markup); + gtk_widget_show (primary_label); + gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); + gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); + GTK_WIDGET_SET_FLAGS (primary_label, GTK_CAN_FOCUS); + gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE); + + if (secondary_text != NULL) + { + secondary_markup = g_strdup_printf ("%s", + secondary_text); + secondary_label = gtk_label_new (secondary_markup); + g_free (secondary_markup); + gtk_widget_show (secondary_label); + gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (secondary_label, GTK_CAN_FOCUS); + gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); + } + + set_contents (message_area, hbox_content); +} + +static void +on_response_cb (GtkWidget *infobar, + gint response_id, + PlumaWindow *window) +{ + if (response_id == GTK_RESPONSE_YES) + { + GError *error = NULL; + WindowData *data; + + data = g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + +#ifdef OS_OSX + pluma_osx_show_url (data->url); +#else + gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (window)), + data->url, + GDK_CURRENT_TIME, + &error); +#endif + if (error != NULL) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("There was an error displaying the URI.")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_signal_connect (G_OBJECT (dialog), + "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + gtk_widget_show (dialog); + + g_error_free (error); + } + } + else if (response_id == GTK_RESPONSE_NO) + { + WindowData *data; + + data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + + mateconf_client_set_string (data->plugin->priv->mateconf_client, + MATECONF_KEY_IGNORE_VERSION, + data->version, + NULL); + } + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); + + gtk_widget_destroy (infobar); +} + +static GtkWidget * +create_infobar (PlumaWindow *window, + const gchar *version) +{ + GtkWidget *infobar; + gchar *message; + +#if !GTK_CHECK_VERSION (2, 17, 1) + infobar = pluma_message_area_new (); + + pluma_message_area_add_stock_button_with_text (PLUMA_MESSAGE_AREA (infobar), + _("_Download"), + GTK_STOCK_SAVE, + GTK_RESPONSE_YES); + pluma_message_area_add_stock_button_with_text (PLUMA_MESSAGE_AREA (infobar), + _("_Ignore Version"), + GTK_STOCK_DISCARD, + GTK_RESPONSE_NO); + pluma_message_area_add_button (PLUMA_MESSAGE_AREA (infobar), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); +#else + GtkWidget *button; + + infobar = gtk_info_bar_new (); + + button = pluma_gtk_button_new_with_stock_icon (_("_Download"), + GTK_STOCK_SAVE); + gtk_widget_show (button); + + gtk_info_bar_add_action_widget (GTK_INFO_BAR (infobar), + button, + GTK_RESPONSE_YES); + + button = pluma_gtk_button_new_with_stock_icon (_("_Ignore Version"), + GTK_STOCK_DISCARD); + gtk_widget_show (button); + + gtk_info_bar_add_action_widget (GTK_INFO_BAR (infobar), + button, + GTK_RESPONSE_NO); + + gtk_info_bar_add_button (GTK_INFO_BAR (infobar), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL); + + gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), + GTK_MESSAGE_INFO); +#endif + + message = g_strdup_printf ("%s (%s)", _("There is a new version of pluma"), version); + set_message_area_text_and_icon (infobar, + "gtk-dialog-info", + message, + _("You can download the new version of pluma" + " by clicking on the download button or" + " ignore that version and wait for a new one")); + + g_free (message); + + g_signal_connect (infobar, "response", + G_CALLBACK (on_response_cb), + window); + + return infobar; +} + +static void +pack_infobar (GtkWidget *window, + GtkWidget *infobar) +{ + GtkWidget *vbox; + + vbox = gtk_bin_get_child (GTK_BIN (window)); + + gtk_box_pack_start (GTK_BOX (vbox), infobar, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (vbox), infobar, 2); +} + +static gchar * +get_file (const gchar *text, + const gchar *regex_place) +{ + GRegex *regex; + GMatchInfo *match_info; + gchar *word = NULL; + + regex = g_regex_new (regex_place, 0, 0, NULL); + g_regex_match (regex, text, 0, &match_info); + while (g_match_info_matches (match_info)) + { + g_free (word); + + word = g_match_info_fetch (match_info, 0); + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + g_regex_unref (regex); + + return word; +} + +static void +get_numbers (const gchar *version, + gint *major, + gint *minor, + gint *micro) +{ + gchar **split; + gint num = 2; + + if (micro != NULL) + num = 3; + + split = g_strsplit (version, ".", num); + *major = atoi (split[0]); + *minor = atoi (split[1]); + if (micro != NULL) + *micro = atoi (split[2]); + + g_strfreev (split); +} + +static gboolean +newer_version (const gchar *v1, + const gchar *v2, + gboolean with_micro) +{ + gboolean newer = FALSE; + gint major1, minor1, micro1; + gint major2, minor2, micro2; + + if (v1 == NULL || v2 == NULL) + return FALSE; + + if (with_micro) + { + get_numbers (v1, &major1, &minor1, µ1); + get_numbers (v2, &major2, &minor2, µ2); + } + else + { + get_numbers (v1, &major1, &minor1, NULL); + get_numbers (v2, &major2, &minor2, NULL); + } + + if (major1 > major2) + { + newer = TRUE; + } + else if (minor1 > minor2 && major1 == major2) + { + newer = TRUE; + } + else if (with_micro && micro1 > micro2 && minor1 == minor2) + { + newer = TRUE; + } + + return newer; +} + +static gchar * +parse_file_version (const gchar *file) +{ + gchar *p, *aux; + + p = (gchar *)file; + + while (*p != '\0' && !g_ascii_isdigit (*p)) + { + p++; + } + + if (*p == '\0') + return NULL; + + aux = g_strrstr (p, "-"); + if (aux == NULL) + aux = g_strrstr (p, "."); + + return g_strndup (p, aux - p); +} + +static gchar * +get_ignore_version (PlumaCheckUpdatePlugin *plugin) +{ + return mateconf_client_get_string (plugin->priv->mateconf_client, + MATECONF_KEY_IGNORE_VERSION, + NULL); +} + +static void +parse_page_file (SoupSession *session, + SoupMessage *msg, + PlumaWindow *window) +{ + if (msg->status_code == SOUP_STATUS_OK) + { + gchar *file; + gchar *file_version; + gchar *ignore_version; + WindowData *data; + + data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + + file = get_file (msg->response_body->data, FILE_REGEX); + file_version = parse_file_version (file); + ignore_version = get_ignore_version (data->plugin); + + if (newer_version (file_version, VERSION, TRUE) && + (ignore_version == NULL || *ignore_version == '\0' || + newer_version (file_version, ignore_version, TRUE))) + { + GtkWidget *infobar; + WindowData *data; + gchar *file_url; + + data = g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + + file_url = g_strconcat (data->url, file, NULL); + + g_free (data->url); + data->url = file_url; + data->version = g_strdup (file_version); + + infobar = create_infobar (window, file_version); + pack_infobar (GTK_WIDGET (window), infobar); + gtk_widget_show (infobar); + } + + g_free (ignore_version); + g_free (file_version); + g_free (file); + } + else + { + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); + } +} + +static gboolean +is_unstable (const gchar *version) +{ + gchar **split; + gint minor; + gboolean unstable = TRUE;; + + split = g_strsplit (version, ".", 2); + minor = atoi (split[1]); + g_strfreev (split); + + if ((minor % 2) == 0) + unstable = FALSE; + + return unstable; +} + +static gchar * +get_file_page_version (const gchar *text, + const gchar *regex_place) +{ + GRegex *regex; + GMatchInfo *match_info; + GString *string = NULL; + gchar *unstable = NULL; + gchar *stable = NULL; + + regex = g_regex_new (regex_place, 0, 0, NULL); + g_regex_match (regex, text, 0, &match_info); + while (g_match_info_matches (match_info)) + { + gint end; + gint i; + + g_match_info_fetch_pos (match_info, 0, NULL, &end); + + string = g_string_new (""); + + i = end; + while (text[i] != '/') + { + string = g_string_append_c (string, text[i]); + i++; + } + + if (is_unstable (string->str)) + { + g_free (unstable); + unstable = g_string_free (string, FALSE); + } + else + { + g_free (stable); + stable = g_string_free (string, FALSE); + } + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + g_regex_unref (regex); + + if ((PLUMA_MINOR_VERSION % 2) == 0) + { + g_free (unstable); + + return stable; + } + else + { + /* We need to check that stable isn't newer than unstable */ + if (newer_version (stable, unstable, FALSE)) + { + g_free (unstable); + + return stable; + } + else + { + g_free (stable); + + return unstable; + } + } +} + +static void +parse_page_version (SoupSession *session, + SoupMessage *msg, + PlumaWindow *window) +{ + if (msg->status_code == SOUP_STATUS_OK) + { + gchar *version; + SoupMessage *msg2; + WindowData *data; + + data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + + version = get_file_page_version (msg->response_body->data, + VERSION_PLACE); + + data->url = g_strconcat (PLUMA_URL, version, "/", NULL); + g_free (version); + msg2 = soup_message_new ("GET", data->url); + + soup_session_queue_message (session, msg2, + (SoupSessionCallback)parse_page_file, + window); + } + else + { + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); + } +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + SoupMessage *msg; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = g_slice_new (WindowData); + data->plugin = PLUMA_CHECK_UPDATE_PLUGIN (plugin); + data->url = NULL; + data->version = NULL; + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + free_window_data); + + msg = soup_message_new ("GET", PLUMA_URL); + + soup_session_queue_message (PLUMA_CHECK_UPDATE_PLUGIN (plugin)->priv->session, msg, + (SoupSessionCallback)parse_page_version, + window); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + + pluma_debug (DEBUG_PLUGINS); + + soup_session_abort (PLUMA_CHECK_UPDATE_PLUGIN (plugin)->priv->session); + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); +} + +static void +pluma_check_update_plugin_class_init (PlumaCheckUpdatePluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (PlumaCheckUpdatePluginPrivate)); + + object_class->finalize = pluma_check_update_plugin_finalize; + object_class->dispose = pluma_check_update_plugin_dispose; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; +} diff --git a/plugins/checkupdate/pluma-check-update-plugin.h b/plugins/checkupdate/pluma-check-update-plugin.h new file mode 100755 index 00000000..6742d2d4 --- /dev/null +++ b/plugins/checkupdate/pluma-check-update-plugin.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 - Ignacio Casal Quinteiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_CHECK_UPDATE_PLUGIN_H__ +#define __PLUMA_CHECK_UPDATE_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_CHECK_UPDATE_PLUGIN (pluma_check_update_plugin_get_type ()) +#define PLUMA_CHECK_UPDATE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_CHECK_UPDATE_PLUGIN, PlumaCheckUpdatePlugin)) +#define PLUMA_CHECK_UPDATE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_CHECK_UPDATE_PLUGIN, PlumaCheckUpdatePluginClass)) +#define IS_PLUMA_CHECK_UPDATE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_CHECK_UPDATE_PLUGIN)) +#define IS_PLUMA_CHECK_UPDATE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_CHECK_UPDATE_PLUGIN)) +#define PLUMA_CHECK_UPDATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_CHECK_UPDATE_PLUGIN, PlumaCheckUpdatePluginClass)) + +/* Private structure type */ +typedef struct _PlumaCheckUpdatePluginPrivate PlumaCheckUpdatePluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaCheckUpdatePlugin PlumaCheckUpdatePlugin; + +struct _PlumaCheckUpdatePlugin +{ + PlumaPlugin parent_instance; + + /*< private >*/ + PlumaCheckUpdatePluginPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _PlumaCheckUpdatePluginClass PlumaCheckUpdatePluginClass; + +struct _PlumaCheckUpdatePluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_check_update_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_CHECK_UPDATE_PLUGIN_H__ */ diff --git a/plugins/checkupdate/pluma-check-update.schemas.in b/plugins/checkupdate/pluma-check-update.schemas.in new file mode 100755 index 00000000..5d4d009a --- /dev/null +++ b/plugins/checkupdate/pluma-check-update.schemas.in @@ -0,0 +1,13 @@ + + + + /schemas/apps/pluma-2/plugins/checkupdate/ignore_version + /apps/pluma-2/plugins/checkupdate/ignore_version + pluma + string + + Version to ignore until the next version is released + + + + diff --git a/plugins/docinfo/Makefile.am b/plugins/docinfo/Makefile.am index edf2909c..27290fc7 100755 --- a/plugins/docinfo/Makefile.am +++ b/plugins/docinfo/Makefile.am @@ -1,29 +1,29 @@ # docinfo plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) plugin_LTLIBRARIES = libdocinfo.la libdocinfo_la_SOURCES = \ - gedit-docinfo-plugin.h \ - gedit-docinfo-plugin.c + pluma-docinfo-plugin.h \ + pluma-docinfo-plugin.c libdocinfo_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libdocinfo_la_LIBADD = $(GEDIT_LIBS) +libdocinfo_la_LIBADD = $(PLUMA_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/docinfo +uidir = $(PLUMA_PLUGINS_DATA_DIR)/docinfo ui_DATA = docinfo.ui -plugin_in_files = docinfo.gedit-plugin.desktop.in +plugin_in_files = docinfo.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(ui_DATA) $(plugin_in_files) diff --git a/plugins/docinfo/docinfo.gedit-plugin.desktop.in b/plugins/docinfo/docinfo.gedit-plugin.desktop.in deleted file mode 100755 index 77f2793d..00000000 --- a/plugins/docinfo/docinfo.gedit-plugin.desktop.in +++ /dev/null @@ -1,7 +0,0 @@ -[Gedit Plugin] -Module=docinfo -IAge=2 -_Name=Document Statistics -_Description=Analyzes the current document and reports the number of words, lines, characters and non-space characters in it. -Authors=Paolo Maggi ;Jorge Alberto Torres -Copyright=Copyright © 2002-2005 Paolo Maggi diff --git a/plugins/docinfo/docinfo.pluma-plugin.desktop.in b/plugins/docinfo/docinfo.pluma-plugin.desktop.in new file mode 100755 index 00000000..990f2cd6 --- /dev/null +++ b/plugins/docinfo/docinfo.pluma-plugin.desktop.in @@ -0,0 +1,7 @@ +[Pluma Plugin] +Module=docinfo +IAge=2 +_Name=Document Statistics +_Description=Analyzes the current document and reports the number of words, lines, characters and non-space characters in it. +Authors=Paolo Maggi ;Jorge Alberto Torres +Copyright=Copyright © 2002-2005 Paolo Maggi diff --git a/plugins/docinfo/gedit-docinfo-plugin.c b/plugins/docinfo/gedit-docinfo-plugin.c deleted file mode 100755 index a143a5a6..00000000 --- a/plugins/docinfo/gedit-docinfo-plugin.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * gedit-docinfo-plugin.c - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-docinfo-plugin.h" - -#include /* For strlen (...) */ - -#include -#include -#include - -#include -#include - -#define WINDOW_DATA_KEY "GeditDocInfoWindowData" -#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_2" - -GEDIT_PLUGIN_REGISTER_TYPE(GeditDocInfoPlugin, gedit_docinfo_plugin) - -typedef struct -{ - GtkWidget *dialog; - GtkWidget *file_name_label; - GtkWidget *lines_label; - GtkWidget *words_label; - GtkWidget *chars_label; - GtkWidget *chars_ns_label; - GtkWidget *bytes_label; - GtkWidget *selection_vbox; - GtkWidget *selected_lines_label; - GtkWidget *selected_words_label; - GtkWidget *selected_chars_label; - GtkWidget *selected_chars_ns_label; - GtkWidget *selected_bytes_label; -} DocInfoDialog; - -typedef struct -{ - GeditPlugin *plugin; - - GtkActionGroup *ui_action_group; - guint ui_id; - - DocInfoDialog *dialog; -} WindowData; - -static void docinfo_dialog_response_cb (GtkDialog *widget, - gint res_id, - GeditWindow *window); - -static void -docinfo_dialog_destroy_cb (GtkObject *obj, - WindowData *data) -{ - gedit_debug (DEBUG_PLUGINS); - - if (data != NULL) - { - g_free (data->dialog); - data->dialog = NULL; - } -} - -static DocInfoDialog * -get_docinfo_dialog (GeditWindow *window, - WindowData *data) -{ - DocInfoDialog *dialog; - gchar *data_dir; - gchar *ui_file; - GtkWidget *content; - GtkWidget *error_widget; - gboolean ret; - - gedit_debug (DEBUG_PLUGINS); - - dialog = g_new (DocInfoDialog, 1); - - data_dir = gedit_plugin_get_data_dir (data->plugin); - ui_file = g_build_filename (data_dir, "docinfo.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - NULL, - &error_widget, - "dialog", &dialog->dialog, - "docinfo_dialog_content", &content, - "file_name_label", &dialog->file_name_label, - "words_label", &dialog->words_label, - "bytes_label", &dialog->bytes_label, - "lines_label", &dialog->lines_label, - "chars_label", &dialog->chars_label, - "chars_ns_label", &dialog->chars_ns_label, - "selection_vbox", &dialog->selection_vbox, - "selected_words_label", &dialog->selected_words_label, - "selected_bytes_label", &dialog->selected_bytes_label, - "selected_lines_label", &dialog->selected_lines_label, - "selected_chars_label", &dialog->selected_chars_label, - "selected_chars_ns_label", &dialog->selected_chars_ns_label, - NULL); - - g_free (data_dir); - g_free (ui_file); - - if (!ret) - { - const gchar *err_message; - - err_message = gtk_label_get_label (GTK_LABEL (error_widget)); - gedit_warning (GTK_WINDOW (window), "%s", err_message); - - g_free (dialog); - gtk_widget_destroy (error_widget); - - return NULL; - } - - gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), - GTK_RESPONSE_OK); - gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), - GTK_WINDOW (window)); - - g_signal_connect (dialog->dialog, - "destroy", - G_CALLBACK (docinfo_dialog_destroy_cb), - data); - g_signal_connect (dialog->dialog, - "response", - G_CALLBACK (docinfo_dialog_response_cb), - window); - - return dialog; -} - -static void -calculate_info (GeditDocument *doc, - GtkTextIter *start, - GtkTextIter *end, - gint *chars, - gint *words, - gint *white_chars, - gint *bytes) -{ - gchar *text; - - gedit_debug (DEBUG_PLUGINS); - - text = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), - start, - end, - TRUE); - - *chars = g_utf8_strlen (text, -1); - *bytes = strlen (text); - - if (*chars > 0) - { - PangoLogAttr *attrs; - gint i; - - attrs = g_new0 (PangoLogAttr, *chars + 1); - - pango_get_log_attrs (text, - -1, - 0, - pango_language_from_string ("C"), - attrs, - *chars + 1); - - for (i = 0; i < (*chars); i++) - { - if (attrs[i].is_white) - ++(*white_chars); - - if (attrs[i].is_word_start) - ++(*words); - } - - g_free (attrs); - } - else - { - *white_chars = 0; - *words = 0; - } - - g_free (text); -} - -static void -docinfo_real (GeditDocument *doc, - DocInfoDialog *dialog) -{ - GtkTextIter start, end; - gint words = 0; - gint chars = 0; - gint white_chars = 0; - gint lines = 0; - gint bytes = 0; - gchar *tmp_str; - gchar *doc_name; - - gedit_debug (DEBUG_PLUGINS); - - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end); - - lines = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc)); - - calculate_info (doc, - &start, &end, - &chars, &words, &white_chars, &bytes); - - if (chars == 0) - lines = 0; - - gedit_debug_message (DEBUG_PLUGINS, "Chars: %d", chars); - gedit_debug_message (DEBUG_PLUGINS, "Lines: %d", lines); - gedit_debug_message (DEBUG_PLUGINS, "Words: %d", words); - gedit_debug_message (DEBUG_PLUGINS, "Chars non-space: %d", chars - white_chars); - gedit_debug_message (DEBUG_PLUGINS, "Bytes: %d", bytes); - - doc_name = gedit_document_get_short_name_for_display (doc); - tmp_str = g_strdup_printf ("%s", doc_name); - gtk_label_set_markup (GTK_LABEL (dialog->file_name_label), tmp_str); - g_free (doc_name); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", lines); - gtk_label_set_text (GTK_LABEL (dialog->lines_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", words); - gtk_label_set_text (GTK_LABEL (dialog->words_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", chars); - gtk_label_set_text (GTK_LABEL (dialog->chars_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", chars - white_chars); - gtk_label_set_text (GTK_LABEL (dialog->chars_ns_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", bytes); - gtk_label_set_text (GTK_LABEL (dialog->bytes_label), tmp_str); - g_free (tmp_str); -} - -static void -selectioninfo_real (GeditDocument *doc, - DocInfoDialog *dialog) -{ - gboolean sel; - GtkTextIter start, end; - gint words = 0; - gint chars = 0; - gint white_chars = 0; - gint lines = 0; - gint bytes = 0; - gchar *tmp_str; - - gedit_debug (DEBUG_PLUGINS); - - sel = gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end); - - if (sel) - { - lines = gtk_text_iter_get_line (&end) - gtk_text_iter_get_line (&start) + 1; - - calculate_info (doc, - &start, &end, - &chars, &words, &white_chars, &bytes); - - gedit_debug_message (DEBUG_PLUGINS, "Selected chars: %d", chars); - gedit_debug_message (DEBUG_PLUGINS, "Selected lines: %d", lines); - gedit_debug_message (DEBUG_PLUGINS, "Selected words: %d", words); - gedit_debug_message (DEBUG_PLUGINS, "Selected chars non-space: %d", chars - white_chars); - gedit_debug_message (DEBUG_PLUGINS, "Selected bytes: %d", bytes); - - gtk_widget_set_sensitive (dialog->selection_vbox, TRUE); - } - else - { - gtk_widget_set_sensitive (dialog->selection_vbox, FALSE); - - gedit_debug_message (DEBUG_PLUGINS, "Selection empty"); - } - - if (chars == 0) - lines = 0; - - tmp_str = g_strdup_printf("%d", lines); - gtk_label_set_text (GTK_LABEL (dialog->selected_lines_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", words); - gtk_label_set_text (GTK_LABEL (dialog->selected_words_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", chars); - gtk_label_set_text (GTK_LABEL (dialog->selected_chars_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", chars - white_chars); - gtk_label_set_text (GTK_LABEL (dialog->selected_chars_ns_label), tmp_str); - g_free (tmp_str); - - tmp_str = g_strdup_printf("%d", bytes); - gtk_label_set_text (GTK_LABEL (dialog->selected_bytes_label), tmp_str); - g_free (tmp_str); -} - -static void -docinfo_cb (GtkAction *action, - GeditWindow *window) -{ - GeditDocument *doc; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - - doc = gedit_window_get_active_document (window); - g_return_if_fail (doc != NULL); - - if (data->dialog != NULL) - { - gtk_window_present (GTK_WINDOW (data->dialog->dialog)); - gtk_widget_grab_focus (GTK_WIDGET (data->dialog->dialog)); - } - else - { - DocInfoDialog *dialog; - - dialog = get_docinfo_dialog (window, data); - g_return_if_fail (dialog != NULL); - - data->dialog = dialog; - - gtk_widget_show (GTK_WIDGET (dialog->dialog)); - } - - docinfo_real (doc, - data->dialog); - selectioninfo_real (doc, - data->dialog); -} - -static void -docinfo_dialog_response_cb (GtkDialog *widget, - gint res_id, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - - switch (res_id) - { - case GTK_RESPONSE_CLOSE: - { - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CLOSE"); - gtk_widget_destroy (data->dialog->dialog); - - break; - } - - case GTK_RESPONSE_OK: - { - GeditDocument *doc; - - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); - - doc = gedit_window_get_active_document (window); - g_return_if_fail (doc != NULL); - - docinfo_real (doc, - data->dialog); - - selectioninfo_real (doc, - data->dialog); - - break; - } - } -} - -static const GtkActionEntry action_entries[] = -{ - { "DocumentStatistics", - NULL, - N_("_Document Statistics"), - NULL, - N_("Get statistical information on the current document"), - G_CALLBACK (docinfo_cb) } -}; - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - gedit_debug (DEBUG_PLUGINS); - - g_object_unref (data->plugin); - - g_object_unref (data->ui_action_group); - - if (data->dialog != NULL) - { - gtk_widget_destroy (data->dialog->dialog); - } - - g_free (data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GeditView *view; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (window); - - gtk_action_group_set_sensitive (data->ui_action_group, - (view != NULL)); - - if (data->dialog != NULL) - { - gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog->dialog), - GTK_RESPONSE_OK, - (view != NULL)); - } -} - -static void -gedit_docinfo_plugin_init (GeditDocInfoPlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditDocInfoPlugin initializing"); -} - -static void -gedit_docinfo_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditDocInfoPlugin finalizing"); - - G_OBJECT_CLASS (gedit_docinfo_plugin_parent_class)->finalize (object); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = g_new (WindowData, 1); - - data->plugin = g_object_ref (plugin); - data->dialog = NULL; - data->ui_action_group = gtk_action_group_new ("GeditDocInfoPluginActions"); - - gtk_action_group_set_translation_domain (data->ui_action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions (data->ui_action_group, - action_entries, - G_N_ELEMENTS (action_entries), - window); - - manager = gedit_window_get_ui_manager (window); - gtk_ui_manager_insert_action_group (manager, - data->ui_action_group, - -1); - - data->ui_id = gtk_ui_manager_new_merge_id (manager); - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "DocumentStatistics", - "DocumentStatistics", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - update_ui_real (window, - data); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, - data->ui_id); - gtk_ui_manager_remove_action_group (manager, - data->ui_action_group); - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, - data); -} - -static void -gedit_docinfo_plugin_class_init (GeditDocInfoPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_docinfo_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; -} diff --git a/plugins/docinfo/gedit-docinfo-plugin.h b/plugins/docinfo/gedit-docinfo-plugin.h deleted file mode 100755 index 36d6bddc..00000000 --- a/plugins/docinfo/gedit-docinfo-plugin.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * gedit-docinfo-plugin.h - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_DOCINFO_PLUGIN_H__ -#define __GEDIT_DOCINFO_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_DOCINFO_PLUGIN (gedit_docinfo_plugin_get_type ()) -#define GEDIT_DOCINFO_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_DOCINFO_PLUGIN, GeditDocInfoPlugin)) -#define GEDIT_DOCINFO_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_DOCINFO_PLUGIN, GeditDocInfoPluginClass)) -#define GEDIT_IS_DOCINFO_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_DOCINFO_PLUGIN)) -#define GEDIT_IS_DOCINFO_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_DOCINFO_PLUGIN)) -#define GEDIT_DOCINFO_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_DOCINFO_PLUGIN, GeditDocInfoPluginClass)) - -/* Private structure type */ -typedef struct _GeditDocInfoPluginPrivate GeditDocInfoPluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditDocInfoPlugin GeditDocInfoPlugin; - -struct _GeditDocInfoPlugin -{ - GeditPlugin parent_instance; -}; - -/* - * Class definition - */ -typedef struct _GeditDocInfoPluginClass GeditDocInfoPluginClass; - -struct _GeditDocInfoPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_docinfo_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_DOCINFO_PLUGIN_H__ */ diff --git a/plugins/docinfo/pluma-docinfo-plugin.c b/plugins/docinfo/pluma-docinfo-plugin.c new file mode 100755 index 00000000..10a5af87 --- /dev/null +++ b/plugins/docinfo/pluma-docinfo-plugin.c @@ -0,0 +1,580 @@ +/* + * pluma-docinfo-plugin.c + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-docinfo-plugin.h" + +#include /* For strlen (...) */ + +#include +#include +#include + +#include +#include + +#define WINDOW_DATA_KEY "PlumaDocInfoWindowData" +#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_2" + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaDocInfoPlugin, pluma_docinfo_plugin) + +typedef struct +{ + GtkWidget *dialog; + GtkWidget *file_name_label; + GtkWidget *lines_label; + GtkWidget *words_label; + GtkWidget *chars_label; + GtkWidget *chars_ns_label; + GtkWidget *bytes_label; + GtkWidget *selection_vbox; + GtkWidget *selected_lines_label; + GtkWidget *selected_words_label; + GtkWidget *selected_chars_label; + GtkWidget *selected_chars_ns_label; + GtkWidget *selected_bytes_label; +} DocInfoDialog; + +typedef struct +{ + PlumaPlugin *plugin; + + GtkActionGroup *ui_action_group; + guint ui_id; + + DocInfoDialog *dialog; +} WindowData; + +static void docinfo_dialog_response_cb (GtkDialog *widget, + gint res_id, + PlumaWindow *window); + +static void +docinfo_dialog_destroy_cb (GtkObject *obj, + WindowData *data) +{ + pluma_debug (DEBUG_PLUGINS); + + if (data != NULL) + { + g_free (data->dialog); + data->dialog = NULL; + } +} + +static DocInfoDialog * +get_docinfo_dialog (PlumaWindow *window, + WindowData *data) +{ + DocInfoDialog *dialog; + gchar *data_dir; + gchar *ui_file; + GtkWidget *content; + GtkWidget *error_widget; + gboolean ret; + + pluma_debug (DEBUG_PLUGINS); + + dialog = g_new (DocInfoDialog, 1); + + data_dir = pluma_plugin_get_data_dir (data->plugin); + ui_file = g_build_filename (data_dir, "docinfo.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + NULL, + &error_widget, + "dialog", &dialog->dialog, + "docinfo_dialog_content", &content, + "file_name_label", &dialog->file_name_label, + "words_label", &dialog->words_label, + "bytes_label", &dialog->bytes_label, + "lines_label", &dialog->lines_label, + "chars_label", &dialog->chars_label, + "chars_ns_label", &dialog->chars_ns_label, + "selection_vbox", &dialog->selection_vbox, + "selected_words_label", &dialog->selected_words_label, + "selected_bytes_label", &dialog->selected_bytes_label, + "selected_lines_label", &dialog->selected_lines_label, + "selected_chars_label", &dialog->selected_chars_label, + "selected_chars_ns_label", &dialog->selected_chars_ns_label, + NULL); + + g_free (data_dir); + g_free (ui_file); + + if (!ret) + { + const gchar *err_message; + + err_message = gtk_label_get_label (GTK_LABEL (error_widget)); + pluma_warning (GTK_WINDOW (window), "%s", err_message); + + g_free (dialog); + gtk_widget_destroy (error_widget); + + return NULL; + } + + gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), + GTK_RESPONSE_OK); + gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), + GTK_WINDOW (window)); + + g_signal_connect (dialog->dialog, + "destroy", + G_CALLBACK (docinfo_dialog_destroy_cb), + data); + g_signal_connect (dialog->dialog, + "response", + G_CALLBACK (docinfo_dialog_response_cb), + window); + + return dialog; +} + +static void +calculate_info (PlumaDocument *doc, + GtkTextIter *start, + GtkTextIter *end, + gint *chars, + gint *words, + gint *white_chars, + gint *bytes) +{ + gchar *text; + + pluma_debug (DEBUG_PLUGINS); + + text = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), + start, + end, + TRUE); + + *chars = g_utf8_strlen (text, -1); + *bytes = strlen (text); + + if (*chars > 0) + { + PangoLogAttr *attrs; + gint i; + + attrs = g_new0 (PangoLogAttr, *chars + 1); + + pango_get_log_attrs (text, + -1, + 0, + pango_language_from_string ("C"), + attrs, + *chars + 1); + + for (i = 0; i < (*chars); i++) + { + if (attrs[i].is_white) + ++(*white_chars); + + if (attrs[i].is_word_start) + ++(*words); + } + + g_free (attrs); + } + else + { + *white_chars = 0; + *words = 0; + } + + g_free (text); +} + +static void +docinfo_real (PlumaDocument *doc, + DocInfoDialog *dialog) +{ + GtkTextIter start, end; + gint words = 0; + gint chars = 0; + gint white_chars = 0; + gint lines = 0; + gint bytes = 0; + gchar *tmp_str; + gchar *doc_name; + + pluma_debug (DEBUG_PLUGINS); + + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end); + + lines = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (doc)); + + calculate_info (doc, + &start, &end, + &chars, &words, &white_chars, &bytes); + + if (chars == 0) + lines = 0; + + pluma_debug_message (DEBUG_PLUGINS, "Chars: %d", chars); + pluma_debug_message (DEBUG_PLUGINS, "Lines: %d", lines); + pluma_debug_message (DEBUG_PLUGINS, "Words: %d", words); + pluma_debug_message (DEBUG_PLUGINS, "Chars non-space: %d", chars - white_chars); + pluma_debug_message (DEBUG_PLUGINS, "Bytes: %d", bytes); + + doc_name = pluma_document_get_short_name_for_display (doc); + tmp_str = g_strdup_printf ("%s", doc_name); + gtk_label_set_markup (GTK_LABEL (dialog->file_name_label), tmp_str); + g_free (doc_name); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", lines); + gtk_label_set_text (GTK_LABEL (dialog->lines_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", words); + gtk_label_set_text (GTK_LABEL (dialog->words_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", chars); + gtk_label_set_text (GTK_LABEL (dialog->chars_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", chars - white_chars); + gtk_label_set_text (GTK_LABEL (dialog->chars_ns_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", bytes); + gtk_label_set_text (GTK_LABEL (dialog->bytes_label), tmp_str); + g_free (tmp_str); +} + +static void +selectioninfo_real (PlumaDocument *doc, + DocInfoDialog *dialog) +{ + gboolean sel; + GtkTextIter start, end; + gint words = 0; + gint chars = 0; + gint white_chars = 0; + gint lines = 0; + gint bytes = 0; + gchar *tmp_str; + + pluma_debug (DEBUG_PLUGINS); + + sel = gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end); + + if (sel) + { + lines = gtk_text_iter_get_line (&end) - gtk_text_iter_get_line (&start) + 1; + + calculate_info (doc, + &start, &end, + &chars, &words, &white_chars, &bytes); + + pluma_debug_message (DEBUG_PLUGINS, "Selected chars: %d", chars); + pluma_debug_message (DEBUG_PLUGINS, "Selected lines: %d", lines); + pluma_debug_message (DEBUG_PLUGINS, "Selected words: %d", words); + pluma_debug_message (DEBUG_PLUGINS, "Selected chars non-space: %d", chars - white_chars); + pluma_debug_message (DEBUG_PLUGINS, "Selected bytes: %d", bytes); + + gtk_widget_set_sensitive (dialog->selection_vbox, TRUE); + } + else + { + gtk_widget_set_sensitive (dialog->selection_vbox, FALSE); + + pluma_debug_message (DEBUG_PLUGINS, "Selection empty"); + } + + if (chars == 0) + lines = 0; + + tmp_str = g_strdup_printf("%d", lines); + gtk_label_set_text (GTK_LABEL (dialog->selected_lines_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", words); + gtk_label_set_text (GTK_LABEL (dialog->selected_words_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", chars); + gtk_label_set_text (GTK_LABEL (dialog->selected_chars_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", chars - white_chars); + gtk_label_set_text (GTK_LABEL (dialog->selected_chars_ns_label), tmp_str); + g_free (tmp_str); + + tmp_str = g_strdup_printf("%d", bytes); + gtk_label_set_text (GTK_LABEL (dialog->selected_bytes_label), tmp_str); + g_free (tmp_str); +} + +static void +docinfo_cb (GtkAction *action, + PlumaWindow *window) +{ + PlumaDocument *doc; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + + doc = pluma_window_get_active_document (window); + g_return_if_fail (doc != NULL); + + if (data->dialog != NULL) + { + gtk_window_present (GTK_WINDOW (data->dialog->dialog)); + gtk_widget_grab_focus (GTK_WIDGET (data->dialog->dialog)); + } + else + { + DocInfoDialog *dialog; + + dialog = get_docinfo_dialog (window, data); + g_return_if_fail (dialog != NULL); + + data->dialog = dialog; + + gtk_widget_show (GTK_WIDGET (dialog->dialog)); + } + + docinfo_real (doc, + data->dialog); + selectioninfo_real (doc, + data->dialog); +} + +static void +docinfo_dialog_response_cb (GtkDialog *widget, + gint res_id, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + + switch (res_id) + { + case GTK_RESPONSE_CLOSE: + { + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CLOSE"); + gtk_widget_destroy (data->dialog->dialog); + + break; + } + + case GTK_RESPONSE_OK: + { + PlumaDocument *doc; + + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); + + doc = pluma_window_get_active_document (window); + g_return_if_fail (doc != NULL); + + docinfo_real (doc, + data->dialog); + + selectioninfo_real (doc, + data->dialog); + + break; + } + } +} + +static const GtkActionEntry action_entries[] = +{ + { "DocumentStatistics", + NULL, + N_("_Document Statistics"), + NULL, + N_("Get statistical information on the current document"), + G_CALLBACK (docinfo_cb) } +}; + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + pluma_debug (DEBUG_PLUGINS); + + g_object_unref (data->plugin); + + g_object_unref (data->ui_action_group); + + if (data->dialog != NULL) + { + gtk_widget_destroy (data->dialog->dialog); + } + + g_free (data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + PlumaView *view; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (window); + + gtk_action_group_set_sensitive (data->ui_action_group, + (view != NULL)); + + if (data->dialog != NULL) + { + gtk_dialog_set_response_sensitive (GTK_DIALOG (data->dialog->dialog), + GTK_RESPONSE_OK, + (view != NULL)); + } +} + +static void +pluma_docinfo_plugin_init (PlumaDocInfoPlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaDocInfoPlugin initializing"); +} + +static void +pluma_docinfo_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaDocInfoPlugin finalizing"); + + G_OBJECT_CLASS (pluma_docinfo_plugin_parent_class)->finalize (object); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = g_new (WindowData, 1); + + data->plugin = g_object_ref (plugin); + data->dialog = NULL; + data->ui_action_group = gtk_action_group_new ("PlumaDocInfoPluginActions"); + + gtk_action_group_set_translation_domain (data->ui_action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions (data->ui_action_group, + action_entries, + G_N_ELEMENTS (action_entries), + window); + + manager = pluma_window_get_ui_manager (window); + gtk_ui_manager_insert_action_group (manager, + data->ui_action_group, + -1); + + data->ui_id = gtk_ui_manager_new_merge_id (manager); + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "DocumentStatistics", + "DocumentStatistics", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + update_ui_real (window, + data); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, + data->ui_id); + gtk_ui_manager_remove_action_group (manager, + data->ui_action_group); + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, + data); +} + +static void +pluma_docinfo_plugin_class_init (PlumaDocInfoPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_docinfo_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; +} diff --git a/plugins/docinfo/pluma-docinfo-plugin.h b/plugins/docinfo/pluma-docinfo-plugin.h new file mode 100755 index 00000000..41252ff0 --- /dev/null +++ b/plugins/docinfo/pluma-docinfo-plugin.h @@ -0,0 +1,75 @@ +/* + * pluma-docinfo-plugin.h + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_DOCINFO_PLUGIN_H__ +#define __PLUMA_DOCINFO_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_DOCINFO_PLUGIN (pluma_docinfo_plugin_get_type ()) +#define PLUMA_DOCINFO_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_DOCINFO_PLUGIN, PlumaDocInfoPlugin)) +#define PLUMA_DOCINFO_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_DOCINFO_PLUGIN, PlumaDocInfoPluginClass)) +#define PLUMA_IS_DOCINFO_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_DOCINFO_PLUGIN)) +#define PLUMA_IS_DOCINFO_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_DOCINFO_PLUGIN)) +#define PLUMA_DOCINFO_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_DOCINFO_PLUGIN, PlumaDocInfoPluginClass)) + +/* Private structure type */ +typedef struct _PlumaDocInfoPluginPrivate PlumaDocInfoPluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaDocInfoPlugin PlumaDocInfoPlugin; + +struct _PlumaDocInfoPlugin +{ + PlumaPlugin parent_instance; +}; + +/* + * Class definition + */ +typedef struct _PlumaDocInfoPluginClass PlumaDocInfoPluginClass; + +struct _PlumaDocInfoPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_docinfo_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_DOCINFO_PLUGIN_H__ */ diff --git a/plugins/externaltools/Makefile.am b/plugins/externaltools/Makefile.am index f529640c..bec58b63 100755 --- a/plugins/externaltools/Makefile.am +++ b/plugins/externaltools/Makefile.am @@ -1,11 +1,11 @@ # External Tools plugin SUBDIRS = tools data scripts -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -plugin_in_files = externaltools.gedit-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = externaltools.pluma-plugin.desktop.in +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(plugin_in_files) diff --git a/plugins/externaltools/data/Makefile.am b/plugins/externaltools/data/Makefile.am index ae3a1c66..abac77c9 100755 --- a/plugins/externaltools/data/Makefile.am +++ b/plugins/externaltools/data/Makefile.am @@ -1,4 +1,4 @@ -TOOL_MERGE=$(top_srcdir)/plugins/externaltools/scripts/gedit-tool-merge.pl +TOOL_MERGE=$(top_srcdir)/plugins/externaltools/scripts/pluma-tool-merge.pl tools_in_files = \ build.tool.in \ @@ -29,7 +29,7 @@ desktop_in_files = $(install_tools_in_files:.tool.in=.desktop.in) desktop_files = $(install_tools_in_files:.tool.in=.desktop) tools_SCRIPTS = $(install_tools_in_files:.tool.in=) -toolsdir = $(GEDIT_PLUGINS_DATA_DIR)/externaltools/tools +toolsdir = $(PLUMA_PLUGINS_DATA_DIR)/externaltools/tools all_tools_in_files = \ $(tools_in_files) \ diff --git a/plugins/externaltools/data/build.desktop.in b/plugins/externaltools/data/build.desktop.in index 13767ee7..c2a49871 100755 --- a/plugins/externaltools/data/build.desktop.in +++ b/plugins/externaltools/data/build.desktop.in @@ -1,4 +1,4 @@ -[Gedit Tool] +[Pluma Tool] _Name=Build _Comment=Run "make" in the document directory Input=nothing diff --git a/plugins/externaltools/data/build.tool.in b/plugins/externaltools/data/build.tool.in index 0b81d5b6..d4cd7f43 100755 --- a/plugins/externaltools/data/build.tool.in +++ b/plugins/externaltools/data/build.tool.in @@ -1,7 +1,7 @@ #!/bin/sh EHOME=`echo $HOME | sed "s/#/\#/"` -DIR=$GEDIT_CURRENT_DOCUMENT_DIR +DIR=$PLUMA_CURRENT_DOCUMENT_DIR while test "$DIR" != "/"; do for m in GNUmakefile makefile Makefile; do if [ -f "${DIR}/${m}" ]; then diff --git a/plugins/externaltools/data/open-terminal-here-osx.desktop.in b/plugins/externaltools/data/open-terminal-here-osx.desktop.in index 801b003c..45587ef6 100755 --- a/plugins/externaltools/data/open-terminal-here-osx.desktop.in +++ b/plugins/externaltools/data/open-terminal-here-osx.desktop.in @@ -1,4 +1,4 @@ -[Gedit Tool] +[Pluma Tool] _Name=Open terminal here _Comment=Open a terminal in the document location Input=nothing diff --git a/plugins/externaltools/data/open-terminal-here-osx.tool.in b/plugins/externaltools/data/open-terminal-here-osx.tool.in index c3360064..86d842dc 100755 --- a/plugins/externaltools/data/open-terminal-here-osx.tool.in +++ b/plugins/externaltools/data/open-terminal-here-osx.tool.in @@ -1,6 +1,6 @@ #!/usr/bin/osascript -set the_path to system attribute "GEDIT_CURRENT_DOCUMENT_DIR" +set the_path to system attribute "PLUMA_CURRENT_DOCUMENT_DIR" set cmd to "cd " & quoted form of the_path tell application "System Events" to set terminalIsRunning to exists application process "Terminal" diff --git a/plugins/externaltools/data/open-terminal-here.desktop.in b/plugins/externaltools/data/open-terminal-here.desktop.in index 801b003c..45587ef6 100755 --- a/plugins/externaltools/data/open-terminal-here.desktop.in +++ b/plugins/externaltools/data/open-terminal-here.desktop.in @@ -1,4 +1,4 @@ -[Gedit Tool] +[Pluma Tool] _Name=Open terminal here _Comment=Open a terminal in the document location Input=nothing diff --git a/plugins/externaltools/data/open-terminal-here.tool.in b/plugins/externaltools/data/open-terminal-here.tool.in index d2dda8db..af35792a 100755 --- a/plugins/externaltools/data/open-terminal-here.tool.in +++ b/plugins/externaltools/data/open-terminal-here.tool.in @@ -1,4 +1,4 @@ #!/bin/sh #TODO: use "mateconftool-2 -g /desktop/mate/applications/terminal/exec" -mate-terminal --working-directory=$GEDIT_CURRENT_DOCUMENT_DIR & +mate-terminal --working-directory=$PLUMA_CURRENT_DOCUMENT_DIR & diff --git a/plugins/externaltools/data/remove-trailing-spaces.desktop.in b/plugins/externaltools/data/remove-trailing-spaces.desktop.in index 99b8b703..70bd8fd1 100755 --- a/plugins/externaltools/data/remove-trailing-spaces.desktop.in +++ b/plugins/externaltools/data/remove-trailing-spaces.desktop.in @@ -1,4 +1,4 @@ -[Gedit Tool] +[Pluma Tool] _Name=Remove trailing spaces _Comment=Remove useless trailing spaces in your file Input=document diff --git a/plugins/externaltools/data/run-command.desktop.in b/plugins/externaltools/data/run-command.desktop.in index b58294b0..4e15e678 100755 --- a/plugins/externaltools/data/run-command.desktop.in +++ b/plugins/externaltools/data/run-command.desktop.in @@ -1,4 +1,4 @@ -[Gedit Tool] +[Pluma Tool] _Name=Run command _Comment=Execute a custom command and put its output in a new document Input=nothing diff --git a/plugins/externaltools/data/run-command.tool.in b/plugins/externaltools/data/run-command.tool.in index ee611bbb..6f08a622 100755 --- a/plugins/externaltools/data/run-command.tool.in +++ b/plugins/externaltools/data/run-command.tool.in @@ -1,4 +1,4 @@ #!/bin/sh #TODO: use "mateconftool-2 -g /desktop/mate/applications/terminal/exec" -exec `matedialog --entry --title="Run command - gedit" --text="Command to run"` +exec `matedialog --entry --title="Run command - pluma" --text="Command to run"` diff --git a/plugins/externaltools/externaltools.gedit-plugin.desktop.in b/plugins/externaltools/externaltools.gedit-plugin.desktop.in deleted file mode 100755 index 5212c49b..00000000 --- a/plugins/externaltools/externaltools.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Loader=python -Module=externaltools -IAge=2 -_Name=External Tools -_Description=Execute external commands and shell scripts. -Authors=Steve Frécinaux -Copyright=Copyright © 2005 Steve Frécinaux -Website=http://www.gedit.org diff --git a/plugins/externaltools/externaltools.pluma-plugin.desktop.in b/plugins/externaltools/externaltools.pluma-plugin.desktop.in new file mode 100755 index 00000000..fcd15a9d --- /dev/null +++ b/plugins/externaltools/externaltools.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Loader=python +Module=externaltools +IAge=2 +_Name=External Tools +_Description=Execute external commands and shell scripts. +Authors=Steve Frécinaux +Copyright=Copyright © 2005 Steve Frécinaux +Website=http://www.pluma.org diff --git a/plugins/externaltools/scripts/Makefile.am b/plugins/externaltools/scripts/Makefile.am index 4ff8060b..237d5e58 100755 --- a/plugins/externaltools/scripts/Makefile.am +++ b/plugins/externaltools/scripts/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = gedit-tool-merge.pl +EXTRA_DIST = pluma-tool-merge.pl -include $(top_srcdir)/git.mk diff --git a/plugins/externaltools/scripts/gedit-tool-merge.pl b/plugins/externaltools/scripts/gedit-tool-merge.pl deleted file mode 100755 index 780d95dd..00000000 --- a/plugins/externaltools/scripts/gedit-tool-merge.pl +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl - -# gedit-tool-merge.pl -# This file is part of gedit -# -# Copyright (C) 2006 - Steve Frécinaux -# -# gedit is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# gedit is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with gedit; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301 USA - -# This script merges a script file with a desktop file containing -# metadata about the external tool. This is required in order to -# have translatable tools (bug #342042) since intltool can't extract -# string directly from tool files (a tool file being the combination -# of a script file and a metadata section). -# -# The desktop file is embedded in a comment of the script file, under -# the assumption that any scripting language supports # as a comment -# mark (this is likely to be true since the shebang uses #!). The -# section is placed at the top of the tool file, after the shebang and -# modelines if present. - -use strict; -use warnings; -use Getopt::Long; - -sub usage { - print < \$help, "output|o=s" => \$output) or &usage; -usage if $help or @ARGV lt 2; - -open INFILE, "<", $ARGV[0]; -open DFILE, "<", $ARGV[1]; -open STDOUT, ">", $output if $output; - -# Put shebang and various modelines at the top of the generated file. -$_ = ; -print and $_ = if /^#!/; -print and $_ = if /-\*-/; -print and $_ = if /(ex|vi|vim):/; - -# Put a blank line before the info block if there is one in INFILE. -print and $_ = if /^\s*$/; -seek INFILE, -length, 1; - -# Embed the desktop file... -print "# $_" while ; -print "\n"; - -# ...and write the remaining part of the script. -print while ; - -close INFILE; -close DFILE; -close STDOUT; diff --git a/plugins/externaltools/scripts/pluma-tool-merge.pl b/plugins/externaltools/scripts/pluma-tool-merge.pl new file mode 100755 index 00000000..37b752e7 --- /dev/null +++ b/plugins/externaltools/scripts/pluma-tool-merge.pl @@ -0,0 +1,78 @@ +#!/usr/bin/perl + +# pluma-tool-merge.pl +# This file is part of pluma +# +# Copyright (C) 2006 - Steve Frécinaux +# +# pluma is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# pluma is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with pluma; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA + +# This script merges a script file with a desktop file containing +# metadata about the external tool. This is required in order to +# have translatable tools (bug #342042) since intltool can't extract +# string directly from tool files (a tool file being the combination +# of a script file and a metadata section). +# +# The desktop file is embedded in a comment of the script file, under +# the assumption that any scripting language supports # as a comment +# mark (this is likely to be true since the shebang uses #!). The +# section is placed at the top of the tool file, after the shebang and +# modelines if present. + +use strict; +use warnings; +use Getopt::Long; + +sub usage { + print < \$help, "output|o=s" => \$output) or &usage; +usage if $help or @ARGV lt 2; + +open INFILE, "<", $ARGV[0]; +open DFILE, "<", $ARGV[1]; +open STDOUT, ">", $output if $output; + +# Put shebang and various modelines at the top of the generated file. +$_ = ; +print and $_ = if /^#!/; +print and $_ = if /-\*-/; +print and $_ = if /(ex|vi|vim):/; + +# Put a blank line before the info block if there is one in INFILE. +print and $_ = if /^\s*$/; +seek INFILE, -length, 1; + +# Embed the desktop file... +print "# $_" while ; +print "\n"; + +# ...and write the remaining part of the script. +print while ; + +close INFILE; +close DFILE; +close STDOUT; diff --git a/plugins/externaltools/tools/Makefile.am b/plugins/externaltools/tools/Makefile.am index 5edcab58..d90eb4aa 100755 --- a/plugins/externaltools/tools/Makefile.am +++ b/plugins/externaltools/tools/Makefile.am @@ -1,6 +1,6 @@ # Python snippets plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR)/externaltools +plugindir = $(PLUMA_PLUGINS_LIBS_DIR)/externaltools plugin_PYTHON = \ __init__.py \ capture.py \ @@ -11,7 +11,7 @@ plugin_PYTHON = \ filelookup.py \ linkparsing.py -uidir = $(GEDIT_PLUGINS_DATA_DIR)/externaltools/ui +uidir = $(PLUMA_PLUGINS_DATA_DIR)/externaltools/ui ui_DATA = tools.ui \ outputpanel.ui diff --git a/plugins/externaltools/tools/__init__.py b/plugins/externaltools/tools/__init__.py index a46aef8f..39522ede 100755 --- a/plugins/externaltools/tools/__init__.py +++ b/plugins/externaltools/tools/__init__.py @@ -1,5 +1,5 @@ # -*- coding: UTF-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # # This program is free software; you can redistribute it and/or modify @@ -19,7 +19,7 @@ __all__ = ('ExternalToolsPlugin', 'ExternalToolsWindowHelper', 'Manager', 'OutputPanel', 'Capture', 'UniqueById') -import gedit +import pluma import gtk from manager import Manager from library import ToolLibrary @@ -166,7 +166,7 @@ class ExternalToolsWindowHelper(object): manager = window.get_ui_manager() self._action_group = gtk.ActionGroup('ExternalToolsPluginActions') - self._action_group.set_translation_domain('gedit') + self._action_group.set_translation_domain('pluma') self._action_group.add_actions([('ExternalToolManager', None, _('Manage _External Tools...'), @@ -229,7 +229,7 @@ class ExternalToolsWindowHelper(object): def update_manager(self, tool): self._plugin.update_manager(tool) -class ExternalToolsPlugin(gedit.Plugin): +class ExternalToolsPlugin(pluma.Plugin): WINDOW_DATA_KEY = "ExternalToolsPluginWindowData" def __init__(self): @@ -263,7 +263,7 @@ class ExternalToolsPlugin(gedit.Plugin): self._manager.dialog.connect('destroy', self.on_manager_destroy) - window = gedit.app_get_default().get_active_window() + window = pluma.app_get_default().get_active_window() self._manager.run(window) return self._manager.dialog diff --git a/plugins/externaltools/tools/capture.py b/plugins/externaltools/tools/capture.py index e47862c8..2f065761 100755 --- a/plugins/externaltools/tools/capture.py +++ b/plugins/externaltools/tools/capture.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # # This program is free software; you can redistribute it and/or modify diff --git a/plugins/externaltools/tools/filelookup.py b/plugins/externaltools/tools/filelookup.py index 229823b7..ce4961f9 100755 --- a/plugins/externaltools/tools/filelookup.py +++ b/plugins/externaltools/tools/filelookup.py @@ -18,7 +18,7 @@ import os import gio -import gedit +import pluma class FileLookup: """ @@ -110,7 +110,7 @@ class OpenDocumentRelPathFileLookupProvider(FileLookupProvider): if path.startswith('/'): return None - for doc in gedit.app_get_default().get_documents(): + for doc in pluma.app_get_default().get_documents(): if doc.is_local(): location = doc.get_location() if location: @@ -135,7 +135,7 @@ class OpenDocumentFileLookupProvider(FileLookupProvider): if path.startswith('/'): return None - for doc in gedit.app_get_default().get_documents(): + for doc in pluma.app_get_default().get_documents(): if doc.is_local(): location = doc.get_location() if location and location.get_uri().endswith(path): diff --git a/plugins/externaltools/tools/functions.py b/plugins/externaltools/tools/functions.py index 0d2bfdbf..b4b666f6 100755 --- a/plugins/externaltools/tools/functions.py +++ b/plugins/externaltools/tools/functions.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # # This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ import os import gtk from gtk import gdk import gio -import gedit +import pluma #import gtksourceview from outputpanel import OutputPanel from capture import * @@ -53,7 +53,7 @@ def run_external_tool(window, node): capture = Capture(node.command, cwd) capture.env = os.environ.copy() - capture.set_env(GEDIT_CWD = cwd) + capture.set_env(PLUMA_CWD = cwd) view = window.get_active_view() if view is not None: @@ -63,7 +63,7 @@ def run_external_tool(window, node): # Current line number piter = document.get_iter_at_mark(document.get_insert()) - capture.set_env(GEDIT_CURRENT_LINE_NUMBER=str(piter.get_line() + 1)) + capture.set_env(PLUMA_CURRENT_LINE_NUMBER=str(piter.get_line() + 1)) # Current line text piter.set_line_offset(0) @@ -72,42 +72,42 @@ def run_external_tool(window, node): if not end.ends_line(): end.forward_to_line_end() - capture.set_env(GEDIT_CURRENT_LINE=piter.get_text(end)) + capture.set_env(PLUMA_CURRENT_LINE=piter.get_text(end)) # Selected text (only if input is not selection) if node.input != 'selection' and node.input != 'selection-document': bounds = document.get_selection_bounds() if bounds: - capture.set_env(GEDIT_SELECTED_TEXT=bounds[0].get_text(bounds[1])) + capture.set_env(PLUMA_SELECTED_TEXT=bounds[0].get_text(bounds[1])) bounds = current_word(document) - capture.set_env(GEDIT_CURRENT_WORD=bounds[0].get_text(bounds[1])) + capture.set_env(PLUMA_CURRENT_WORD=bounds[0].get_text(bounds[1])) - capture.set_env(GEDIT_CURRENT_DOCUMENT_TYPE=document.get_mime_type()) + capture.set_env(PLUMA_CURRENT_DOCUMENT_TYPE=document.get_mime_type()) if uri is not None: gfile = gio.File(uri) scheme = gfile.get_uri_scheme() name = os.path.basename(uri) - capture.set_env(GEDIT_CURRENT_DOCUMENT_URI = uri, - GEDIT_CURRENT_DOCUMENT_NAME = name, - GEDIT_CURRENT_DOCUMENT_SCHEME = scheme) - if gedit.utils.uri_has_file_scheme(uri): + capture.set_env(PLUMA_CURRENT_DOCUMENT_URI = uri, + PLUMA_CURRENT_DOCUMENT_NAME = name, + PLUMA_CURRENT_DOCUMENT_SCHEME = scheme) + if pluma.utils.uri_has_file_scheme(uri): path = gfile.get_path() cwd = os.path.dirname(path) capture.set_cwd(cwd) - capture.set_env(GEDIT_CURRENT_DOCUMENT_PATH = path, - GEDIT_CURRENT_DOCUMENT_DIR = cwd) + capture.set_env(PLUMA_CURRENT_DOCUMENT_PATH = path, + PLUMA_CURRENT_DOCUMENT_DIR = cwd) documents_uri = [doc.get_uri() for doc in window.get_documents() if doc.get_uri() is not None] documents_path = [gio.File(uri).get_path() for uri in documents_uri - if gedit.utils.uri_has_file_scheme(uri)] - capture.set_env(GEDIT_DOCUMENTS_URI = ' '.join(documents_uri), - GEDIT_DOCUMENTS_PATH = ' '.join(documents_path)) + if pluma.utils.uri_has_file_scheme(uri)] + capture.set_env(PLUMA_DOCUMENTS_URI = ' '.join(documents_uri), + PLUMA_DOCUMENTS_PATH = ' '.join(documents_path)) flags = capture.CAPTURE_BOTH @@ -224,7 +224,7 @@ class MultipleDocumentsSaver: for doc in docs: signals[doc] = doc.connect('saving', self.on_document_saving) - gedit.commands.save_document(window, doc) + pluma.commands.save_document(window, doc) doc.disconnect(signals[doc]) def on_document_saving(self, doc, size, total_size): @@ -277,7 +277,7 @@ def capture_end_execute_panel(capture, exit_code, panel, view, output_type): end.forward_chars(300) mtype = gio.content_type_guess(data=doc.get_text(start, end)) - lmanager = gedit.get_language_manager() + lmanager = pluma.get_language_manager() language = lmanager.guess_language(doc.get_uri(), mtype) diff --git a/plugins/externaltools/tools/library.py b/plugins/externaltools/tools/library.py index 6eb6ff1a..e3dc624c 100755 --- a/plugins/externaltools/tools/library.py +++ b/plugins/externaltools/tools/library.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2006 Steve Frécinaux # # This program is free software; you can redistribute it and/or modify @@ -41,19 +41,19 @@ class ToolLibrary(Singleton): if platform.platform() != 'Windows': for d in self.get_xdg_data_dirs(): - self.locations.append(os.path.join(d, 'gedit-2', 'plugins', 'externaltools', 'tools')) + self.locations.append(os.path.join(d, 'pluma-2', 'plugins', 'externaltools', 'tools')) self.locations.append(datadir) # self.locations[0] is where we save the custom scripts if platform.platform() == 'Windows': - toolsdir = os.path.expanduser('~/gedit/tools') + toolsdir = os.path.expanduser('~/pluma/tools') else: userdir = os.getenv('MATE22_USER_DIR') if userdir: - toolsdir = os.path.join(userdir, 'gedit/tools') + toolsdir = os.path.join(userdir, 'pluma/tools') else: - toolsdir = os.path.expanduser('~/.mate2/gedit/tools') + toolsdir = os.path.expanduser('~/.mate2/pluma/tools') self.locations.insert(0, toolsdir); @@ -80,9 +80,9 @@ class ToolLibrary(Singleton): import xml.etree.ElementTree as et userdir = os.getenv('MATE22_USER_DIR') if userdir: - filename = os.path.join(userdir, 'gedit/gedit-tools.xml') + filename = os.path.join(userdir, 'pluma/pluma-tools.xml') else: - filename = os.path.expanduser('~/.mate2/gedit/gedit-tools.xml') + filename = os.path.expanduser('~/.mate2/pluma/pluma-tools.xml') if not os.path.isfile(filename): return @@ -250,7 +250,7 @@ class Tool(object): for line in fp: if not in_block: - in_block = line.startswith('# [Gedit Tool]') + in_block = line.startswith('# [Pluma Tool]') continue if line.startswith('##') or line.startswith('# #'): continue if not line.startswith('# '): break @@ -389,7 +389,7 @@ class Tool(object): # before entering the data block for line in fp: - if line.startswith('# [Gedit Tool]'): + if line.startswith('# [Pluma Tool]'): break lines.append(line) # in the block: @@ -407,7 +407,7 @@ class Tool(object): return lines def _dump_properties(self): - lines = ['# [Gedit Tool]'] + lines = ['# [Pluma Tool]'] for item in self._properties.iteritems(): if item[0] in self._transform: lines.append('# %s=%s' % (item[0], self._transform[item[0]][1](item[1]))) diff --git a/plugins/externaltools/tools/manager.py b/plugins/externaltools/tools/manager.py index e28a088a..4d4d50aa 100755 --- a/plugins/externaltools/tools/manager.py +++ b/plugins/externaltools/tools/manager.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # # This program is free software; you can redistribute it and/or modify @@ -18,7 +18,7 @@ __all__ = ('Manager', ) -import gedit +import pluma import gtk import gtksourceview2 as gsv import os.path @@ -114,7 +114,7 @@ class LanguagesPopup(gtk.Window): def init_languages(self, languages): manager = gsv.LanguageManager() - langs = gedit.language_manager_list_languages_sorted(manager, True) + langs = pluma.language_manager_list_languages_sorted(manager, True) self.model.append([_('All languages'), None, not languages]) self.model.append(['-', None, False]) @@ -548,7 +548,7 @@ class Manager: self.script_hash = self.compute_hash(script) contenttype = gio.content_type_guess(data=script) - lmanager = gedit.get_language_manager() + lmanager = pluma.get_language_manager() language = lmanager.guess_language(content_type=contenttype) if language is not None: @@ -818,7 +818,7 @@ class Manager: def on_tool_manager_dialog_response(self, dialog, response): if response == gtk.RESPONSE_HELP: - gedit.help_display(self.dialog, 'gedit', 'gedit-external-tools-plugin') + pluma.help_display(self.dialog, 'pluma', 'pluma-external-tools-plugin') return self.on_tool_manager_dialog_focus_out(dialog, None) @@ -830,7 +830,7 @@ class Manager: def on_tool_manager_dialog_focus_out(self, dialog, event): self.save_current_tool() - for window in gedit.app_get_default().get_windows(): + for window in pluma.app_get_default().get_windows(): helper = window.get_data("ExternalToolsPluginWindowData") helper.menu.update() diff --git a/plugins/externaltools/tools/outputpanel.py b/plugins/externaltools/tools/outputpanel.py index a30aad72..9d1da65f 100755 --- a/plugins/externaltools/tools/outputpanel.py +++ b/plugins/externaltools/tools/outputpanel.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Gedit External Tools plugin +# Pluma External Tools plugin # Copyright (C) 2005-2006 Steve Frécinaux # Copyright (C) 2010 Per Arneng # @@ -19,7 +19,7 @@ __all__ = ('OutputPanel', 'UniqueById') -import gtk, gedit +import gtk, pluma import pango import gobject import os @@ -217,7 +217,7 @@ class OutputPanel(UniqueById): gfile = self.file_lookup.lookup(link.path) if gfile: - gedit.commands.load_uri(self.window, gfile.get_uri(), None, + pluma.commands.load_uri(self.window, gfile.get_uri(), None, link.line_nr) gobject.idle_add(self.idle_grab_focus) diff --git a/plugins/externaltools/tools/tools.ui b/plugins/externaltools/tools/tools.ui index dff7d192..8b40ad98 100755 --- a/plugins/externaltools/tools/tools.ui +++ b/plugins/externaltools/tools/tools.ui @@ -122,7 +122,7 @@ - + True @@ -517,7 +517,7 @@ automatic in - + commands_buffer True True diff --git a/plugins/filebrowser/Makefile.am b/plugins/filebrowser/Makefile.am index 22301d5b..6791255a 100755 --- a/plugins/filebrowser/Makefile.am +++ b/plugins/filebrowser/Makefile.am @@ -1,72 +1,72 @@ # filebrowser -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) BUILT_SOURCES = \ - gedit-file-browser-enum-types.h \ - gedit-file-browser-enum-types.c \ - gedit-file-browser-marshal.h \ - gedit-file-browser-marshal.c + pluma-file-browser-enum-types.h \ + pluma-file-browser-enum-types.c \ + pluma-file-browser-marshal.h \ + pluma-file-browser-marshal.c plugin_LTLIBRARIES = libfilebrowser.la NOINST_H_FILES = \ - gedit-file-bookmarks-store.h \ - gedit-file-browser-store.h \ - gedit-file-browser-view.h \ - gedit-file-browser-widget.h \ - gedit-file-browser-error.h \ - gedit-file-browser-utils.h \ - gedit-file-browser-plugin.h \ - gedit-file-browser-messages.h + pluma-file-bookmarks-store.h \ + pluma-file-browser-store.h \ + pluma-file-browser-view.h \ + pluma-file-browser-widget.h \ + pluma-file-browser-error.h \ + pluma-file-browser-utils.h \ + pluma-file-browser-plugin.h \ + pluma-file-browser-messages.h libfilebrowser_la_SOURCES = \ $(BUILT_SOURCES) \ - gedit-file-bookmarks-store.c \ - gedit-file-browser-store.c \ - gedit-file-browser-view.c \ - gedit-file-browser-widget.c \ - gedit-file-browser-utils.c \ - gedit-file-browser-plugin.c \ - gedit-file-browser-messages.c \ + pluma-file-bookmarks-store.c \ + pluma-file-browser-store.c \ + pluma-file-browser-view.c \ + pluma-file-browser-widget.c \ + pluma-file-browser-utils.c \ + pluma-file-browser-plugin.c \ + pluma-file-browser-messages.c \ $(NOINST_H_FILES) libfilebrowser_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libfilebrowser_la_LIBADD = $(GEDIT_LIBS) +libfilebrowser_la_LIBADD = $(PLUMA_LIBS) # UI files (if you use ui for your plugin, list those files here) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/filebrowser -ui_DATA = gedit-file-browser-widget-ui.xml +uidir = $(PLUMA_PLUGINS_DATA_DIR)/filebrowser +ui_DATA = pluma-file-browser-widget-ui.xml -plugin_in_files = filebrowser.gedit-plugin.desktop.in +plugin_in_files = filebrowser.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -gedit-file-browser-enum-types.h: gedit-file-browser-enum-types.h.template $(NOINST_H_FILES) $(GLIB_MKENUMS) - (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-file-browser-enum-types.h.template $(NOINST_H_FILES)) > $@ +pluma-file-browser-enum-types.h: pluma-file-browser-enum-types.h.template $(NOINST_H_FILES) $(GLIB_MKENUMS) + (cd $(srcdir) && $(GLIB_MKENUMS) --template pluma-file-browser-enum-types.h.template $(NOINST_H_FILES)) > $@ -gedit-file-browser-enum-types.c: gedit-file-browser-enum-types.c.template gedit-file-browser-enum-register.c.template $(NOINST_H_FILES) $(GLIB_MKENUMS) +pluma-file-browser-enum-types.c: pluma-file-browser-enum-types.c.template pluma-file-browser-enum-register.c.template $(NOINST_H_FILES) $(GLIB_MKENUMS) $(AM_V_GEN) (cd $(srcdir) && \ - $(GLIB_MKENUMS) --template gedit-file-browser-enum-types.c.template $(NOINST_H_FILES) && \ - $(GLIB_MKENUMS) --template gedit-file-browser-enum-register.c.template $(NOINST_H_FILES)) > $@ + $(GLIB_MKENUMS) --template pluma-file-browser-enum-types.c.template $(NOINST_H_FILES) && \ + $(GLIB_MKENUMS) --template pluma-file-browser-enum-register.c.template $(NOINST_H_FILES)) > $@ -gedit-file-browser-marshal.h: gedit-file-browser-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_file_browser_marshal > $@ +pluma-file-browser-marshal.h: pluma-file-browser-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=pluma_file_browser_marshal > $@ -gedit-file-browser-marshal.c: gedit-file-browser-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) echo "#include \"gedit-file-browser-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=gedit_file_browser_marshal >> $@ +pluma-file-browser-marshal.c: pluma-file-browser-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) echo "#include \"pluma-file-browser-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=pluma_file_browser_marshal >> $@ -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) schemasdir = $(MATECONF_SCHEMA_FILE_DIR) -schemas_in_files = gedit-file-browser.schemas.in +schemas_in_files = pluma-file-browser.schemas.in schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) @INTLTOOL_SCHEMAS_RULE@ @@ -86,10 +86,10 @@ EXTRA_DIST = \ $(ui_DATA) \ $(plugin_in_files) \ $(schemas_in_files) \ - gedit-file-browser-enum-types.h.template \ - gedit-file-browser-enum-types.c.template \ - gedit-file-browser-enum-register.c.template \ - gedit-file-browser-marshal.list + pluma-file-browser-enum-types.h.template \ + pluma-file-browser-enum-types.c.template \ + pluma-file-browser-enum-register.c.template \ + pluma-file-browser-marshal.list CLEANFILES = \ $(plugin_DATA) \ diff --git a/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in b/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in deleted file mode 100755 index 808816c5..00000000 --- a/plugins/filebrowser/filebrowser.gedit-plugin.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Gedit Plugin] -Loader=C -Module=filebrowser -IAge=2 -_Name=File Browser Pane -_Description=Easy file access from the side pane -Icon=system-file-manager -Authors=Jesse van den Kieboom -Copyright=Copyright © 2006 Jesse van den Kieboom -Website=http://www.gedit.org diff --git a/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in b/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in new file mode 100755 index 00000000..bf328f7a --- /dev/null +++ b/plugins/filebrowser/filebrowser.pluma-plugin.desktop.in @@ -0,0 +1,10 @@ +[Pluma Plugin] +Loader=C +Module=filebrowser +IAge=2 +_Name=File Browser Pane +_Description=Easy file access from the side pane +Icon=system-file-manager +Authors=Jesse van den Kieboom +Copyright=Copyright © 2006 Jesse van den Kieboom +Website=http://www.pluma.org diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.c b/plugins/filebrowser/gedit-file-bookmarks-store.c deleted file mode 100755 index 86e7f0c8..00000000 --- a/plugins/filebrowser/gedit-file-bookmarks-store.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * gedit-file-bookmarks-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include - -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-utils.h" - -#define GEDIT_FILE_BOOKMARKS_STORE_GET_PRIVATE(object)( \ - G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_FILE_BOOKMARKS_STORE, \ - GeditFileBookmarksStorePrivate)) - -struct _GeditFileBookmarksStorePrivate -{ - GVolumeMonitor * volume_monitor; - GFileMonitor * bookmarks_monitor; -}; - -static void remove_node (GtkTreeModel * model, - GtkTreeIter * iter); - -static void on_fs_changed (GVolumeMonitor *monitor, - GObject *object, - GeditFileBookmarksStore *model); - -static void on_bookmarks_file_changed (GFileMonitor * monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - GeditFileBookmarksStore * model); -static gboolean find_with_flags (GtkTreeModel * model, - GtkTreeIter * iter, - gpointer obj, - guint flags, - guint notflags); - -GEDIT_PLUGIN_DEFINE_TYPE(GeditFileBookmarksStore, gedit_file_bookmarks_store, GTK_TYPE_TREE_STORE) - -static void -gedit_file_bookmarks_store_dispose (GObject * object) -{ - GeditFileBookmarksStore *obj = GEDIT_FILE_BOOKMARKS_STORE (object); - - if (obj->priv->volume_monitor != NULL) { - g_signal_handlers_disconnect_by_func (obj->priv->volume_monitor, - on_fs_changed, - obj); - - g_object_unref (obj->priv->volume_monitor); - obj->priv->volume_monitor = NULL; - } - - if (obj->priv->bookmarks_monitor != NULL) { - g_object_unref (obj->priv->bookmarks_monitor); - obj->priv->bookmarks_monitor = NULL; - } - - G_OBJECT_CLASS (gedit_file_bookmarks_store_parent_class)->dispose (object); -} - -static void -gedit_file_bookmarks_store_finalize (GObject * object) -{ - G_OBJECT_CLASS (gedit_file_bookmarks_store_parent_class)->finalize (object); -} - -static void -gedit_file_bookmarks_store_class_init (GeditFileBookmarksStoreClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gedit_file_bookmarks_store_dispose; - object_class->finalize = gedit_file_bookmarks_store_finalize; - - g_type_class_add_private (object_class, sizeof (GeditFileBookmarksStorePrivate)); -} - -static void -gedit_file_bookmarks_store_init (GeditFileBookmarksStore * obj) -{ - obj->priv = GEDIT_FILE_BOOKMARKS_STORE_GET_PRIVATE (obj); -} - -/* Private */ -static void -add_node (GeditFileBookmarksStore *model, - GdkPixbuf *pixbuf, - const gchar *name, - GObject *obj, - guint flags, - GtkTreeIter *iter) -{ - GtkTreeIter newiter; - - gtk_tree_store_append (GTK_TREE_STORE (model), &newiter, NULL); - - gtk_tree_store_set (GTK_TREE_STORE (model), &newiter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, pixbuf, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, name, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, obj, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, flags, - -1); - - if (iter != NULL) - *iter = newiter; -} - -static gboolean -add_file (GeditFileBookmarksStore *model, - GFile *file, - const gchar *name, - guint flags, - GtkTreeIter *iter) -{ - GdkPixbuf *pixbuf = NULL; - gboolean native; - gchar *newname; - - native = g_file_is_native (file); - - if (native && !g_file_query_exists (file, NULL)) { - return FALSE; - } - - if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_HOME) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("user-home", GTK_ICON_SIZE_MENU); - else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("user-desktop", GTK_ICON_SIZE_MENU); - else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT) - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("drive-harddisk", GTK_ICON_SIZE_MENU); - - if (pixbuf == NULL) { - /* getting the icon is a sync get_info call, so we just do it for local files */ - if (native) { - pixbuf = gedit_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); - } else { - pixbuf = gedit_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); - } - } - - if (name == NULL) { - newname = gedit_file_browser_utils_file_basename (file); - } else { - newname = g_strdup (name); - } - - add_node (model, pixbuf, newname, G_OBJECT (file), flags, iter); - - if (pixbuf) - g_object_unref (pixbuf); - - g_free (newname); - - return TRUE; -} - -static void -check_mount_separator (GeditFileBookmarksStore * model, guint flags, - gboolean added) -{ - GtkTreeIter iter; - gboolean found; - - found = - find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, - flags | - GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR, 0); - - if (added && !found) { - /* Add the separator */ - add_node (model, NULL, NULL, NULL, - flags | GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR, - NULL); - } else if (!added && found) { - remove_node (GTK_TREE_MODEL (model), &iter); - } -} - -static void -init_special_directories (GeditFileBookmarksStore * model) -{ - gchar const *path; - GFile * file; - - path = g_get_home_dir (); - if (path != NULL) - { - file = g_file_new_for_path (path); - add_file (model, file, NULL, GEDIT_FILE_BOOKMARKS_STORE_IS_HOME | - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); - g_object_unref (file); - } - - path = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); - if (path != NULL) - { - file = g_file_new_for_path (path); - add_file (model, file, NULL, GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP | - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); - g_object_unref (file); - } - - path = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); - if (path != NULL) - { - file = g_file_new_for_path (path); - add_file (model, file, NULL, GEDIT_FILE_BOOKMARKS_STORE_IS_DOCUMENTS | - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); - g_object_unref (file); - } - - file = g_file_new_for_uri ("file:///"); - add_file (model, file, _("File System"), GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT, NULL); - g_object_unref (file); - - check_mount_separator (model, GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT, TRUE); -} - -static void -get_fs_properties (gpointer fs, - gchar **name, - GdkPixbuf **pixbuf, - guint *flags) -{ - GIcon *icon = NULL; - - *flags = GEDIT_FILE_BOOKMARKS_STORE_IS_FS; - *name = NULL; - *pixbuf = NULL; - - if (G_IS_DRIVE (fs)) - { - icon = g_drive_get_icon (G_DRIVE (fs)); - *name = g_drive_get_name (G_DRIVE (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE; - } - else if (G_IS_VOLUME (fs)) - { - icon = g_volume_get_icon (G_VOLUME (fs)); - *name = g_volume_get_name (G_VOLUME (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME; - } - else if (G_IS_MOUNT (fs)) - { - icon = g_mount_get_icon (G_MOUNT (fs)); - *name = g_mount_get_name (G_MOUNT (fs)); - - *flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT; - } - - if (icon) - { - *pixbuf = gedit_file_browser_utils_pixbuf_from_icon (icon, GTK_ICON_SIZE_MENU); - g_object_unref (icon); - } -} - - -static void -add_fs (GeditFileBookmarksStore *model, - gpointer fs, - guint flags, - GtkTreeIter *iter) -{ - gchar *name; - GdkPixbuf *pixbuf; - guint fsflags; - - get_fs_properties (fs, &name, &pixbuf, &fsflags); - add_node (model, pixbuf, name, fs, flags | fsflags, iter); - - if (pixbuf) - g_object_unref (pixbuf); - - g_free (name); - check_mount_separator (model, GEDIT_FILE_BOOKMARKS_STORE_IS_FS, TRUE); -} - -static void -process_volume_cb (GVolume *volume, - GeditFileBookmarksStore *model) -{ - GMount *mount; - guint flags = GEDIT_FILE_BOOKMARKS_STORE_NONE; - mount = g_volume_get_mount (volume); - - /* CHECK: should we use the LOCAL/REMOTE thing still? */ - if (mount) - { - /* Show mounted volume */ - add_fs (model, mount, flags, NULL); - g_object_unref (mount); - } - else if (g_volume_can_mount (volume)) - { - /* We also show the unmounted volume here so users can - mount it if they want to access it */ - add_fs (model, volume, flags, NULL); - } -} - -static void -process_drive_novolumes (GeditFileBookmarksStore *model, - GDrive *drive) -{ - if (g_drive_is_media_removable (drive) && - !g_drive_is_media_check_automatic (drive) && - g_drive_can_poll_for_media (drive)) - { - /* This can be the case for floppy drives or other - drives where media detection fails. We show the - drive and poll for media when the user activates - it */ - add_fs (model, drive, GEDIT_FILE_BOOKMARKS_STORE_NONE, NULL); - } -} - -static void -process_drive_cb (GDrive *drive, - GeditFileBookmarksStore *model) -{ - GList *volumes; - - volumes = g_drive_get_volumes (drive); - - if (volumes) - { - /* Add all volumes for the drive */ - g_list_foreach (volumes, (GFunc)process_volume_cb, model); - g_list_free (volumes); - } - else - { - process_drive_novolumes (model, drive); - } -} - -static void -init_drives (GeditFileBookmarksStore *model) -{ - GList *drives; - - drives = g_volume_monitor_get_connected_drives (model->priv->volume_monitor); - - g_list_foreach (drives, (GFunc)process_drive_cb, model); - g_list_foreach (drives, (GFunc)g_object_unref, NULL); - g_list_free (drives); -} - -static void -process_volume_nodrive_cb (GVolume *volume, - GeditFileBookmarksStore *model) -{ - GDrive *drive; - - drive = g_volume_get_drive (volume); - - if (drive) - { - g_object_unref (drive); - return; - } - - process_volume_cb (volume, model); -} - -static void -init_volumes (GeditFileBookmarksStore *model) -{ - GList *volumes; - - volumes = g_volume_monitor_get_volumes (model->priv->volume_monitor); - - g_list_foreach (volumes, (GFunc)process_volume_nodrive_cb, model); - g_list_foreach (volumes, (GFunc)g_object_unref, NULL); - g_list_free (volumes); -} - -static void -process_mount_novolume_cb (GMount *mount, - GeditFileBookmarksStore *model) -{ - GVolume *volume; - - volume = g_mount_get_volume (mount); - - if (volume) - { - g_object_unref (volume); - } - else if (!g_mount_is_shadowed (mount)) - { - /* Add the mount */ - add_fs (model, mount, GEDIT_FILE_BOOKMARKS_STORE_NONE, NULL); - } -} - -static void -init_mounts (GeditFileBookmarksStore *model) -{ - GList *mounts; - - mounts = g_volume_monitor_get_mounts (model->priv->volume_monitor); - - g_list_foreach (mounts, (GFunc)process_mount_novolume_cb, model); - g_list_foreach (mounts, (GFunc)g_object_unref, NULL); - g_list_free (mounts); -} - -static void -init_fs (GeditFileBookmarksStore * model) -{ - if (model->priv->volume_monitor == NULL) { - const gchar **ptr; - const gchar *signals[] = { - "drive-connected", "drive-changed", "drive-disconnected", - "volume-added", "volume-removed", "volume-changed", - "mount-added", "mount-removed", "mount-changed", - NULL - }; - - model->priv->volume_monitor = g_volume_monitor_get (); - - /* Connect signals */ - for (ptr = signals; *ptr; ptr++) - { - g_signal_connect (model->priv->volume_monitor, - *ptr, - G_CALLBACK (on_fs_changed), model); - } - } - - /* First go through all the connected drives */ - init_drives (model); - - /* Then add all volumes, not associated with a drive */ - init_volumes (model); - - /* Then finally add all mounts that have no volume */ - init_mounts (model); -} - -static gboolean -add_bookmark (GeditFileBookmarksStore * model, - gchar const * name, - gchar const * uri) -{ - GFile * file; - gboolean ret; - guint flags = GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK; - GtkTreeIter iter; - - file = g_file_new_for_uri (uri); - - if (g_file_is_native (file)) { - flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK; - } else { - flags |= GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK; - } - - ret = add_file (model, file, name, flags, &iter); - - g_object_unref (file); - - return ret; -} - -static void -init_bookmarks (GeditFileBookmarksStore * model) -{ - gchar *bookmarks; - GError *error = NULL; - gchar *contents; - gchar **lines; - gchar **line; - gboolean added = FALSE; - - /* Read the bookmarks file */ - bookmarks = g_build_filename (g_get_home_dir (), - ".gtk-bookmarks", - NULL); - - if (g_file_get_contents (bookmarks, &contents, NULL, &error)) { - lines = g_strsplit (contents, "\n", 0); - - for (line = lines; *line; ++line) { - if (**line) { - gchar *pos; - gchar *name; - - /* CHECK: is this really utf8? */ - pos = g_utf8_strchr (*line, -1, ' '); - - if (pos != NULL) { - *pos = '\0'; - name = pos + 1; - } else { - name = NULL; - } - - /* the bookmarks file should contain valid - * URIs, but paranoia is good */ - if (gedit_utils_is_valid_uri (*line)) { - added |= add_bookmark (model, name, *line); - } - } - } - - g_strfreev (lines); - g_free (contents); - - /* Add a watch */ - if (model->priv->bookmarks_monitor == NULL) { - GFile * file; - - file = g_file_new_for_path (bookmarks); - model->priv->bookmarks_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - - g_signal_connect (model->priv->bookmarks_monitor, - "changed", - (GCallback)on_bookmarks_file_changed, - model); - } - } else { - /* The bookmarks file doesn't exist (which is perfectly fine) */ - g_error_free (error); - } - - if (added) { - /* Bookmarks separator */ - add_node (model, NULL, NULL, NULL, - GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK | - GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR, NULL); - } - - g_free (bookmarks); -} - -static gint flags_order[] = { - GEDIT_FILE_BOOKMARKS_STORE_IS_HOME, - GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP, - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, - GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT, - GEDIT_FILE_BOOKMARKS_STORE_IS_FS, - GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK, - -1 -}; - -static gint -utf8_casecmp (gchar const *s1, const gchar * s2) -{ - gchar *n1; - gchar *n2; - gint result; - - n1 = g_utf8_casefold (s1, -1); - n2 = g_utf8_casefold (s2, -1); - - result = g_utf8_collate (n1, n2); - - g_free (n1); - g_free (n2); - - return result; -} - -static gint -bookmarks_compare_names (GtkTreeModel * model, GtkTreeIter * a, - GtkTreeIter * b) -{ - gchar *n1; - gchar *n2; - gint result; - guint f1; - guint f2; - - gtk_tree_model_get (model, a, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n1, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, - -1); - gtk_tree_model_get (model, b, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n2, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2, - -1); - - /* do not sort actual bookmarks to keep same order as in caja */ - if ((f1 & GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK) && - (f2 & GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK)) - result = 0; - else if (n1 == NULL && n2 == NULL) - result = 0; - else if (n1 == NULL) - result = -1; - else if (n2 == NULL) - result = 1; - else - result = utf8_casecmp (n1, n2); - - g_free (n1); - g_free (n2); - - return result; -} - -static gint -bookmarks_compare_flags (GtkTreeModel * model, GtkTreeIter * a, - GtkTreeIter * b) -{ - guint f1; - guint f2; - gint *flags; - guint sep; - - sep = GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR; - - gtk_tree_model_get (model, a, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, - -1); - gtk_tree_model_get (model, b, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2, - -1); - - for (flags = flags_order; *flags != -1; ++flags) { - if ((f1 & *flags) != (f2 & *flags)) { - if (f1 & *flags) { - return -1; - } else { - return 1; - } - } else if ((f1 & *flags) && (f1 & sep) != (f2 & sep)) { - if (f1 & sep) - return -1; - else - return 1; - } - } - - return 0; -} - -static gint -bookmarks_compare_func (GtkTreeModel * model, GtkTreeIter * a, - GtkTreeIter * b, gpointer user_data) -{ - gint result; - - result = bookmarks_compare_flags (model, a, b); - - if (result == 0) - result = bookmarks_compare_names (model, a, b); - - return result; -} - -static gboolean -find_with_flags (GtkTreeModel * model, GtkTreeIter * iter, gpointer obj, - guint flags, guint notflags) -{ - GtkTreeIter child; - guint childflags = 0; - GObject * childobj; - gboolean fequal; - - if (!gtk_tree_model_get_iter_first (model, &child)) - return FALSE; - - do { - gtk_tree_model_get (model, &child, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, - &childobj, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, - &childflags, -1); - - fequal = (obj == childobj); - - if (childobj) - g_object_unref (childobj); - - if ((obj == NULL || fequal) && - (childflags & flags) == flags - && !(childflags & notflags)) { - *iter = child; - return TRUE; - } - } while (gtk_tree_model_iter_next (model, &child)); - - return FALSE; -} - -static void -remove_node (GtkTreeModel * model, GtkTreeIter * iter) -{ - guint flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!(flags & GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR)) { - if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS) { - check_mount_separator (GEDIT_FILE_BOOKMARKS_STORE (model), - flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS, - FALSE); - } - } - - gtk_tree_store_remove (GTK_TREE_STORE (model), iter); -} - -static void -remove_bookmarks (GeditFileBookmarksStore * model) -{ - GtkTreeIter iter; - - while (find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, - GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK, - 0)) { - remove_node (GTK_TREE_MODEL (model), &iter); - } -} - -static void -initialize_fill (GeditFileBookmarksStore * model) -{ - init_special_directories (model); - init_fs (model); - init_bookmarks (model); -} - -/* Public */ -GeditFileBookmarksStore * -gedit_file_bookmarks_store_new (void) -{ - GeditFileBookmarksStore *model; - GType column_types[] = { - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_OBJECT, - G_TYPE_UINT - }; - - model = g_object_new (GEDIT_TYPE_FILE_BOOKMARKS_STORE, NULL); - gtk_tree_store_set_column_types (GTK_TREE_STORE (model), - GEDIT_FILE_BOOKMARKS_STORE_N_COLUMNS, - column_types); - - gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), - bookmarks_compare_func, - NULL, NULL); - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), - GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, - GTK_SORT_ASCENDING); - - initialize_fill (model); - - return model; -} - -gchar * -gedit_file_bookmarks_store_get_uri (GeditFileBookmarksStore * model, - GtkTreeIter * iter) -{ - GObject * obj; - GFile * file = NULL; - guint flags; - gchar * ret = NULL; - gboolean isfs; - - g_return_val_if_fail (GEDIT_IS_FILE_BOOKMARKS_STORE (model), NULL); - g_return_val_if_fail (iter != NULL, NULL); - - gtk_tree_model_get (GTK_TREE_MODEL (model), iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, - &flags, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, - &obj, - -1); - - if (obj == NULL) - return NULL; - - isfs = (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_FS); - - if (isfs && (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT)) - { - file = g_mount_get_root (G_MOUNT (obj)); - } - else if (!isfs) - { - file = g_object_ref (obj); - } - - g_object_unref (obj); - - if (file) - { - ret = g_file_get_uri (file); - g_object_unref (file); - } - - return ret; -} - -void -gedit_file_bookmarks_store_refresh (GeditFileBookmarksStore * model) -{ - gtk_tree_store_clear (GTK_TREE_STORE (model)); - initialize_fill (model); -} - -static void -on_fs_changed (GVolumeMonitor *monitor, - GObject *object, - GeditFileBookmarksStore *model) -{ - GtkTreeModel *tree_model = GTK_TREE_MODEL (model); - guint flags = GEDIT_FILE_BOOKMARKS_STORE_IS_FS; - guint noflags = GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR; - GtkTreeIter iter; - - /* clear all fs items */ - while (find_with_flags (tree_model, &iter, NULL, flags, noflags)) - remove_node (tree_model, &iter); - - /* then reinitialize */ - init_fs (model); -} - -static void -on_bookmarks_file_changed (GFileMonitor * monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - GeditFileBookmarksStore * model) -{ - switch (event_type) { - case G_FILE_MONITOR_EVENT_CHANGED: - case G_FILE_MONITOR_EVENT_CREATED: - /* Re-initialize bookmarks */ - remove_bookmarks (model); - init_bookmarks (model); - break; - case G_FILE_MONITOR_EVENT_DELETED: // FIXME: shouldn't we also monitor the directory? - /* Remove bookmarks */ - remove_bookmarks (model); - g_object_unref (monitor); - model->priv->bookmarks_monitor = NULL; - break; - default: - break; - } -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-bookmarks-store.h b/plugins/filebrowser/gedit-file-bookmarks-store.h deleted file mode 100755 index bd20911e..00000000 --- a/plugins/filebrowser/gedit-file-bookmarks-store.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * gedit-file-bookmarks-store.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BOOKMARKS_STORE_H__ -#define __GEDIT_FILE_BOOKMARKS_STORE_H__ - -#include - -G_BEGIN_DECLS -#define GEDIT_TYPE_FILE_BOOKMARKS_STORE (gedit_file_bookmarks_store_get_type ()) -#define GEDIT_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStore)) -#define GEDIT_FILE_BOOKMARKS_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStore const)) -#define GEDIT_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStoreClass)) -#define GEDIT_IS_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE)) -#define GEDIT_IS_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BOOKMARKS_STORE)) -#define GEDIT_FILE_BOOKMARKS_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BOOKMARKS_STORE, GeditFileBookmarksStoreClass)) - -typedef struct _GeditFileBookmarksStore GeditFileBookmarksStore; -typedef struct _GeditFileBookmarksStoreClass GeditFileBookmarksStoreClass; -typedef struct _GeditFileBookmarksStorePrivate GeditFileBookmarksStorePrivate; - -enum -{ - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON = 0, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, - GEDIT_FILE_BOOKMARKS_STORE_N_COLUMNS -}; - -enum -{ - GEDIT_FILE_BOOKMARKS_STORE_NONE = 0, - GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR = 1 << 0, /* Separator item */ - GEDIT_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR = 1 << 1, /* Special user dir */ - GEDIT_FILE_BOOKMARKS_STORE_IS_HOME = 1 << 2, /* The special Home user directory */ - GEDIT_FILE_BOOKMARKS_STORE_IS_DESKTOP = 1 << 3, /* The special Desktop user directory */ - GEDIT_FILE_BOOKMARKS_STORE_IS_DOCUMENTS = 1 << 4, /* The special Documents user directory */ - GEDIT_FILE_BOOKMARKS_STORE_IS_FS = 1 << 5, /* A mount object */ - GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT = 1 << 6, /* A mount object */ - GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME = 1 << 7, /* A volume object */ - GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE = 1 << 8, /* A drive object */ - GEDIT_FILE_BOOKMARKS_STORE_IS_ROOT = 1 << 9, /* The root file system (file:///) */ - GEDIT_FILE_BOOKMARKS_STORE_IS_BOOKMARK = 1 << 10, /* A gtk bookmark */ - GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK = 1 << 11, /* A remote gtk bookmark */ - GEDIT_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK = 1 << 12 /* A local gtk bookmark */ -}; - -struct _GeditFileBookmarksStore -{ - GtkTreeStore parent; - - GeditFileBookmarksStorePrivate *priv; -}; - -struct _GeditFileBookmarksStoreClass -{ - GtkTreeStoreClass parent_class; -}; - -GType gedit_file_bookmarks_store_get_type (void) G_GNUC_CONST; -GType gedit_file_bookmarks_store_register_type (GTypeModule * module); - -GeditFileBookmarksStore *gedit_file_bookmarks_store_new (void); -gchar *gedit_file_bookmarks_store_get_uri (GeditFileBookmarksStore * model, - GtkTreeIter * iter); -void gedit_file_bookmarks_store_refresh (GeditFileBookmarksStore * model); - -G_END_DECLS -#endif /* __GEDIT_FILE_BOOKMARKS_STORE_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-enum-register.c.template b/plugins/filebrowser/gedit-file-browser-enum-register.c.template deleted file mode 100755 index 63a9c562..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-register.c.template +++ /dev/null @@ -1,20 +0,0 @@ -/*** BEGIN file-header ***/ -void -gedit_file_browser_enum_and_flag_register_type (GTypeModule * module) -{ -/*** END file-header ***/ - -/*** BEGIN file-production ***/ - /* Enumerations from "@filename@" */ - -/*** END file-production ***/ - -/*** BEGIN enumeration-production ***/ - register_@enum_name@ (module); - -/*** END enumeration-production ***/ - -/*** BEGIN file-tail ***/ -} - -/*** END file-tail ***/ diff --git a/plugins/filebrowser/gedit-file-browser-enum-types.c.template b/plugins/filebrowser/gedit-file-browser-enum-types.c.template deleted file mode 100755 index 4e89370d..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-types.c.template +++ /dev/null @@ -1,45 +0,0 @@ -/*** BEGIN file-header ***/ -#include "gedit-file-browser-enum-types.h" - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* enumerations from "@filename@" */ -#include "@filename@" - -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -static GType @enum_name@_type = 0; - -static GType -register_@enum_name@ (GTypeModule *module) -{ - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, - "@VALUENAME@", - "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - - @enum_name@_type = - g_type_module_register_@type@ (module, - "@EnumName@", - values); - - return @enum_name@_type; -} - -GType -@enum_name@_get_type (void) -{ - return @enum_name@_type; -} - -/*** END value-tail ***/ diff --git a/plugins/filebrowser/gedit-file-browser-enum-types.h.template b/plugins/filebrowser/gedit-file-browser-enum-types.h.template deleted file mode 100755 index aea4fad9..00000000 --- a/plugins/filebrowser/gedit-file-browser-enum-types.h.template +++ /dev/null @@ -1,29 +0,0 @@ -/*** BEGIN file-header ***/ -#ifndef __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ -#define __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* Enumerations from "@filename@" */ - -/*** END file-production ***/ - -/*** BEGIN enumeration-production ***/ -#define GEDIT_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) -GType @enum_name@_get_type (void) G_GNUC_CONST; - -/*** END enumeration-production ***/ - -/*** BEGIN file-tail ***/ -void gedit_file_browser_enum_and_flag_register_type (GTypeModule * module); - -G_END_DECLS - -#endif /* __GEDIT_FILE_BROWSER_ENUM_TYPES_H__ */ -/*** END file-tail ***/ - diff --git a/plugins/filebrowser/gedit-file-browser-error.h b/plugins/filebrowser/gedit-file-browser-error.h deleted file mode 100755 index ec5b8618..00000000 --- a/plugins/filebrowser/gedit-file-browser-error.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * gedit-file-browser-error.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_ERROR_H__ -#define __GEDIT_FILE_BROWSER_ERROR_H__ - -G_BEGIN_DECLS - -typedef enum { - GEDIT_FILE_BROWSER_ERROR_NONE, - GEDIT_FILE_BROWSER_ERROR_RENAME, - GEDIT_FILE_BROWSER_ERROR_DELETE, - GEDIT_FILE_BROWSER_ERROR_NEW_FILE, - GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY, - GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY, - GEDIT_FILE_BROWSER_ERROR_SET_ROOT, - GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY, - GEDIT_FILE_BROWSER_ERROR_NUM -} GeditFileBrowserError; - -G_END_DECLS - -#endif /* __GEDIT_FILE_BROWSER_ERROR_H__ */ diff --git a/plugins/filebrowser/gedit-file-browser-marshal.list b/plugins/filebrowser/gedit-file-browser-marshal.list deleted file mode 100755 index 5fa72c8b..00000000 --- a/plugins/filebrowser/gedit-file-browser-marshal.list +++ /dev/null @@ -1,5 +0,0 @@ -VOID:UINT,STRING -VOID:STRING,STRING -BOOL:OBJECT,POINTER -BOOL:POINTER -BOOL:VOID diff --git a/plugins/filebrowser/gedit-file-browser-messages.c b/plugins/filebrowser/gedit-file-browser-messages.c deleted file mode 100755 index b587edf1..00000000 --- a/plugins/filebrowser/gedit-file-browser-messages.c +++ /dev/null @@ -1,1033 +0,0 @@ -#include "gedit-file-browser-messages.h" -#include "gedit-file-browser-store.h" -#include - -#define MESSAGE_OBJECT_PATH "/plugins/filebrowser" -#define WINDOW_DATA_KEY "GeditFileBrowserMessagesWindowData" - -#define BUS_CONNECT(bus, name, data) gedit_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (GeditMessageCallback) message_##name##_cb, data, NULL) - -typedef struct -{ - GeditWindow *window; - GeditMessage *message; -} MessageCacheData; - -typedef struct -{ - guint row_inserted_id; - guint row_deleted_id; - guint root_changed_id; - guint begin_loading_id; - guint end_loading_id; - - GList *merge_ids; - GtkActionGroup *merged_actions; - - GeditMessageBus *bus; - GeditFileBrowserWidget *widget; - GHashTable *row_tracking; - - GHashTable *filters; -} WindowData; - -typedef struct -{ - gulong id; - - GeditWindow *window; - GeditMessage *message; -} FilterData; - -static WindowData * -window_data_new (GeditWindow *window, - GeditFileBrowserWidget *widget) -{ - WindowData *data = g_slice_new (WindowData); - GtkUIManager *manager; - GList *groups; - - data->bus = gedit_window_get_message_bus (window); - data->widget = widget; - data->row_tracking = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify)g_free, - (GDestroyNotify)gtk_tree_row_reference_free); - - data->filters = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify)g_free, - NULL); - - manager = gedit_file_browser_widget_get_ui_manager (widget); - - data->merge_ids = NULL; - data->merged_actions = gtk_action_group_new ("MessageMergedActions"); - - groups = gtk_ui_manager_get_action_groups (manager); - gtk_ui_manager_insert_action_group (manager, data->merged_actions, g_list_length (groups)); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); - - return data; -} - -static WindowData * -get_window_data (GeditWindow * window) -{ - return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); -} - -static void -window_data_free (GeditWindow *window) -{ - WindowData *data = get_window_data (window); - GtkUIManager *manager; - GList *item; - - g_hash_table_destroy (data->row_tracking); - g_hash_table_destroy (data->filters); - - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - gtk_ui_manager_remove_action_group (manager, data->merged_actions); - - for (item = data->merge_ids; item; item = item->next) - gtk_ui_manager_remove_ui (manager, GPOINTER_TO_INT (item->data)); - - g_list_free (data->merge_ids); - g_object_unref (data->merged_actions); - - g_slice_free (WindowData, data); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static FilterData * -filter_data_new (GeditWindow *window, - GeditMessage *message) -{ - FilterData *data = g_slice_new (FilterData); - WindowData *wdata; - - data->window = window; - data->id = 0; - data->message = message; - - wdata = get_window_data (window); - - g_hash_table_insert (wdata->filters, - gedit_message_type_identifier (gedit_message_get_object_path (message), - gedit_message_get_method (message)), - data); - - return data; -} - -static void -filter_data_free (FilterData *data) -{ - WindowData *wdata = get_window_data (data->window); - gchar *identifier; - - identifier = gedit_message_type_identifier (gedit_message_get_object_path (data->message), - gedit_message_get_method (data->message)); - - g_hash_table_remove (wdata->filters, identifier); - g_free (identifier); - - g_object_unref (data->message); - g_slice_free (FilterData, data); -} - -static GtkTreePath * -track_row_lookup (WindowData *data, - const gchar *id) -{ - GtkTreeRowReference *ref; - - ref = (GtkTreeRowReference *)g_hash_table_lookup (data->row_tracking, id); - - if (!ref) - return NULL; - - return gtk_tree_row_reference_get_path (ref); -} - -static void -message_cache_data_free (MessageCacheData *data) -{ - g_object_unref (data->message); - g_slice_free (MessageCacheData, data); -} - -static MessageCacheData * -message_cache_data_new (GeditWindow *window, - GeditMessage *message) -{ - MessageCacheData *data = g_slice_new (MessageCacheData); - - data->window = window; - data->message = message; - - return data; -} - -static void -message_get_root_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GeditFileBrowserStore *store; - gchar *uri; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - uri = gedit_file_browser_store_get_virtual_root (store); - - gedit_message_set (message, "uri", uri, NULL); - g_free (uri); -} - -static void -message_set_root_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gchar *root = NULL; - gchar *virtual = NULL; - - gedit_message_get (message, "uri", &root, NULL); - - if (!root) - return; - - if (gedit_message_has_key (message, "virtual")) - gedit_message_get (message, "virtual", &virtual, NULL); - - if (virtual) - gedit_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual); - else - gedit_file_browser_widget_set_root (data->widget, root, TRUE); - - g_free (root); - g_free (virtual); -} - -static void -message_set_emblem_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gchar *id = NULL; - gchar *emblem = NULL; - GtkTreePath *path; - GeditFileBrowserStore *store; - - gedit_message_get (message, "id", &id, "emblem", &emblem, NULL); - - if (!id || !emblem) - { - g_free (id); - g_free (emblem); - - return; - } - - path = track_row_lookup (data, id); - - if (path != NULL) - { - GError *error = NULL; - GdkPixbuf *pixbuf; - - pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), - emblem, - 10, - 0, - &error); - - if (pixbuf) - { - GValue value = { 0, }; - GtkTreeIter iter; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - - if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) - { - g_value_init (&value, GDK_TYPE_PIXBUF); - g_value_set_object (&value, pixbuf); - - gedit_file_browser_store_set_value (store, - &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM, - &value); - - g_value_unset (&value); - } - - g_object_unref (pixbuf); - } - - if (error) - g_error_free (error); - } - - g_free (id); - g_free (emblem); -} - -static gchar * -item_id (const gchar *path, - const gchar *uri) -{ - return g_strconcat (path, "::", uri, NULL); -} - -static gchar * -track_row (WindowData *data, - GeditFileBrowserStore *store, - GtkTreePath *path, - const gchar *uri) -{ - GtkTreeRowReference *ref; - gchar *id; - gchar *pathstr; - - pathstr = gtk_tree_path_to_string (path); - id = item_id (pathstr, uri); - - ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path); - g_hash_table_insert (data->row_tracking, g_strdup (id), ref); - - g_free (pathstr); - - return id; -} - -static void -set_item_message (WindowData *data, - GtkTreeIter *iter, - GtkTreePath *path, - GeditMessage *message) -{ - GeditFileBrowserStore *store; - gchar *uri = NULL; - guint flags = 0; - gchar *track_id; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!uri) - return; - - if (path && gtk_tree_path_get_depth (path) != 0) - track_id = track_row (data, store, path, uri); - else - track_id = NULL; - - gedit_message_set (message, - "id", track_id, - "uri", uri, - NULL); - - if (gedit_message_has_key (message, "is_directory")) - { - gedit_message_set (message, - "is_directory", FILE_IS_DIR (flags), - NULL); - } - - g_free (uri); - g_free (track_id); -} - -static gboolean -custom_message_filter_func (GeditFileBrowserWidget *widget, - GeditFileBrowserStore *store, - GtkTreeIter *iter, - FilterData *data) -{ - WindowData *wdata = get_window_data (data->window); - gchar *uri = NULL; - guint flags = 0; - gboolean filter = FALSE; - GtkTreePath *path; - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!uri || FILE_IS_DUMMY (flags)) - { - g_free (uri); - return FALSE; - } - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); - set_item_message (wdata, iter, path, data->message); - gtk_tree_path_free (path); - - gedit_message_set (data->message, "filter", filter, NULL); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - gedit_message_get (data->message, "filter", &filter, NULL); - - return !filter; -} - -static void -message_add_filter_cb (GeditMessageBus *bus, - GeditMessage *message, - GeditWindow *window) -{ - gchar *object_path = NULL; - gchar *method = NULL; - gulong id; - GeditMessageType *message_type; - GeditMessage *cbmessage; - FilterData *filter_data; - WindowData *data = get_window_data (window); - - gedit_message_get (message, - "object_path", &object_path, - "method", &method, - NULL); - - // Check if there exists such a 'callback' message - if (!object_path || !method) - { - g_free (object_path); - g_free (method); - - return; - } - - message_type = gedit_message_bus_lookup (bus, object_path, method); - - if (!message_type) - { - g_free (object_path); - g_free (method); - - return; - } - - // Check if the message type has the correct arguments - if (gedit_message_type_lookup (message_type, "id") != G_TYPE_STRING || - gedit_message_type_lookup (message_type, "uri") != G_TYPE_STRING || - gedit_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN || - gedit_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN) - { - return; - } - - cbmessage = gedit_message_type_instantiate (message_type, - "id", NULL, - "uri", NULL, - "is_directory", FALSE, - "filter", FALSE, - NULL); - - // Register the custom filter on the widget - filter_data = filter_data_new (window, cbmessage); - id = gedit_file_browser_widget_add_filter (data->widget, - (GeditFileBrowserWidgetFilterFunc)custom_message_filter_func, - filter_data, - (GDestroyNotify)filter_data_free); - - filter_data->id = id; -} - -static void -message_remove_filter_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gulong id = 0; - - gedit_message_get (message, "id", &id, NULL); - - if (!id) - return; - - gedit_file_browser_widget_remove_filter (data->widget, id); -} - -static void -message_up_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GeditFileBrowserStore *store = gedit_file_browser_widget_get_browser_store (data->widget); - - gedit_file_browser_store_set_virtual_root_up (store); -} - -static void -message_history_back_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gedit_file_browser_widget_history_back (data->widget); -} - -static void -message_history_forward_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gedit_file_browser_widget_history_forward (data->widget); -} - -static void -message_refresh_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gedit_file_browser_widget_refresh (data->widget); -} - -static void -message_set_show_hidden_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gboolean active = FALSE; - GeditFileBrowserStore *store; - GeditFileBrowserStoreFilterMode mode; - - gedit_message_get (message, "active", &active, NULL); - - store = gedit_file_browser_widget_get_browser_store (data->widget); - mode = gedit_file_browser_store_get_filter_mode (store); - - if (active) - mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; - else - mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; - - gedit_file_browser_store_set_filter_mode (store, mode); -} - -static void -message_set_show_binary_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gboolean active = FALSE; - GeditFileBrowserStore *store; - GeditFileBrowserStoreFilterMode mode; - - gedit_message_get (message, "active", &active, NULL); - - store = gedit_file_browser_widget_get_browser_store (data->widget); - mode = gedit_file_browser_store_get_filter_mode (store); - - if (active) - mode &= ~GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - else - mode |= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - - gedit_file_browser_store_set_filter_mode (store, mode); -} - -static void -message_show_bookmarks_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gedit_file_browser_widget_show_bookmarks (data->widget); -} - -static void -message_show_files_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - gedit_file_browser_widget_show_files (data->widget); -} - -static void -message_add_context_item_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GtkAction *action = NULL; - gchar *path = NULL; - gchar *name; - GtkUIManager *manager; - guint merge_id; - - gedit_message_get (message, - "action", &action, - "path", &path, - NULL); - - if (!action || !path) - { - if (action) - g_object_unref (action); - - g_free (path); - return; - } - - gtk_action_group_add_action (data->merged_actions, action); - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - name = g_strconcat (gtk_action_get_name (action), "MenuItem", NULL); - merge_id = gtk_ui_manager_new_merge_id (manager); - - gtk_ui_manager_add_ui (manager, - merge_id, - path, - name, - gtk_action_get_name (action), - GTK_UI_MANAGER_AUTO, - FALSE); - - if (gtk_ui_manager_get_widget (manager, path)) - { - data->merge_ids = g_list_prepend (data->merge_ids, GINT_TO_POINTER (merge_id)); - gedit_message_set (message, "id", merge_id, NULL); - } - else - { - gedit_message_set (message, "id", 0, NULL); - } - - g_object_unref (action); - g_free (path); - g_free (name); -} - -static void -message_remove_context_item_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - guint merge_id = 0; - GtkUIManager *manager; - - gedit_message_get (message, "id", &merge_id, NULL); - - if (merge_id == 0) - return; - - manager = gedit_file_browser_widget_get_ui_manager (data->widget); - - data->merge_ids = g_list_remove (data->merge_ids, GINT_TO_POINTER (merge_id)); - gtk_ui_manager_remove_ui (manager, merge_id); -} - -static void -message_get_view_cb (GeditMessageBus *bus, - GeditMessage *message, - WindowData *data) -{ - GeditFileBrowserView *view; - view = gedit_file_browser_widget_get_browser_view (data->widget); - - gedit_message_set (message, "view", view, NULL); -} - -static void -register_methods (GeditWindow *window, - GeditFileBrowserWidget *widget) -{ - GeditMessageBus *bus = gedit_window_get_message_bus (window); - WindowData *data = get_window_data (window); - - /* Register method calls */ - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "get_root", - 1, - "uri", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_root", - 1, - "uri", G_TYPE_STRING, - "virtual", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_emblem", - 0, - "id", G_TYPE_STRING, - "emblem", G_TYPE_STRING, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "add_filter", - 1, - "object_path", G_TYPE_STRING, - "method", G_TYPE_STRING, - "id", G_TYPE_ULONG, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "remove_filter", - 0, - "id", G_TYPE_ULONG, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "add_context_item", - 1, - "action", GTK_TYPE_ACTION, - "path", G_TYPE_STRING, - "id", G_TYPE_UINT, - NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "remove_context_item", - 0, - "id", G_TYPE_UINT, - NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL); - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_show_hidden", - 0, - "active", G_TYPE_BOOLEAN, - NULL); - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "set_show_binary", - 0, - "active", G_TYPE_BOOLEAN, - NULL); - - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL); - gedit_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL); - - gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "get_view", - 1, - "view", GEDIT_TYPE_FILE_BROWSER_VIEW, - NULL); - - BUS_CONNECT (bus, get_root, data); - BUS_CONNECT (bus, set_root, data); - BUS_CONNECT (bus, set_emblem, data); - BUS_CONNECT (bus, add_filter, window); - BUS_CONNECT (bus, remove_filter, data); - - BUS_CONNECT (bus, add_context_item, data); - BUS_CONNECT (bus, remove_context_item, data); - - BUS_CONNECT (bus, up, data); - BUS_CONNECT (bus, history_back, data); - BUS_CONNECT (bus, history_forward, data); - - BUS_CONNECT (bus, refresh, data); - - BUS_CONNECT (bus, set_show_hidden, data); - BUS_CONNECT (bus, set_show_binary, data); - - BUS_CONNECT (bus, show_bookmarks, data); - BUS_CONNECT (bus, show_files, data); - - BUS_CONNECT (bus, get_view, data); -} - -static void -store_row_inserted (GeditFileBrowserStore *store, - GtkTreePath *path, - GtkTreeIter *iter, - MessageCacheData *data) -{ - gchar *uri = NULL; - guint flags = 0; - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags)) - { - WindowData *wdata = get_window_data (data->window); - - set_item_message (wdata, iter, path, data->message); - gedit_message_bus_send_message_sync (wdata->bus, data->message); - } - - g_free (uri); -} - -static void -store_row_deleted (GeditFileBrowserStore *store, - GtkTreePath *path, - MessageCacheData *data) -{ - GtkTreeIter iter; - gchar *uri = NULL; - guint flags = 0; - - if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) - return; - - gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags)) - { - WindowData *wdata = get_window_data (data->window); - - set_item_message (wdata, &iter, path, data->message); - gedit_message_bus_send_message_sync (wdata->bus, data->message); - } - - g_free (uri); -} - -static void -store_virtual_root_changed (GeditFileBrowserStore *store, - GParamSpec *spec, - MessageCacheData *data) -{ - WindowData *wdata = get_window_data (data->window); - gchar *uri; - - uri = gedit_file_browser_store_get_virtual_root (store); - - if (!uri) - return; - - gedit_message_set (data->message, - "uri", uri, - NULL); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - - g_free (uri); -} - -static void -store_begin_loading (GeditFileBrowserStore *store, - GtkTreeIter *iter, - MessageCacheData *data) -{ - GtkTreePath *path; - WindowData *wdata = get_window_data (data->window); - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); - - set_item_message (wdata, iter, path, data->message); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - gtk_tree_path_free (path); -} - -static void -store_end_loading (GeditFileBrowserStore *store, - GtkTreeIter *iter, - MessageCacheData *data) -{ - GtkTreePath *path; - WindowData *wdata = get_window_data (data->window); - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); - - set_item_message (wdata, iter, path, data->message); - - gedit_message_bus_send_message_sync (wdata->bus, data->message); - gtk_tree_path_free (path); -} - -static void -register_signals (GeditWindow *window, - GeditFileBrowserWidget *widget) -{ - GeditMessageBus *bus = gedit_window_get_message_bus (window); - GeditFileBrowserStore *store; - GeditMessageType *inserted_type; - GeditMessageType *deleted_type; - GeditMessageType *begin_loading_type; - GeditMessageType *end_loading_type; - GeditMessageType *root_changed_type; - - GeditMessage *message; - WindowData *data; - - /* Register signals */ - root_changed_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "root_changed", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - begin_loading_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "begin_loading", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - end_loading_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "end_loading", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - NULL); - - inserted_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "inserted", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - "is_directory", G_TYPE_BOOLEAN, - NULL); - - deleted_type = gedit_message_bus_register (bus, - MESSAGE_OBJECT_PATH, "deleted", - 0, - "id", G_TYPE_STRING, - "uri", G_TYPE_STRING, - "is_directory", G_TYPE_BOOLEAN, - NULL); - - store = gedit_file_browser_widget_get_browser_store (widget); - - message = gedit_message_type_instantiate (inserted_type, - "id", NULL, - "uri", NULL, - "is_directory", FALSE, - NULL); - - data = get_window_data (window); - - data->row_inserted_id = - g_signal_connect_data (store, - "row-inserted", - G_CALLBACK (store_row_inserted), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); - - message = gedit_message_type_instantiate (deleted_type, - "id", NULL, - "uri", NULL, - "is_directory", FALSE, - NULL); - data->row_deleted_id = - g_signal_connect_data (store, - "row-deleted", - G_CALLBACK (store_row_deleted), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); - - message = gedit_message_type_instantiate (root_changed_type, - "id", NULL, - "uri", NULL, - NULL); - data->root_changed_id = - g_signal_connect_data (store, - "notify::virtual-root", - G_CALLBACK (store_virtual_root_changed), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); - - message = gedit_message_type_instantiate (begin_loading_type, - "id", NULL, - "uri", NULL, - NULL); - data->begin_loading_id = - g_signal_connect_data (store, - "begin_loading", - G_CALLBACK (store_begin_loading), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); - - message = gedit_message_type_instantiate (end_loading_type, - "id", NULL, - "uri", NULL, - NULL); - data->end_loading_id = - g_signal_connect_data (store, - "end_loading", - G_CALLBACK (store_end_loading), - message_cache_data_new (window, message), - (GClosureNotify)message_cache_data_free, - 0); -} - -static void -message_unregistered (GeditMessageBus *bus, - GeditMessageType *message_type, - GeditWindow *window) -{ - gchar *identifier = gedit_message_type_identifier (gedit_message_type_get_object_path (message_type), - gedit_message_type_get_method (message_type)); - FilterData *data; - WindowData *wdata = get_window_data (window); - - data = g_hash_table_lookup (wdata->filters, identifier); - - if (data) - gedit_file_browser_widget_remove_filter (wdata->widget, data->id); - - g_free (identifier); -} - -void -gedit_file_browser_messages_register (GeditWindow *window, - GeditFileBrowserWidget *widget) -{ - window_data_new (window, widget); - - register_methods (window, widget); - register_signals (window, widget); - - g_signal_connect (gedit_window_get_message_bus (window), - "unregistered", - G_CALLBACK (message_unregistered), - window); -} - -static void -cleanup_signals (GeditWindow *window) -{ - WindowData *data = get_window_data (window); - GeditFileBrowserStore *store; - - store = gedit_file_browser_widget_get_browser_store (data->widget); - - g_signal_handler_disconnect (store, data->row_inserted_id); - g_signal_handler_disconnect (store, data->row_deleted_id); - g_signal_handler_disconnect (store, data->root_changed_id); - g_signal_handler_disconnect (store, data->begin_loading_id); - g_signal_handler_disconnect (store, data->end_loading_id); - - g_signal_handlers_disconnect_by_func (data->bus, message_unregistered, window); -} - -void -gedit_file_browser_messages_unregister (GeditWindow *window) -{ - GeditMessageBus *bus = gedit_window_get_message_bus (window); - - cleanup_signals (window); - gedit_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH); - - window_data_free (window); -} diff --git a/plugins/filebrowser/gedit-file-browser-messages.h b/plugins/filebrowser/gedit-file-browser-messages.h deleted file mode 100755 index e62094e8..00000000 --- a/plugins/filebrowser/gedit-file-browser-messages.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * gedit-file-browser-messages.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2008 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_MESSAGES_H__ -#define __GEDIT_FILE_BROWSER_MESSAGES_H__ - -#include -#include -#include "gedit-file-browser-widget.h" - -void gedit_file_browser_messages_register (GeditWindow *window, - GeditFileBrowserWidget *widget); -void gedit_file_browser_messages_unregister (GeditWindow *window); - -#endif /* __GEDIT_FILE_BROWSER_MESSAGES_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-plugin.c b/plugins/filebrowser/gedit-file-browser-plugin.c deleted file mode 100755 index f2da19f5..00000000 --- a/plugins/filebrowser/gedit-file-browser-plugin.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* - * gedit-file-browser-plugin.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "gedit-file-browser-enum-types.h" -#include "gedit-file-browser-plugin.h" -#include "gedit-file-browser-utils.h" -#include "gedit-file-browser-error.h" -#include "gedit-file-browser-widget.h" -#include "gedit-file-browser-messages.h" - -#define WINDOW_DATA_KEY "GeditFileBrowserPluginWindowData" -#define FILE_BROWSER_BASE_KEY "/apps/gedit-2/plugins/filebrowser" -#define CAJA_CLICK_POLICY_BASE_KEY "/apps/caja/preferences" -#define CAJA_CLICK_POLICY_KEY "click_policy" -#define CAJA_ENABLE_DELETE_KEY "enable_delete" -#define CAJA_CONFIRM_TRASH_KEY "confirm_trash" -#define TERMINAL_EXEC_KEY "/desktop/mate/applications/terminal/exec" - -#define GEDIT_FILE_BROWSER_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginPrivate)) - -struct _GeditFileBrowserPluginPrivate -{ - gpointer dummy; -}; - -typedef struct _GeditFileBrowserPluginData -{ - GeditFileBrowserWidget * tree_widget; - gulong merge_id; - GtkActionGroup * action_group; - GtkActionGroup * single_selection_action_group; - gboolean auto_root; - gulong end_loading_handle; - gboolean confirm_trash; - - guint click_policy_handle; - guint enable_delete_handle; - guint confirm_trash_handle; -} GeditFileBrowserPluginData; - -static void on_uri_activated_cb (GeditFileBrowserWidget * widget, - gchar const *uri, - GeditWindow * window); -static void on_error_cb (GeditFileBrowserWidget * widget, - guint code, - gchar const *message, - GeditWindow * window); -static void on_model_set_cb (GeditFileBrowserView * widget, - GParamSpec *arg1, - GeditWindow * window); -static void on_virtual_root_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window); -static void on_filter_mode_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window); -static void on_rename_cb (GeditFileBrowserStore * model, - const gchar * olduri, - const gchar * newuri, - GeditWindow * window); -static void on_filter_pattern_changed_cb (GeditFileBrowserWidget * widget, - GParamSpec * param, - GeditWindow * window); -static void on_tab_added_cb (GeditWindow * window, - GeditTab * tab, - GeditFileBrowserPluginData * data); -static gboolean on_confirm_delete_cb (GeditFileBrowserWidget * widget, - GeditFileBrowserStore * store, - GList * rows, - GeditWindow * window); -static gboolean on_confirm_no_trash_cb (GeditFileBrowserWidget * widget, - GList * files, - GeditWindow * window); - -GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE (GeditFileBrowserPlugin, filetree_plugin, \ - gedit_file_browser_enum_and_flag_register_type (type_module); \ - gedit_file_browser_store_register_type (type_module); \ - gedit_file_bookmarks_store_register_type (type_module); \ - gedit_file_browser_view_register_type (type_module); \ - gedit_file_browser_widget_register_type (type_module); \ -) - - -static void -filetree_plugin_init (GeditFileBrowserPlugin * plugin) -{ - plugin->priv = GEDIT_FILE_BROWSER_PLUGIN_GET_PRIVATE (plugin); -} - -static void -filetree_plugin_finalize (GObject * object) -{ - //GeditFileBrowserPlugin * plugin = GEDIT_FILE_BROWSER_PLUGIN (object); - - G_OBJECT_CLASS (filetree_plugin_parent_class)->finalize (object); -} - -static GeditFileBrowserPluginData * -get_plugin_data (GeditWindow * window) -{ - return (GeditFileBrowserPluginData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); -} - -static void -on_end_loading_cb (GeditFileBrowserStore * store, - GtkTreeIter * iter, - GeditFileBrowserPluginData * data) -{ - /* Disconnect the signal */ - g_signal_handler_disconnect (store, data->end_loading_handle); - data->end_loading_handle = 0; - data->auto_root = FALSE; -} - -static void -prepare_auto_root (GeditFileBrowserPluginData *data) -{ - GeditFileBrowserStore *store; - - data->auto_root = TRUE; - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - - if (data->end_loading_handle != 0) { - g_signal_handler_disconnect (store, data->end_loading_handle); - data->end_loading_handle = 0; - } - - data->end_loading_handle = g_signal_connect (store, - "end-loading", - G_CALLBACK (on_end_loading_cb), - data); -} - -static void -restore_default_location (GeditFileBrowserPluginData *data) -{ - gchar * root; - gchar * virtual_root; - gboolean bookmarks; - gboolean remote; - MateConfClient * client; - - client = mateconf_client_get_default (); - if (!client) - return; - - bookmarks = !mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/tree_view", - NULL); - - if (bookmarks) { - g_object_unref (client); - gedit_file_browser_widget_show_bookmarks (data->tree_widget); - return; - } - - root = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/on_load/root", - NULL); - virtual_root = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - NULL); - - remote = mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/enable_remote", - NULL); - - if (root != NULL && *root != '\0') { - GFile *file; - - file = g_file_new_for_uri (root); - - if (remote || g_file_is_native (file)) { - if (virtual_root != NULL && *virtual_root != '\0') { - prepare_auto_root (data); - gedit_file_browser_widget_set_root_and_virtual_root (data->tree_widget, - root, - virtual_root); - } else { - prepare_auto_root (data); - gedit_file_browser_widget_set_root (data->tree_widget, - root, - TRUE); - } - } - - g_object_unref (file); - } - - g_object_unref (client); - g_free (root); - g_free (virtual_root); -} - -static void -restore_filter (GeditFileBrowserPluginData * data) -{ - MateConfClient * client; - gchar *filter_mode; - GeditFileBrowserStoreFilterMode mode; - gchar *pattern; - - client = mateconf_client_get_default (); - if (!client) - return; - - /* Get filter_mode */ - filter_mode = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - NULL); - - /* Filter mode */ - mode = gedit_file_browser_store_filter_mode_get_default (); - - if (filter_mode != NULL) { - if (strcmp (filter_mode, "hidden") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; - } else if (strcmp (filter_mode, "binary") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - } else if (strcmp (filter_mode, "hidden_and_binary") == 0 || - strcmp (filter_mode, "binary_and_hidden") == 0) { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN | - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; - } else if (strcmp (filter_mode, "none") == 0 || - *filter_mode == '\0') { - mode = GEDIT_FILE_BROWSER_STORE_FILTER_MODE_NONE; - } - } - - /* Set the filter mode */ - gedit_file_browser_store_set_filter_mode ( - gedit_file_browser_widget_get_browser_store (data->tree_widget), - mode); - - pattern = mateconf_client_get_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - NULL); - - gedit_file_browser_widget_set_filter_pattern (data->tree_widget, - pattern); - - g_object_unref (client); - g_free (filter_mode); - g_free (pattern); -} - -static GeditFileBrowserViewClickPolicy -click_policy_from_string (gchar const *click_policy) -{ - if (click_policy && strcmp (click_policy, "single") == 0) - return GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; - else - return GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; -} - -static void -on_click_policy_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData * data; - gchar const *click_policy; - GeditFileBrowserViewClickPolicy policy = GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; - GeditFileBrowserView *view; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_STRING) { - click_policy = mateconf_value_get_string (value); - - policy = click_policy_from_string (click_policy); - } - - view = gedit_file_browser_widget_get_browser_view (data->tree_widget); - gedit_file_browser_view_set_click_policy (view, policy); -} - -static void -on_enable_delete_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData *data; - gboolean enable = FALSE; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_BOOL) - enable = mateconf_value_get_bool (value); - - g_object_set (G_OBJECT (data->tree_widget), "enable-delete", enable, NULL); -} - -static void -on_confirm_trash_changed (MateConfClient *client, - guint cnxn_id, - MateConfEntry *entry, - gpointer user_data) -{ - MateConfValue *value; - GeditFileBrowserPluginData *data; - gboolean enable = FALSE; - - data = (GeditFileBrowserPluginData *)(user_data); - value = mateconf_entry_get_value (entry); - - if (value && value->type == MATECONF_VALUE_BOOL) - enable = mateconf_value_get_bool (value); - - data->confirm_trash = enable; -} - -static void -install_caja_prefs (GeditFileBrowserPluginData *data) -{ - MateConfClient *client; - gchar *pref; - gboolean prefb; - GeditFileBrowserViewClickPolicy policy; - GeditFileBrowserView *view; - - client = mateconf_client_get_default (); - if (!client) - return; - - mateconf_client_add_dir (client, - CAJA_CLICK_POLICY_BASE_KEY, - MATECONF_CLIENT_PRELOAD_NONE, - NULL); - - /* Get click_policy */ - pref = mateconf_client_get_string (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, - NULL); - - policy = click_policy_from_string (pref); - - view = gedit_file_browser_widget_get_browser_view (data->tree_widget); - gedit_file_browser_view_set_click_policy (view, policy); - - if (pref) { - data->click_policy_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, - on_click_policy_changed, - data, - NULL, - NULL); - g_free (pref); - } - - /* Get enable_delete */ - prefb = mateconf_client_get_bool (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, - NULL); - - g_object_set (G_OBJECT (data->tree_widget), "enable-delete", prefb, NULL); - - data->enable_delete_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, - on_enable_delete_changed, - data, - NULL, - NULL); - - /* Get confirm_trash */ - prefb = mateconf_client_get_bool (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, - NULL); - - data->confirm_trash = prefb; - - data->confirm_trash_handle = - mateconf_client_notify_add (client, - CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, - on_confirm_trash_changed, - data, - NULL, - NULL); - g_object_unref (client); -} - -static void -set_root_from_doc (GeditFileBrowserPluginData * data, - GeditDocument * doc) -{ - GFile *file; - GFile *parent; - - if (doc == NULL) - return; - - file = gedit_document_get_location (doc); - if (file == NULL) - return; - - parent = g_file_get_parent (file); - - if (parent != NULL) { - gchar * root; - - root = g_file_get_uri (parent); - - gedit_file_browser_widget_set_root (data->tree_widget, - root, - TRUE); - - g_object_unref (parent); - g_free (root); - } - - g_object_unref (file); -} - -static void -on_action_set_active_root (GtkAction * action, - GeditWindow * window) -{ - GeditFileBrowserPluginData *data; - - data = get_plugin_data (window); - set_root_from_doc (data, - gedit_window_get_active_document (window)); -} - -static gchar * -get_terminal (void) -{ - MateConfClient * client; - gchar * terminal; - - client = mateconf_client_get_default (); - terminal = mateconf_client_get_string (client, - TERMINAL_EXEC_KEY, - NULL); - g_object_unref (client); - - if (terminal == NULL) { - const gchar *term = g_getenv ("TERM"); - - if (term != NULL) - terminal = g_strdup (term); - else - terminal = g_strdup ("xterm"); - } - - return terminal; -} - -static void -on_action_open_terminal (GtkAction * action, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - gchar * terminal; - gchar * wd = NULL; - gchar * local; - gchar * argv[2]; - GFile * file; - - GtkTreeIter iter; - GeditFileBrowserStore * store; - - data = get_plugin_data (window); - - /* Get the current directory */ - if (!gedit_file_browser_widget_get_selected_directory (data->tree_widget, &iter)) - return; - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - gtk_tree_model_get (GTK_TREE_MODEL (store), - &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &wd, - -1); - - if (wd == NULL) - return; - - terminal = get_terminal (); - - file = g_file_new_for_uri (wd); - local = g_file_get_path (file); - g_object_unref (file); - - argv[0] = terminal; - argv[1] = NULL; - - g_spawn_async (local, - argv, - NULL, - G_SPAWN_SEARCH_PATH, - NULL, - NULL, - NULL, - NULL); - - g_free (terminal); - g_free (wd); - g_free (local); -} - -static void -on_selection_changed_cb (GtkTreeSelection *selection, - GeditWindow *window) -{ - GeditFileBrowserPluginData * data; - GtkTreeView * tree_view; - GtkTreeModel * model; - GtkTreeIter iter; - gboolean sensitive; - gchar * uri; - - data = get_plugin_data (window); - - tree_view = GTK_TREE_VIEW (gedit_file_browser_widget_get_browser_view (data->tree_widget)); - model = gtk_tree_view_get_model (tree_view); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - sensitive = gedit_file_browser_widget_get_selected_directory (data->tree_widget, &iter); - - if (sensitive) { - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, -1); - - sensitive = gedit_utils_uri_has_file_scheme (uri); - g_free (uri); - } - - gtk_action_set_sensitive ( - gtk_action_group_get_action (data->single_selection_action_group, - "OpenTerminal"), - sensitive); -} - -#define POPUP_UI "" \ -"" \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -" " \ -"" - -static GtkActionEntry extra_actions[] = -{ - {"SetActiveRoot", GTK_STOCK_JUMP_TO, N_("_Set root to active document"), - NULL, - N_("Set the root to the active document location"), - G_CALLBACK (on_action_set_active_root)} -}; - -static GtkActionEntry extra_single_selection_actions[] = { - {"OpenTerminal", "utilities-terminal", N_("_Open terminal here"), - NULL, - N_("Open a terminal at the currently opened directory"), - G_CALLBACK (on_action_open_terminal)} -}; - -static void -add_popup_ui (GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GtkUIManager * manager; - GtkActionGroup * action_group; - GError * error = NULL; - - data = get_plugin_data (window); - manager = gedit_file_browser_widget_get_ui_manager (data->tree_widget); - - action_group = gtk_action_group_new ("FileBrowserPluginExtra"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - extra_actions, - G_N_ELEMENTS (extra_actions), - window); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - data->action_group = action_group; - - action_group = gtk_action_group_new ("FileBrowserPluginSingleSelectionExtra"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - extra_single_selection_actions, - G_N_ELEMENTS (extra_single_selection_actions), - window); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - data->single_selection_action_group = action_group; - - data->merge_id = gtk_ui_manager_add_ui_from_string (manager, - POPUP_UI, - -1, - &error); - - if (data->merge_id == 0) { - g_warning("Unable to merge UI: %s", error->message); - g_error_free(error); - } -} - -static void -remove_popup_ui (GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GtkUIManager * manager; - - data = get_plugin_data (window); - manager = gedit_file_browser_widget_get_ui_manager (data->tree_widget); - gtk_ui_manager_remove_ui (manager, data->merge_id); - - gtk_ui_manager_remove_action_group (manager, data->action_group); - g_object_unref (data->action_group); - - gtk_ui_manager_remove_action_group (manager, data->single_selection_action_group); - g_object_unref (data->single_selection_action_group); -} - -static void -impl_updateui (GeditPlugin * plugin, GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GeditDocument * doc; - - data = get_plugin_data (window); - - doc = gedit_window_get_active_document (window); - - gtk_action_set_sensitive (gtk_action_group_get_action (data->action_group, - "SetActiveRoot"), - doc != NULL && - !gedit_document_is_untitled (doc)); -} - -static void -impl_activate (GeditPlugin * plugin, GeditWindow * window) -{ - GeditPanel * panel; - GeditFileBrowserPluginData * data; - GtkWidget * image; - GdkPixbuf * pixbuf; - GeditFileBrowserStore * store; - gchar *data_dir; - - data = g_new0 (GeditFileBrowserPluginData, 1); - - data_dir = gedit_plugin_get_data_dir (plugin); - data->tree_widget = GEDIT_FILE_BROWSER_WIDGET (gedit_file_browser_widget_new (data_dir)); - g_free (data_dir); - - g_signal_connect (data->tree_widget, - "uri-activated", - G_CALLBACK (on_uri_activated_cb), window); - - g_signal_connect (data->tree_widget, - "error", G_CALLBACK (on_error_cb), window); - - g_signal_connect (data->tree_widget, - "notify::filter-pattern", - G_CALLBACK (on_filter_pattern_changed_cb), - window); - - g_signal_connect (data->tree_widget, - "confirm-delete", - G_CALLBACK (on_confirm_delete_cb), - window); - - g_signal_connect (data->tree_widget, - "confirm-no-trash", - G_CALLBACK (on_confirm_no_trash_cb), - window); - - g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW - (gedit_file_browser_widget_get_browser_view - (data->tree_widget))), - "changed", - G_CALLBACK (on_selection_changed_cb), - window); - - panel = gedit_window_get_side_panel (window); - pixbuf = gedit_file_browser_utils_pixbuf_from_theme("system-file-manager", - GTK_ICON_SIZE_MENU); - - if (pixbuf) { - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - } else { - image = gtk_image_new_from_stock(GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU); - } - - gtk_widget_show(image); - gedit_panel_add_item (panel, - GTK_WIDGET (data->tree_widget), - _("File Browser"), - image); - gtk_widget_show (GTK_WIDGET (data->tree_widget)); - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); - - add_popup_ui (window); - - /* Restore filter options */ - restore_filter (data); - - /* Install caja preferences */ - install_caja_prefs (data); - - /* Connect signals to store the last visited location */ - g_signal_connect (gedit_file_browser_widget_get_browser_view (data->tree_widget), - "notify::model", - G_CALLBACK (on_model_set_cb), - window); - - store = gedit_file_browser_widget_get_browser_store (data->tree_widget); - g_signal_connect (store, - "notify::virtual-root", - G_CALLBACK (on_virtual_root_changed_cb), - window); - - g_signal_connect (store, - "notify::filter-mode", - G_CALLBACK (on_filter_mode_changed_cb), - window); - - g_signal_connect (store, - "rename", - G_CALLBACK (on_rename_cb), - window); - - g_signal_connect (window, - "tab-added", - G_CALLBACK (on_tab_added_cb), - data); - - /* Register messages on the bus */ - gedit_file_browser_messages_register (window, data->tree_widget); - - impl_updateui (plugin, window); -} - -static void -impl_deactivate (GeditPlugin * plugin, GeditWindow * window) -{ - GeditFileBrowserPluginData * data; - GeditPanel * panel; - MateConfClient *client; - - data = get_plugin_data (window); - - /* Unregister messages from the bus */ - gedit_file_browser_messages_unregister (window); - - /* Disconnect signals */ - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); - - client = mateconf_client_get_default (); - mateconf_client_remove_dir (client, CAJA_CLICK_POLICY_BASE_KEY, NULL); - - if (data->click_policy_handle) - mateconf_client_notify_remove (client, data->click_policy_handle); - - if (data->enable_delete_handle) - mateconf_client_notify_remove (client, data->enable_delete_handle); - - if (data->confirm_trash_handle) - mateconf_client_notify_remove (client, data->confirm_trash_handle); - - g_object_unref (client); - remove_popup_ui (window); - - panel = gedit_window_get_side_panel (window); - gedit_panel_remove_item (panel, GTK_WIDGET (data->tree_widget)); - - g_free (data); - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -filetree_plugin_class_init (GeditFileBrowserPluginClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass * plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = filetree_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_updateui; - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserPluginPrivate)); -} - -/* Callbacks */ -static void -on_uri_activated_cb (GeditFileBrowserWidget * tree_widget, - gchar const *uri, GeditWindow * window) -{ - gedit_commands_load_uri (window, uri, NULL, 0); -} - -static void -on_error_cb (GeditFileBrowserWidget * tree_widget, - guint code, gchar const *message, GeditWindow * window) -{ - gchar * title; - GtkWidget * dlg; - GeditFileBrowserPluginData * data; - - data = get_plugin_data (window); - - /* Do not show the error when the root has been set automatically */ - if (data->auto_root && (code == GEDIT_FILE_BROWSER_ERROR_SET_ROOT || - code == GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY)) - { - /* Show bookmarks */ - gedit_file_browser_widget_show_bookmarks (data->tree_widget); - return; - } - - switch (code) { - case GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY: - title = - _("An error occurred while creating a new directory"); - break; - case GEDIT_FILE_BROWSER_ERROR_NEW_FILE: - title = _("An error occurred while creating a new file"); - break; - case GEDIT_FILE_BROWSER_ERROR_RENAME: - title = - _ - ("An error occurred while renaming a file or directory"); - break; - case GEDIT_FILE_BROWSER_ERROR_DELETE: - title = - _ - ("An error occurred while deleting a file or directory"); - break; - case GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY: - title = - _ - ("An error occurred while opening a directory in the file manager"); - break; - case GEDIT_FILE_BROWSER_ERROR_SET_ROOT: - title = - _("An error occurred while setting a root directory"); - break; - case GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY: - title = - _("An error occurred while loading a directory"); - break; - default: - title = _("An error occurred"); - break; - } - - dlg = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, - "%s", title); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", message); - - gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); -} - -static void -on_model_set_cb (GeditFileBrowserView * widget, - GParamSpec *arg1, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data = get_plugin_data (window); - GtkTreeModel * model; - MateConfClient * client; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (gedit_file_browser_widget_get_browser_view (data->tree_widget))); - - if (model == NULL) - return; - - client = mateconf_client_get_default (); - mateconf_client_set_bool (client, - FILE_BROWSER_BASE_KEY "/on_load/tree_view", - GEDIT_IS_FILE_BROWSER_STORE (model), - NULL); - g_object_unref (client); -} - -static void -on_filter_mode_changed_cb (GeditFileBrowserStore * model, - GParamSpec * param, - GeditWindow * window) -{ - MateConfClient * client; - GeditFileBrowserStoreFilterMode mode; - - client = mateconf_client_get_default (); - - if (!client) - return; - - mode = gedit_file_browser_store_get_filter_mode (model); - - if ((mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) && - (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY)) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "hidden_and_binary", - NULL); - } else if (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "hidden", - NULL); - } else if (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "binary", - NULL); - } else { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_mode", - "none", - NULL); - } - - g_object_unref (client); - -} - -static void -on_rename_cb (GeditFileBrowserStore * store, - const gchar * olduri, - const gchar * newuri, - GeditWindow * window) -{ - GeditApp * app; - GList * documents; - GList * item; - GeditDocument * doc; - GFile * docfile; - GFile * oldfile; - GFile * newfile; - gchar * uri; - - /* Find all documents and set its uri to newuri where it matches olduri */ - app = gedit_app_get_default (); - documents = gedit_app_get_documents (app); - - oldfile = g_file_new_for_uri (olduri); - newfile = g_file_new_for_uri (newuri); - - for (item = documents; item; item = item->next) { - doc = GEDIT_DOCUMENT (item->data); - uri = gedit_document_get_uri (doc); - - if (!uri) - continue; - - docfile = g_file_new_for_uri (uri); - - if (g_file_equal (docfile, oldfile)) { - gedit_document_set_uri (doc, newuri); - } else { - gchar *relative; - - relative = g_file_get_relative_path (oldfile, docfile); - - if (relative) { - /* relative now contains the part in docfile without - the prefix oldfile */ - - g_object_unref (docfile); - g_free (uri); - - docfile = g_file_get_child (newfile, relative); - uri = g_file_get_uri (docfile); - - gedit_document_set_uri (doc, uri); - } - - g_free (relative); - } - - g_free (uri); - g_object_unref (docfile); - } - - g_object_unref (oldfile); - g_object_unref (newfile); - - g_list_free (documents); -} - -static void -on_filter_pattern_changed_cb (GeditFileBrowserWidget * widget, - GParamSpec * param, - GeditWindow * window) -{ - MateConfClient * client; - gchar * pattern; - - client = mateconf_client_get_default (); - - if (!client) - return; - - g_object_get (G_OBJECT (widget), "filter-pattern", &pattern, NULL); - - if (pattern == NULL) - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - "", - NULL); - else - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/filter_pattern", - pattern, - NULL); - - g_free (pattern); -} - -static void -on_virtual_root_changed_cb (GeditFileBrowserStore * store, - GParamSpec * param, - GeditWindow * window) -{ - GeditFileBrowserPluginData * data = get_plugin_data (window); - gchar * root; - gchar * virtual_root; - MateConfClient * client; - - root = gedit_file_browser_store_get_root (store); - - if (!root) - return; - - client = mateconf_client_get_default (); - - if (!client) - return; - - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/root", - root, - NULL); - - virtual_root = gedit_file_browser_store_get_virtual_root (store); - - if (!virtual_root) { - /* Set virtual to same as root then */ - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - root, - NULL); - } else { - mateconf_client_set_string (client, - FILE_BROWSER_BASE_KEY "/on_load/virtual_root", - virtual_root, - NULL); - } - - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); - - g_object_unref (client); - g_free (root); - g_free (virtual_root); -} - -static void -on_tab_added_cb (GeditWindow * window, - GeditTab * tab, - GeditFileBrowserPluginData * data) -{ - MateConfClient *client; - gboolean open; - gboolean load_default = TRUE; - - client = mateconf_client_get_default (); - - if (!client) - return; - - open = mateconf_client_get_bool (client, - FILE_BROWSER_BASE_KEY "/open_at_first_doc", - NULL); - - if (open) { - GeditDocument *doc; - gchar *uri; - - doc = gedit_tab_get_document (tab); - - uri = gedit_document_get_uri (doc); - - if (uri != NULL && gedit_utils_uri_has_file_scheme (uri)) { - prepare_auto_root (data); - set_root_from_doc (data, doc); - load_default = FALSE; - } - - g_free (uri); - } - - if (load_default) - restore_default_location (data); - - g_object_unref (client); - - /* Disconnect this signal, it's only called once */ - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_tab_added_cb), - data); -} - -static gchar * -get_filename_from_path (GtkTreeModel *model, GtkTreePath *path) -{ - GtkTreeIter iter; - gchar *uri; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - return gedit_file_browser_utils_uri_basename (uri); -} - -static gboolean -on_confirm_no_trash_cb (GeditFileBrowserWidget * widget, - GList * files, - GeditWindow * window) -{ - gchar *normal; - gchar *message; - gchar *secondary; - gboolean result; - - message = _("Cannot move file to trash, do you\nwant to delete permanently?"); - - if (files->next == NULL) { - normal = gedit_file_browser_utils_file_basename (G_FILE (files->data)); - secondary = g_strdup_printf (_("The file \"%s\" cannot be moved to the trash."), normal); - g_free (normal); - } else { - secondary = g_strdup (_("The selected files cannot be moved to the trash.")); - } - - result = gedit_file_browser_utils_confirmation_dialog (window, - GTK_MESSAGE_QUESTION, - message, - secondary, - GTK_STOCK_DELETE, - NULL); - g_free (secondary); - - return result; -} - -static gboolean -on_confirm_delete_cb (GeditFileBrowserWidget *widget, - GeditFileBrowserStore *store, - GList *paths, - GeditWindow *window) -{ - gchar *normal; - gchar *message; - gchar *secondary; - gboolean result; - GeditFileBrowserPluginData *data; - - data = get_plugin_data (window); - - if (!data->confirm_trash) - return TRUE; - - if (paths->next == NULL) { - normal = get_filename_from_path (GTK_TREE_MODEL (store), (GtkTreePath *)(paths->data)); - message = g_strdup_printf (_("Are you sure you want to permanently delete \"%s\"?"), normal); - g_free (normal); - } else { - message = g_strdup (_("Are you sure you want to permanently delete the selected files?")); - } - - secondary = _("If you delete an item, it is permanently lost."); - - result = gedit_file_browser_utils_confirmation_dialog (window, - GTK_MESSAGE_QUESTION, - message, - secondary, - GTK_STOCK_DELETE, - NULL); - - g_free (message); - - return result; -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-plugin.h b/plugins/filebrowser/gedit-file-browser-plugin.h deleted file mode 100755 index 19ca86bf..00000000 --- a/plugins/filebrowser/gedit-file-browser-plugin.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * gedit-file-browser-plugin.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_PLUGIN_H__ -#define __GEDIT_FILE_BROWSER_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_FILE_BROWSER_PLUGIN (filetree_plugin_get_type ()) -#define GEDIT_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPlugin)) -#define GEDIT_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginClass)) -#define GEDIT_IS_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN)) -#define GEDIT_IS_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_FILE_BROWSER_PLUGIN)) -#define GEDIT_FILE_BROWSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_FILE_BROWSER_PLUGIN, GeditFileBrowserPluginClass)) - -/* Private structure type */ -typedef struct _GeditFileBrowserPluginPrivate GeditFileBrowserPluginPrivate; -typedef struct _GeditFileBrowserPlugin GeditFileBrowserPlugin; -typedef struct _GeditFileBrowserPluginClass GeditFileBrowserPluginClass; - -struct _GeditFileBrowserPlugin -{ - GeditPlugin parent_instance; - - /*< private > */ - GeditFileBrowserPluginPrivate *priv; -}; - - - -struct _GeditFileBrowserPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType filetree_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule * module); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_PLUGIN_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-store.c b/plugins/filebrowser/gedit-file-browser-store.c deleted file mode 100755 index 6c4f5b51..00000000 --- a/plugins/filebrowser/gedit-file-browser-store.c +++ /dev/null @@ -1,3625 +0,0 @@ -/* - * gedit-file-browser-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "gedit-file-browser-store.h" -#include "gedit-file-browser-marshal.h" -#include "gedit-file-browser-enum-types.h" -#include "gedit-file-browser-error.h" -#include "gedit-file-browser-utils.h" - -#define GEDIT_FILE_BROWSER_STORE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_STORE, \ - GeditFileBrowserStorePrivate)) - -#define NODE_IS_DIR(node) (FILE_IS_DIR((node)->flags)) -#define NODE_IS_HIDDEN(node) (FILE_IS_HIDDEN((node)->flags)) -#define NODE_IS_TEXT(node) (FILE_IS_TEXT((node)->flags)) -#define NODE_LOADED(node) (FILE_LOADED((node)->flags)) -#define NODE_IS_FILTERED(node) (FILE_IS_FILTERED((node)->flags)) -#define NODE_IS_DUMMY(node) (FILE_IS_DUMMY((node)->flags)) - -#define FILE_BROWSER_NODE_DIR(node) ((FileBrowserNodeDir *)(node)) - -#define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100 -#define STANDARD_ATTRIBUTE_TYPES G_FILE_ATTRIBUTE_STANDARD_TYPE "," \ - G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," \ - G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP "," \ - G_FILE_ATTRIBUTE_STANDARD_NAME "," \ - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \ - G_FILE_ATTRIBUTE_STANDARD_ICON - -typedef struct _FileBrowserNode FileBrowserNode; -typedef struct _FileBrowserNodeDir FileBrowserNodeDir; -typedef struct _AsyncData AsyncData; -typedef struct _AsyncNode AsyncNode; - -typedef gint (*SortFunc) (FileBrowserNode * node1, - FileBrowserNode * node2); - -struct _AsyncData -{ - GeditFileBrowserStore * model; - GCancellable * cancellable; - gboolean trash; - GList * files; - GList * iter; - gboolean removed; -}; - -struct _AsyncNode -{ - FileBrowserNodeDir *dir; - GCancellable *cancellable; - GSList *original_children; -}; - -typedef struct { - GeditFileBrowserStore * model; - gchar * virtual_root; - GMountOperation * operation; - GCancellable * cancellable; -} MountInfo; - -struct _FileBrowserNode -{ - GFile *file; - guint flags; - gchar *name; - - GdkPixbuf *icon; - GdkPixbuf *emblem; - - FileBrowserNode *parent; - gint pos; - gboolean inserted; -}; - -struct _FileBrowserNodeDir -{ - FileBrowserNode node; - GSList *children; - GHashTable *hidden_file_hash; - - GCancellable *cancellable; - GFileMonitor *monitor; - GeditFileBrowserStore *model; -}; - -struct _GeditFileBrowserStorePrivate -{ - FileBrowserNode *root; - FileBrowserNode *virtual_root; - GType column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_NUM]; - - GeditFileBrowserStoreFilterMode filter_mode; - GeditFileBrowserStoreFilterFunc filter_func; - gpointer filter_user_data; - - SortFunc sort_func; - - GSList *async_handles; - MountInfo *mount_info; -}; - -static FileBrowserNode *model_find_node (GeditFileBrowserStore *model, - FileBrowserNode *node, - GFile *uri); -static void model_remove_node (GeditFileBrowserStore * model, - FileBrowserNode * node, - GtkTreePath * path, - gboolean free_nodes); - -static void set_virtual_root_from_node (GeditFileBrowserStore * model, - FileBrowserNode * node); - -static void gedit_file_browser_store_iface_init (GtkTreeModelIface * iface); -static GtkTreeModelFlags gedit_file_browser_store_get_flags (GtkTreeModel * tree_model); -static gint gedit_file_browser_store_get_n_columns (GtkTreeModel * tree_model); -static GType gedit_file_browser_store_get_column_type (GtkTreeModel * tree_model, - gint index); -static gboolean gedit_file_browser_store_get_iter (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreePath * path); -static GtkTreePath *gedit_file_browser_store_get_path (GtkTreeModel * tree_model, - GtkTreeIter * iter); -static void gedit_file_browser_store_get_value (GtkTreeModel * tree_model, - GtkTreeIter * iter, - gint column, - GValue * value); -static gboolean gedit_file_browser_store_iter_next (GtkTreeModel * tree_model, - GtkTreeIter * iter); -static gboolean gedit_file_browser_store_iter_children (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * parent); -static gboolean gedit_file_browser_store_iter_has_child (GtkTreeModel * tree_model, - GtkTreeIter * iter); -static gint gedit_file_browser_store_iter_n_children (GtkTreeModel * tree_model, - GtkTreeIter * iter); -static gboolean gedit_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * parent, - gint n); -static gboolean gedit_file_browser_store_iter_parent (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * child); -static void gedit_file_browser_store_row_inserted (GtkTreeModel * tree_model, - GtkTreePath * path, - GtkTreeIter * iter); - -static void gedit_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface); -static gboolean gedit_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, - GtkTreePath * path); -static gboolean gedit_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, - GtkTreePath * path); -static gboolean gedit_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, - GtkTreePath * path, - GtkSelectionData * selection_data); - -static void file_browser_node_free (GeditFileBrowserStore * model, - FileBrowserNode * node); -static void model_add_node (GeditFileBrowserStore * model, - FileBrowserNode * child, - FileBrowserNode * parent); -static void model_clear (GeditFileBrowserStore * model, - gboolean free_nodes); -static gint model_sort_default (FileBrowserNode * node1, - FileBrowserNode * node2); -static void model_check_dummy (GeditFileBrowserStore * model, - FileBrowserNode * node); -static void next_files_async (GFileEnumerator * enumerator, - AsyncNode * async); - -GEDIT_PLUGIN_DEFINE_TYPE_WITH_CODE (GeditFileBrowserStore, gedit_file_browser_store, - G_TYPE_OBJECT, - GEDIT_PLUGIN_IMPLEMENT_INTERFACE (gedit_file_browser_store_tree_model, - GTK_TYPE_TREE_MODEL, - gedit_file_browser_store_iface_init) - GEDIT_PLUGIN_IMPLEMENT_INTERFACE (gedit_file_browser_store_drag_source, - GTK_TYPE_TREE_DRAG_SOURCE, - gedit_file_browser_store_drag_source_init)) - -/* Properties */ -enum { - PROP_0, - - PROP_ROOT, - PROP_VIRTUAL_ROOT, - PROP_FILTER_MODE -}; - -/* Signals */ -enum -{ - BEGIN_LOADING, - END_LOADING, - ERROR, - NO_TRASH, - RENAME, - BEGIN_REFRESH, - END_REFRESH, - UNLOAD, - NUM_SIGNALS -}; - -static guint model_signals[NUM_SIGNALS] = { 0 }; - -static void -cancel_mount_operation (GeditFileBrowserStore *obj) -{ - if (obj->priv->mount_info != NULL) - { - obj->priv->mount_info->model = NULL; - g_cancellable_cancel (obj->priv->mount_info->cancellable); - obj->priv->mount_info = NULL; - } -} - -static void -gedit_file_browser_store_finalize (GObject * object) -{ - GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object); - GSList *item; - - /* Free all the nodes */ - file_browser_node_free (obj, obj->priv->root); - - /* Cancel any asynchronous operations */ - for (item = obj->priv->async_handles; item; item = item->next) - { - AsyncData *data = (AsyncData *) (item->data); - g_cancellable_cancel (data->cancellable); - - data->removed = TRUE; - } - - cancel_mount_operation (obj); - - g_slist_free (obj->priv->async_handles); - G_OBJECT_CLASS (gedit_file_browser_store_parent_class)->finalize (object); -} - -static void -set_gvalue_from_node (GValue *value, - FileBrowserNode *node) -{ - gchar * uri; - - if (node == NULL || !node->file) { - g_value_set_string (value, NULL); - } else { - uri = g_file_get_uri (node->file); - g_value_take_string (value, uri); - } -} - -static void -gedit_file_browser_store_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object); - - switch (prop_id) - { - case PROP_ROOT: - set_gvalue_from_node (value, obj->priv->root); - break; - case PROP_VIRTUAL_ROOT: - set_gvalue_from_node (value, obj->priv->virtual_root); - break; - case PROP_FILTER_MODE: - g_value_set_flags (value, obj->priv->filter_mode); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_file_browser_store_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserStore *obj = GEDIT_FILE_BROWSER_STORE (object); - - switch (prop_id) - { - case PROP_FILTER_MODE: - gedit_file_browser_store_set_filter_mode (obj, - g_value_get_flags (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_file_browser_store_class_init (GeditFileBrowserStoreClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gedit_file_browser_store_finalize; - - object_class->get_property = gedit_file_browser_store_get_property; - object_class->set_property = gedit_file_browser_store_set_property; - - g_object_class_install_property (object_class, PROP_ROOT, - g_param_spec_string ("root", - "Root", - "The root uri", - NULL, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_VIRTUAL_ROOT, - g_param_spec_string ("virtual-root", - "Virtual Root", - "The virtual root uri", - NULL, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, PROP_FILTER_MODE, - g_param_spec_flags ("filter-mode", - "Filter Mode", - "The filter mode", - GEDIT_TYPE_FILE_BROWSER_STORE_FILTER_MODE, - gedit_file_browser_store_filter_mode_get_default (), - G_PARAM_READWRITE)); - - model_signals[BEGIN_LOADING] = - g_signal_new ("begin-loading", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - begin_loading), NULL, NULL, - g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, - GTK_TYPE_TREE_ITER); - model_signals[END_LOADING] = - g_signal_new ("end-loading", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - end_loading), NULL, NULL, - g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, - GTK_TYPE_TREE_ITER); - model_signals[ERROR] = - g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - error), NULL, NULL, - gedit_file_browser_marshal_VOID__UINT_STRING, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); - model_signals[NO_TRASH] = - g_signal_new ("no-trash", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - no_trash), g_signal_accumulator_true_handled, NULL, - gedit_file_browser_marshal_BOOL__POINTER, - G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); - model_signals[RENAME] = - g_signal_new ("rename", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - rename), NULL, NULL, - gedit_file_browser_marshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_STRING); - model_signals[BEGIN_REFRESH] = - g_signal_new ("begin-refresh", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - begin_refresh), NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - model_signals[END_REFRESH] = - g_signal_new ("end-refresh", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - end_refresh), NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - model_signals[UNLOAD] = - g_signal_new ("unload", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserStoreClass, - unload), NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserStorePrivate)); -} - -static void -gedit_file_browser_store_iface_init (GtkTreeModelIface * iface) -{ - iface->get_flags = gedit_file_browser_store_get_flags; - iface->get_n_columns = gedit_file_browser_store_get_n_columns; - iface->get_column_type = gedit_file_browser_store_get_column_type; - iface->get_iter = gedit_file_browser_store_get_iter; - iface->get_path = gedit_file_browser_store_get_path; - iface->get_value = gedit_file_browser_store_get_value; - iface->iter_next = gedit_file_browser_store_iter_next; - iface->iter_children = gedit_file_browser_store_iter_children; - iface->iter_has_child = gedit_file_browser_store_iter_has_child; - iface->iter_n_children = gedit_file_browser_store_iter_n_children; - iface->iter_nth_child = gedit_file_browser_store_iter_nth_child; - iface->iter_parent = gedit_file_browser_store_iter_parent; - iface->row_inserted = gedit_file_browser_store_row_inserted; -} - -static void -gedit_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface) -{ - iface->row_draggable = gedit_file_browser_store_row_draggable; - iface->drag_data_delete = gedit_file_browser_store_drag_data_delete; - iface->drag_data_get = gedit_file_browser_store_drag_data_get; -} - -static void -gedit_file_browser_store_init (GeditFileBrowserStore * obj) -{ - obj->priv = GEDIT_FILE_BROWSER_STORE_GET_PRIVATE (obj); - - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_URI] = - G_TYPE_STRING; - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_NAME] = - G_TYPE_STRING; - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS] = - G_TYPE_UINT; - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_ICON] = - GDK_TYPE_PIXBUF; - obj->priv->column_types[GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM] = - GDK_TYPE_PIXBUF; - - // Default filter mode is hiding the hidden files - obj->priv->filter_mode = gedit_file_browser_store_filter_mode_get_default (); - obj->priv->sort_func = model_sort_default; -} - -static gboolean -node_has_parent (FileBrowserNode * node, FileBrowserNode * parent) -{ - if (node->parent == NULL) - return FALSE; - - if (node->parent == parent) - return TRUE; - - return node_has_parent (node->parent, parent); -} - -static gboolean -node_in_tree (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - return node_has_parent (node, model->priv->virtual_root); -} - -static gboolean -model_node_visibility (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - if (node == NULL) - return FALSE; - - if (NODE_IS_DUMMY (node)) - return !NODE_IS_HIDDEN (node); - - if (node == model->priv->virtual_root) - return TRUE; - - if (!node_has_parent (node, model->priv->virtual_root)) - return FALSE; - - return !NODE_IS_FILTERED (node); -} - -static gboolean -model_node_inserted (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - return node == model->priv->virtual_root || (model_node_visibility (model, node) && node->inserted); -} - -/* Interface implementation */ - -static GtkTreeModelFlags -gedit_file_browser_store_get_flags (GtkTreeModel * tree_model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - (GtkTreeModelFlags) 0); - - return GTK_TREE_MODEL_ITERS_PERSIST; -} - -static gint -gedit_file_browser_store_get_n_columns (GtkTreeModel * tree_model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), 0); - - return GEDIT_FILE_BROWSER_STORE_COLUMN_NUM; -} - -static GType -gedit_file_browser_store_get_column_type (GtkTreeModel * tree_model, gint idx) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - G_TYPE_INVALID); - g_return_val_if_fail (idx < GEDIT_FILE_BROWSER_STORE_COLUMN_NUM && - idx >= 0, G_TYPE_INVALID); - - return GEDIT_FILE_BROWSER_STORE (tree_model)->priv->column_types[idx]; -} - -static gboolean -gedit_file_browser_store_get_iter (GtkTreeModel * tree_model, - GtkTreeIter * iter, GtkTreePath * path) -{ - gint * indices, depth, i; - FileBrowserNode * node; - GeditFileBrowserStore * model; - gint num; - - g_assert (GEDIT_IS_FILE_BROWSER_STORE (tree_model)); - g_assert (path != NULL); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - indices = gtk_tree_path_get_indices (path); - depth = gtk_tree_path_get_depth (path); - node = model->priv->virtual_root; - - for (i = 0; i < depth; ++i) { - GSList * item; - - if (node == NULL) - return FALSE; - - num = 0; - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { - FileBrowserNode * child; - - child = (FileBrowserNode *) (item->data); - - if (model_node_inserted (model, child)) { - if (num == indices[i]) { - node = child; - break; - } - - num++; - } - } - - if (item == NULL) - return FALSE; - - node = (FileBrowserNode *) (item->data); - } - - iter->user_data = node; - iter->user_data2 = NULL; - iter->user_data3 = NULL; - - return node != NULL; -} - -static GtkTreePath * -gedit_file_browser_store_get_path_real (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - GtkTreePath *path; - gint num = 0; - - path = gtk_tree_path_new (); - - while (node != model->priv->virtual_root) { - GSList *item; - - if (node->parent == NULL) { - gtk_tree_path_free (path); - return NULL; - } - - num = 0; - - for (item = FILE_BROWSER_NODE_DIR (node->parent)->children; item; item = item->next) { - FileBrowserNode *check; - - check = (FileBrowserNode *) (item->data); - - if (model_node_visibility (model, check) && (check == node || check->inserted)) { - if (check == node) { - gtk_tree_path_prepend_index (path, - num); - break; - } - - ++num; - } else if (check == node) { - if (NODE_IS_DUMMY (node)) - g_warning ("Dummy not visible???"); - - gtk_tree_path_free (path); - return NULL; - } - } - - node = node->parent; - } - - return path; -} - -static GtkTreePath * -gedit_file_browser_store_get_path (GtkTreeModel * tree_model, - GtkTreeIter * iter) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), NULL); - g_return_val_if_fail (iter != NULL, NULL); - g_return_val_if_fail (iter->user_data != NULL, NULL); - - return gedit_file_browser_store_get_path_real (GEDIT_FILE_BROWSER_STORE (tree_model), - (FileBrowserNode *) (iter->user_data)); -} - -static void -gedit_file_browser_store_get_value (GtkTreeModel * tree_model, - GtkTreeIter * iter, - gint column, - GValue * value) -{ - FileBrowserNode *node; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - node = (FileBrowserNode *) (iter->user_data); - - g_value_init (value, GEDIT_FILE_BROWSER_STORE (tree_model)->priv->column_types[column]); - - switch (column) { - case GEDIT_FILE_BROWSER_STORE_COLUMN_URI: - set_gvalue_from_node (value, node); - break; - case GEDIT_FILE_BROWSER_STORE_COLUMN_NAME: - g_value_set_string (value, node->name); - break; - case GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS: - g_value_set_uint (value, node->flags); - break; - case GEDIT_FILE_BROWSER_STORE_COLUMN_ICON: - g_value_set_object (value, node->icon); - break; - case GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM: - g_value_set_object (value, node->emblem); - break; - default: - g_return_if_reached (); - } -} - -static gboolean -gedit_file_browser_store_iter_next (GtkTreeModel * tree_model, - GtkTreeIter * iter) -{ - GeditFileBrowserStore * model; - FileBrowserNode * node; - GSList * item; - GSList * first; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (iter->user_data != NULL, FALSE); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - node = (FileBrowserNode *) (iter->user_data); - - if (node->parent == NULL) - return FALSE; - - first = g_slist_next (g_slist_find (FILE_BROWSER_NODE_DIR (node->parent)->children, node)); - - for (item = first; item; item = item->next) { - if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { - iter->user_data = item->data; - return TRUE; - } - } - - return FALSE; -} - -static gboolean -gedit_file_browser_store_iter_children (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * parent) -{ - FileBrowserNode * node; - GeditFileBrowserStore * model; - GSList * item; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - FALSE); - g_return_val_if_fail (parent == NULL - || parent->user_data != NULL, FALSE); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - - if (parent == NULL) - node = model->priv->virtual_root; - else - node = (FileBrowserNode *) (parent->user_data); - - if (node == NULL) - return FALSE; - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { - if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { - iter->user_data = item->data; - return TRUE; - } - } - - return FALSE; -} - -static gboolean -filter_tree_model_iter_has_child_real (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - GSList *item; - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { - if (model_node_inserted (model, (FileBrowserNode *) (item->data))) - return TRUE; - } - - return FALSE; -} - -static gboolean -gedit_file_browser_store_iter_has_child (GtkTreeModel * tree_model, - GtkTreeIter * iter) -{ - FileBrowserNode *node; - GeditFileBrowserStore *model; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - FALSE); - g_return_val_if_fail (iter == NULL - || iter->user_data != NULL, FALSE); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - - if (iter == NULL) - node = model->priv->virtual_root; - else - node = (FileBrowserNode *) (iter->user_data); - - return filter_tree_model_iter_has_child_real (model, node); -} - -static gint -gedit_file_browser_store_iter_n_children (GtkTreeModel * tree_model, - GtkTreeIter * iter) -{ - FileBrowserNode *node; - GeditFileBrowserStore *model; - GSList *item; - gint num = 0; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - FALSE); - g_return_val_if_fail (iter == NULL - || iter->user_data != NULL, FALSE); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - - if (iter == NULL) - node = model->priv->virtual_root; - else - node = (FileBrowserNode *) (iter->user_data); - - if (!NODE_IS_DIR (node)) - return 0; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) - if (model_node_inserted (model, (FileBrowserNode *) (item->data))) - ++num; - - return num; -} - -static gboolean -gedit_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * parent, gint n) -{ - FileBrowserNode *node; - GeditFileBrowserStore *model; - GSList *item; - gint num = 0; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), - FALSE); - g_return_val_if_fail (parent == NULL - || parent->user_data != NULL, FALSE); - - model = GEDIT_FILE_BROWSER_STORE (tree_model); - - if (parent == NULL) - node = model->priv->virtual_root; - else - node = (FileBrowserNode *) (parent->user_data); - - if (!NODE_IS_DIR (node)) - return FALSE; - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; - item = item->next) { - if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { - if (num == n) { - iter->user_data = item->data; - return TRUE; - } - - ++num; - } - } - - return FALSE; -} - -static gboolean -gedit_file_browser_store_iter_parent (GtkTreeModel * tree_model, - GtkTreeIter * iter, - GtkTreeIter * child) -{ - FileBrowserNode *node; - GeditFileBrowserStore *model; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model), FALSE); - g_return_val_if_fail (child != NULL, FALSE); - g_return_val_if_fail (child->user_data != NULL, FALSE); - - node = (FileBrowserNode *) (child->user_data); - model = GEDIT_FILE_BROWSER_STORE (tree_model); - - if (!node_in_tree (model, node)) - return FALSE; - - if (node->parent == NULL) - return FALSE; - - iter->user_data = node->parent; - return TRUE; -} - -static void -gedit_file_browser_store_row_inserted (GtkTreeModel * tree_model, - GtkTreePath * path, - GtkTreeIter * iter) -{ - FileBrowserNode * node = (FileBrowserNode *)(iter->user_data); - - node->inserted = TRUE; -} - -static gboolean -gedit_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, - GtkTreePath * path) -{ - GtkTreeIter iter; - GeditFileBrowserStoreFlag flags; - - if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), - &iter, path)) - { - return FALSE; - } - - gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - return !FILE_IS_DUMMY(flags); -} - -static gboolean -gedit_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, - GtkTreePath * path) -{ - return FALSE; -} - -static gboolean -gedit_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, - GtkTreePath * path, - GtkSelectionData * selection_data) -{ - GtkTreeIter iter; - gchar *uri; - gchar *uris[2] = {0, }; - gboolean ret; - - if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), - &iter, path)) - { - return FALSE; - } - - gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - g_assert (uri); - - uris[0] = uri; - ret = gtk_selection_data_set_uris (selection_data, uris); - - g_free (uri); - - return ret; -} - -#define FILTER_HIDDEN(mode) (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) -#define FILTER_BINARY(mode) (mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) - -/* Private */ -static void -model_begin_loading (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - GtkTreeIter iter; - - iter.user_data = node; - g_signal_emit (model, model_signals[BEGIN_LOADING], 0, &iter); -} - -static void -model_end_loading (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - GtkTreeIter iter; - - iter.user_data = node; - g_signal_emit (model, model_signals[END_LOADING], 0, &iter); -} - -static void -model_node_update_visibility (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - GtkTreeIter iter; - - node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED; - - if (FILTER_HIDDEN (model->priv->filter_mode) && - NODE_IS_HIDDEN (node)) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED; - else if (FILTER_BINARY (model->priv->filter_mode) && - (!NODE_IS_TEXT (node) && !NODE_IS_DIR (node))) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED; - else if (model->priv->filter_func) { - iter.user_data = node; - - if (!model->priv-> - filter_func (model, &iter, - model->priv->filter_user_data)) - node->flags |= - GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED; - } -} - -static gint -collate_nodes (FileBrowserNode * node1, FileBrowserNode * node2) -{ - if (node1->name == NULL) - return -1; - else if (node2->name == NULL) - return 1; - else { - gchar *k1, *k2; - gint result; - - k1 = g_utf8_collate_key_for_filename (node1->name, -1); - k2 = g_utf8_collate_key_for_filename (node2->name, -1); - - result = strcmp (k1, k2); - - g_free (k1); - g_free (k2); - - return result; - } -} - -static gint -model_sort_default (FileBrowserNode * node1, FileBrowserNode * node2) -{ - gint f1; - gint f2; - - f1 = NODE_IS_DUMMY (node1); - f2 = NODE_IS_DUMMY (node2); - - if (f1 && f2) - { - return 0; - } - else if (f1 || f2) - { - return f1 ? -1 : 1; - } - - f1 = NODE_IS_DIR (node1); - f2 = NODE_IS_DIR (node2); - - if (f1 != f2) - { - return f1 ? -1 : 1; - } - - f1 = NODE_IS_HIDDEN (node1); - f2 = NODE_IS_HIDDEN (node2); - - if (f1 != f2) - { - return f2 ? -1 : 1; - } - - return collate_nodes (node1, node2); -} - -static void -model_resort_node (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - FileBrowserNodeDir *dir; - GSList *item; - FileBrowserNode *child; - gint pos = 0; - GtkTreeIter iter; - GtkTreePath *path; - gint *neworder; - - dir = FILE_BROWSER_NODE_DIR (node->parent); - - if (!model_node_visibility (model, node->parent)) { - /* Just sort the children of the parent */ - dir->children = g_slist_sort (dir->children, - (GCompareFunc) (model->priv-> - sort_func)); - } else { - /* Store current positions */ - for (item = dir->children; item; item = item->next) { - child = (FileBrowserNode *) (item->data); - - if (model_node_visibility (model, child)) - child->pos = pos++; - } - - dir->children = g_slist_sort (dir->children, - (GCompareFunc) (model->priv-> - sort_func)); - neworder = g_new (gint, pos); - pos = 0; - - /* Store the new positions */ - for (item = dir->children; item; item = item->next) { - child = (FileBrowserNode *) (item->data); - - if (model_node_visibility (model, child)) - neworder[pos++] = child->pos; - } - - iter.user_data = node->parent; - path = - gedit_file_browser_store_get_path_real (model, - node->parent); - - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), - path, &iter, neworder); - - g_free (neworder); - gtk_tree_path_free (path); - } -} - -static void -row_changed (GeditFileBrowserStore * model, - GtkTreePath ** path, - GtkTreeIter * iter) -{ - GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path); - - /* Insert a copy of the actual path here because the row-inserted - signal may alter the path */ - gtk_tree_model_row_changed (GTK_TREE_MODEL(model), *path, iter); - gtk_tree_path_free (*path); - - *path = gtk_tree_row_reference_get_path (ref); - gtk_tree_row_reference_free (ref); -} - -static void -row_inserted (GeditFileBrowserStore * model, - GtkTreePath ** path, - GtkTreeIter * iter) -{ - /* This function creates a row reference for the path because it's - uncertain what might change the actual model/view when we insert - a node, maybe another directory load is triggered for example. - Because functions that use this function rely on the notion that - the path remains pointed towards the inserted node, we use the - reference to keep track. */ - GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path); - GtkTreePath * copy = gtk_tree_path_copy (*path); - - gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), copy, iter); - gtk_tree_path_free (copy); - - if (ref) - { - gtk_tree_path_free (*path); - - /* To restore the path, we get the path from the reference. But, since - we inserted a row, the path will be one index further than the - actual path of our node. We therefore call gtk_tree_path_prev */ - *path = gtk_tree_row_reference_get_path (ref); - gtk_tree_path_prev (*path); - } - - gtk_tree_row_reference_free (ref); -} - -static void -row_deleted (GeditFileBrowserStore * model, - const GtkTreePath * path) -{ - GtkTreePath *copy = gtk_tree_path_copy (path); - - /* Delete a copy of the actual path here because the row-deleted - signal may alter the path */ - gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), copy); - gtk_tree_path_free (copy); -} - -static void -model_refilter_node (GeditFileBrowserStore * model, - FileBrowserNode * node, - GtkTreePath ** path) -{ - gboolean old_visible; - gboolean new_visible; - FileBrowserNodeDir *dir; - GSList *item; - GtkTreeIter iter; - GtkTreePath *tmppath = NULL; - gboolean in_tree; - - if (node == NULL) - return; - - old_visible = model_node_visibility (model, node); - model_node_update_visibility (model, node); - - in_tree = node_in_tree (model, node); - - if (path == NULL) - { - if (in_tree) - tmppath = gedit_file_browser_store_get_path_real (model, - node); - else - tmppath = gtk_tree_path_new_first (); - - path = &tmppath; - } - - if (NODE_IS_DIR (node)) { - if (in_tree) - gtk_tree_path_down (*path); - - dir = FILE_BROWSER_NODE_DIR (node); - - for (item = dir->children; item; item = item->next) { - model_refilter_node (model, - (FileBrowserNode *) (item->data), - path); - } - - if (in_tree) - gtk_tree_path_up (*path); - } - - if (in_tree) { - new_visible = model_node_visibility (model, node); - - if (old_visible != new_visible) { - if (old_visible) { - node->inserted = FALSE; - row_deleted (model, *path); - } else { - iter.user_data = node; - row_inserted (model, path, &iter); - gtk_tree_path_next (*path); - } - } else if (old_visible) { - gtk_tree_path_next (*path); - } - } - - model_check_dummy (model, node); - - if (tmppath) - gtk_tree_path_free (tmppath); -} - -static void -model_refilter (GeditFileBrowserStore * model) -{ - model_refilter_node (model, model->priv->root, NULL); -} - -static void -file_browser_node_set_name (FileBrowserNode * node) -{ - g_free (node->name); - - if (node->file) { - node->name = gedit_file_browser_utils_file_basename (node->file); - } else { - node->name = NULL; - } -} - -static void -file_browser_node_init (FileBrowserNode * node, GFile * file, - FileBrowserNode * parent) -{ - if (file != NULL) { - node->file = g_object_ref (file); - file_browser_node_set_name (node); - } - - node->parent = parent; -} - -static FileBrowserNode * -file_browser_node_new (GFile * file, FileBrowserNode * parent) -{ - FileBrowserNode *node = g_slice_new0 (FileBrowserNode); - - file_browser_node_init (node, file, parent); - return node; -} - -static FileBrowserNode * -file_browser_node_dir_new (GeditFileBrowserStore * model, - GFile * file, FileBrowserNode * parent) -{ - FileBrowserNode *node = - (FileBrowserNode *) g_slice_new0 (FileBrowserNodeDir); - - file_browser_node_init (node, file, parent); - - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; - - FILE_BROWSER_NODE_DIR (node)->model = model; - - return node; -} - -static void -file_browser_node_free_children (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - GSList *item; - - if (node == NULL) - return; - - if (NODE_IS_DIR (node)) { - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; - item = item->next) - file_browser_node_free (model, - (FileBrowserNode *) (item-> - data)); - - g_slist_free (FILE_BROWSER_NODE_DIR (node)->children); - FILE_BROWSER_NODE_DIR (node)->children = NULL; - - /* This node is no longer loaded */ - node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_LOADED; - } -} - -static void -file_browser_node_free (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - gchar *uri; - - if (node == NULL) - return; - - if (NODE_IS_DIR (node)) - { - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (node); - - if (dir->cancellable) { - g_cancellable_cancel (dir->cancellable); - g_object_unref (dir->cancellable); - - model_end_loading (model, node); - } - - file_browser_node_free_children (model, node); - - if (dir->monitor) { - g_file_monitor_cancel (dir->monitor); - g_object_unref (dir->monitor); - } - - if (dir->hidden_file_hash) - g_hash_table_destroy (dir->hidden_file_hash); - } - - if (node->file) - { - uri = g_file_get_uri (node->file); - g_signal_emit (model, model_signals[UNLOAD], 0, uri); - - g_free (uri); - g_object_unref (node->file); - } - - if (node->icon) - g_object_unref (node->icon); - - if (node->emblem) - g_object_unref (node->emblem); - - g_free (node->name); - - if (NODE_IS_DIR (node)) - g_slice_free (FileBrowserNodeDir, (FileBrowserNodeDir *)node); - else - g_slice_free (FileBrowserNode, (FileBrowserNode *)node); -} - -/** - * model_remove_node_children: - * @model: the #GeditFileBrowserStore - * @node: the FileBrowserNode to remove - * @path: the path of the node, or NULL to let the path be calculated - * @free_nodes: whether to also remove the nodes from memory - * - * Removes all the children of node from the model. This function is used - * to remove the child nodes from the _model_. Don't use it to just free - * a node. - **/ -static void -model_remove_node_children (GeditFileBrowserStore * model, - FileBrowserNode * node, - GtkTreePath * path, - gboolean free_nodes) -{ - FileBrowserNodeDir *dir; - GtkTreePath *path_child; - GSList *list; - GSList *item; - - if (node == NULL || !NODE_IS_DIR (node)) - return; - - dir = FILE_BROWSER_NODE_DIR (node); - - if (dir->children == NULL) - return; - - if (!model_node_visibility (model, node)) { - // Node is invisible and therefore the children can just - // be freed - if (free_nodes) - file_browser_node_free_children (model, node); - - return; - } - - if (path == NULL) - path_child = - gedit_file_browser_store_get_path_real (model, node); - else - path_child = gtk_tree_path_copy (path); - - gtk_tree_path_down (path_child); - - list = g_slist_copy (dir->children); - - for (item = list; item; item = item->next) { - model_remove_node (model, (FileBrowserNode *) (item->data), - path_child, free_nodes); - } - - g_slist_free (list); - gtk_tree_path_free (path_child); -} - -/** - * model_remove_node: - * @model: the #GeditFileBrowserStore - * @node: the FileBrowserNode to remove - * @path: the path to use to remove this node, or NULL to use the path - * calculated from the node itself - * @free_nodes: whether to also remove the nodes from memory - * - * Removes this node and all its children from the model. This function is used - * to remove the node from the _model_. Don't use it to just free - * a node. - **/ -static void -model_remove_node (GeditFileBrowserStore * model, - FileBrowserNode * node, - GtkTreePath * path, - gboolean free_nodes) -{ - gboolean free_path = FALSE; - FileBrowserNode *parent; - - if (path == NULL) { - path = - gedit_file_browser_store_get_path_real (model, node); - free_path = TRUE; - } - - model_remove_node_children (model, node, path, free_nodes); - - /* Only delete if the node is visible in the tree (but only when it's - not the virtual root) */ - if (model_node_visibility (model, node) && node != model->priv->virtual_root) - { - node->inserted = FALSE; - row_deleted (model, path); - } - - if (free_path) - gtk_tree_path_free (path); - - parent = node->parent; - - if (free_nodes) { - /* Remove the node from the parents children list */ - if (parent) - FILE_BROWSER_NODE_DIR (node->parent)->children = - g_slist_remove (FILE_BROWSER_NODE_DIR - (node->parent)->children, - node); - } - - /* If this is the virtual root, than set the parent as the virtual root */ - if (node == model->priv->virtual_root) - set_virtual_root_from_node (model, parent); - else if (parent && model_node_visibility (model, parent) && !(free_nodes && NODE_IS_DUMMY(node))) - model_check_dummy (model, parent); - - /* Now free the node if necessary */ - if (free_nodes) - file_browser_node_free (model, node); -} - -/** - * model_clear: - * @model: the #GeditFileBrowserStore - * @free_nodes: whether to also remove the nodes from memory - * - * Removes all nodes from the model. This function is used - * to remove all the nodes from the _model_. Don't use it to just free the - * nodes in the model. - **/ -static void -model_clear (GeditFileBrowserStore * model, gboolean free_nodes) -{ - GtkTreePath *path; - FileBrowserNodeDir *dir; - FileBrowserNode *dummy; - - path = gtk_tree_path_new (); - model_remove_node_children (model, model->priv->virtual_root, path, - free_nodes); - gtk_tree_path_free (path); - - /* Remove the dummy if there is one */ - if (model->priv->virtual_root) { - dir = FILE_BROWSER_NODE_DIR (model->priv->virtual_root); - - if (dir->children != NULL) { - dummy = (FileBrowserNode *) (dir->children->data); - - if (NODE_IS_DUMMY (dummy) - && model_node_visibility (model, dummy)) { - path = gtk_tree_path_new_first (); - - dummy->inserted = FALSE; - row_deleted (model, path); - gtk_tree_path_free (path); - } - } - } -} - -static void -file_browser_node_unload (GeditFileBrowserStore * model, - FileBrowserNode * node, gboolean remove_children) -{ - FileBrowserNodeDir *dir; - - if (node == NULL) - return; - - if (!NODE_IS_DIR (node) || !NODE_LOADED (node)) - return; - - dir = FILE_BROWSER_NODE_DIR (node); - - if (remove_children) - model_remove_node_children (model, node, NULL, TRUE); - - if (dir->cancellable) { - g_cancellable_cancel (dir->cancellable); - g_object_unref (dir->cancellable); - - model_end_loading (model, node); - dir->cancellable = NULL; - } - - if (dir->monitor) { - g_file_monitor_cancel (dir->monitor); - g_object_unref (dir->monitor); - - dir->monitor = NULL; - } - - node->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_LOADED; -} - -static void -model_recomposite_icon_real (GeditFileBrowserStore * tree_model, - FileBrowserNode * node, - GFileInfo * info) -{ - GdkPixbuf *icon; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model)); - g_return_if_fail (node != NULL); - - if (node->file == NULL) - return; - - if (info) { - GIcon *gicon = g_file_info_get_icon (info); - if (gicon != NULL) - icon = gedit_file_browser_utils_pixbuf_from_icon (gicon, GTK_ICON_SIZE_MENU); - else - icon = NULL; - } else { - icon = gedit_file_browser_utils_pixbuf_from_file (node->file, GTK_ICON_SIZE_MENU); - } - - if (node->icon) - g_object_unref (node->icon); - - if (node->emblem) { - gint icon_size; - - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size); - - if (icon == NULL) { - node->icon = - gdk_pixbuf_new (gdk_pixbuf_get_colorspace (node->emblem), - gdk_pixbuf_get_has_alpha (node->emblem), - gdk_pixbuf_get_bits_per_sample (node->emblem), - icon_size, - icon_size); - } else { - node->icon = gdk_pixbuf_copy (icon); - g_object_unref (icon); - } - - gdk_pixbuf_composite (node->emblem, node->icon, - icon_size - 10, icon_size - 10, 10, - 10, icon_size - 10, icon_size - 10, - 1, 1, GDK_INTERP_NEAREST, 255); - } else { - node->icon = icon; - } -} - -static void -model_recomposite_icon (GeditFileBrowserStore * tree_model, - GtkTreeIter * iter) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - model_recomposite_icon_real (tree_model, - (FileBrowserNode *) (iter->user_data), - NULL); -} - -static FileBrowserNode * -model_create_dummy_node (GeditFileBrowserStore * model, - FileBrowserNode * parent) -{ - FileBrowserNode *dummy; - - dummy = file_browser_node_new (NULL, parent); - dummy->name = g_strdup (_("(Empty)")); - - dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY; - dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - return dummy; -} - -static FileBrowserNode * -model_add_dummy_node (GeditFileBrowserStore * model, - FileBrowserNode * parent) -{ - FileBrowserNode *dummy; - - dummy = model_create_dummy_node (model, parent); - - if (model_node_visibility (model, parent)) - dummy->flags &= ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - model_add_node (model, dummy, parent); - - return dummy; -} - -static void -model_check_dummy (GeditFileBrowserStore * model, FileBrowserNode * node) -{ - // Hide the dummy child if needed - if (NODE_IS_DIR (node)) { - FileBrowserNode *dummy; - GtkTreeIter iter; - GtkTreePath *path; - guint flags; - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (node); - - if (dir->children == NULL) { - model_add_dummy_node (model, node); - return; - } - - dummy = (FileBrowserNode *) (dir->children->data); - - if (!NODE_IS_DUMMY (dummy)) { - dummy = model_create_dummy_node (model, node); - dir->children = g_slist_prepend (dir->children, dummy); - } - - if (!model_node_visibility (model, node)) { - dummy->flags |= - GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - return; - } - - /* Temporarily set the node to invisible to check - * for real children */ - flags = dummy->flags; - dummy->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - if (!filter_tree_model_iter_has_child_real (model, node)) { - dummy->flags &= - ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - if (FILE_IS_HIDDEN (flags)) { - // Was hidden, needs to be inserted - iter.user_data = dummy; - path = - gedit_file_browser_store_get_path_real - (model, dummy); - - row_inserted (model, &path, &iter); - gtk_tree_path_free (path); - } - } else { - if (!FILE_IS_HIDDEN (flags)) { - // Was shown, needs to be removed - - // To get the path we need to set it to visible temporarily - dummy->flags &= - ~GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - path = - gedit_file_browser_store_get_path_real - (model, dummy); - dummy->flags |= - GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - dummy->inserted = FALSE; - row_deleted (model, path); - gtk_tree_path_free (path); - } - } - } -} - -static void -insert_node_sorted (GeditFileBrowserStore * model, - FileBrowserNode * child, - FileBrowserNode * parent) -{ - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (parent); - - if (model->priv->sort_func == NULL) { - dir->children = g_slist_append (dir->children, child); - } else { - dir->children = - g_slist_insert_sorted (dir->children, child, - (GCompareFunc) (model->priv-> - sort_func)); - } -} - -static void -model_add_node (GeditFileBrowserStore * model, FileBrowserNode * child, - FileBrowserNode * parent) -{ - /* Add child to parents children */ - insert_node_sorted (model, child, parent); - - if (model_node_visibility (model, parent) && - model_node_visibility (model, child)) { - GtkTreeIter iter; - GtkTreePath *path; - - iter.user_data = child; - path = gedit_file_browser_store_get_path_real (model, child); - - /* Emit row inserted */ - row_inserted (model, &path, &iter); - gtk_tree_path_free (path); - } - - model_check_dummy (model, parent); - model_check_dummy (model, child); -} - -static void -model_add_nodes_batch (GeditFileBrowserStore * model, - GSList * children, - FileBrowserNode * parent) -{ - GSList *sorted_children; - GSList *child; - GSList *prev; - GSList *l; - FileBrowserNodeDir *dir; - - dir = FILE_BROWSER_NODE_DIR (parent); - - sorted_children = g_slist_sort (children, (GCompareFunc) model->priv->sort_func); - - child = sorted_children; - l = dir->children; - prev = NULL; - - model_check_dummy (model, parent); - - while (child) { - FileBrowserNode *node = child->data; - GtkTreeIter iter; - GtkTreePath *path; - - /* reached the end of the first list, just append the second */ - if (l == NULL) { - - dir->children = g_slist_concat (dir->children, child); - - for (l = child; l; l = l->next) { - if (model_node_visibility (model, parent) && - model_node_visibility (model, l->data)) { - iter.user_data = l->data; - path = gedit_file_browser_store_get_path_real (model, l->data); - - // Emit row inserted - row_inserted (model, &path, &iter); - gtk_tree_path_free (path); - } - - model_check_dummy (model, l->data); - } - - break; - } - - if (model->priv->sort_func (l->data, node) > 0) { - GSList *next_child; - - if (prev == NULL) { - /* prepend to the list */ - dir->children = g_slist_prepend (dir->children, child); - } else { - prev->next = child; - } - - next_child = child->next; - prev = child; - child->next = l; - child = next_child; - - if (model_node_visibility (model, parent) && - model_node_visibility (model, node)) { - iter.user_data = node; - path = gedit_file_browser_store_get_path_real (model, node); - - // Emit row inserted - row_inserted (model, &path, &iter); - gtk_tree_path_free (path); - } - - model_check_dummy (model, node); - - /* try again at the same l position with the - * next child */ - } else { - - /* Move to the next item in the list */ - prev = l; - l = l->next; - } - } -} - -static gchar const * -backup_content_type (GFileInfo * info) -{ - gchar const * content; - - if (!g_file_info_get_is_backup (info)) - return NULL; - - content = g_file_info_get_content_type (info); - - if (!content || g_content_type_equals (content, "application/x-trash")) - return "text/plain"; - - return content; -} - -static void -file_browser_node_set_from_info (GeditFileBrowserStore * model, - FileBrowserNode * node, - GFileInfo * info, - gboolean isadded) -{ - FileBrowserNodeDir * dir; - gchar const * content; - gchar const * name; - gboolean free_info = FALSE; - GtkTreePath * path; - gchar * uri; - GError * error = NULL; - - if (info == NULL) { - info = g_file_query_info (node->file, - STANDARD_ATTRIBUTE_TYPES, - G_FILE_QUERY_INFO_NONE, - NULL, - &error); - - if (!info) { - if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND)) { - uri = g_file_get_uri (node->file); - g_warning ("Could not get info for %s: %s", uri, error->message); - g_free (uri); - } - g_error_free (error); - - return; - } - - free_info = TRUE; - } - - dir = FILE_BROWSER_NODE_DIR (node->parent); - name = g_file_info_get_name (info); - - if (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - else if (dir != NULL && dir->hidden_file_hash != NULL && - g_hash_table_lookup (dir->hidden_file_hash, name) != NULL) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; - else { - if (!(content = backup_content_type (info))) - content = g_file_info_get_content_type (info); - - if (!content || - g_content_type_is_unknown (content) || - g_content_type_is_a (content, "text/plain")) - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT; - } - - model_recomposite_icon_real (model, node, info); - - if (free_info) - g_object_unref (info); - - if (isadded) { - path = gedit_file_browser_store_get_path_real (model, node); - model_refilter_node (model, node, &path); - gtk_tree_path_free (path); - - model_check_dummy (model, node->parent); - } else { - model_node_update_visibility (model, node); - } -} - -static FileBrowserNode * -node_list_contains_file (GSList *children, GFile * file) -{ - GSList *item; - - for (item = children; item; item = item->next) { - FileBrowserNode *node; - - node = (FileBrowserNode *) (item->data); - - if (node->file != NULL - && g_file_equal (node->file, file)) - return node; - } - - return NULL; -} - -static FileBrowserNode * -model_add_node_from_file (GeditFileBrowserStore * model, - FileBrowserNode * parent, - GFile * file, - GFileInfo * info) -{ - FileBrowserNode *node; - gboolean free_info = FALSE; - GError * error = NULL; - - if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL) { - if (info == NULL) { - info = g_file_query_info (file, - STANDARD_ATTRIBUTE_TYPES, - G_FILE_QUERY_INFO_NONE, - NULL, - &error); - free_info = TRUE; - } - - if (!info) { - g_warning ("Error querying file info: %s", error->message); - g_error_free (error); - - /* FIXME: What to do now then... */ - node = file_browser_node_new (file, parent); - } else if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { - node = file_browser_node_dir_new (model, file, parent); - } else { - node = file_browser_node_new (file, parent); - } - - file_browser_node_set_from_info (model, node, info, FALSE); - model_add_node (model, node, parent); - - if (info && free_info) - g_object_unref (info); - } - - return node; -} - -/* We pass in a copy of the list of parent->children so that we do - * not have to check if a file already exists among the ones we just - * added */ -static void -model_add_nodes_from_files (GeditFileBrowserStore * model, - FileBrowserNode * parent, - GSList * original_children, - GList * files) -{ - GList *item; - GSList *nodes = NULL; - - for (item = files; item; item = item->next) { - GFileInfo *info = G_FILE_INFO (item->data); - GFileType type; - gchar const * name; - GFile * file; - FileBrowserNode *node; - - type = g_file_info_get_file_type (info); - - /* Skip all non regular, non directory files */ - if (type != G_FILE_TYPE_REGULAR && - type != G_FILE_TYPE_DIRECTORY && - type != G_FILE_TYPE_SYMBOLIC_LINK) { - g_object_unref (info); - continue; - } - - name = g_file_info_get_name (info); - - /* Skip '.' and '..' directories */ - if (type == G_FILE_TYPE_DIRECTORY && - (strcmp (name, ".") == 0 || - strcmp (name, "..") == 0)) { - continue; - } - - file = g_file_get_child (parent->file, name); - - if ((node = node_list_contains_file (original_children, file)) == NULL) { - - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { - node = file_browser_node_dir_new (model, file, parent); - } else { - node = file_browser_node_new (file, parent); - } - - file_browser_node_set_from_info (model, node, info, FALSE); - - nodes = g_slist_prepend (nodes, node); - } - - g_object_unref (file); - g_object_unref (info); - } - - if (nodes) - model_add_nodes_batch (model, nodes, parent); -} - -static FileBrowserNode * -model_add_node_from_dir (GeditFileBrowserStore * model, - FileBrowserNode * parent, - GFile * file) -{ - FileBrowserNode *node; - - /* Check if it already exists */ - if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL) { - node = file_browser_node_dir_new (model, file, parent); - file_browser_node_set_from_info (model, node, NULL, FALSE); - - if (node->name == NULL) { - file_browser_node_set_name (node); - } - - if (node->icon == NULL) { - node->icon = gedit_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); - } - - model_add_node (model, node, parent); - } - - return node; -} - -/* Read is sync, but we only do it for local files */ -static void -parse_dot_hidden_file (FileBrowserNode *directory) -{ - gsize file_size; - char *file_contents; - GFile *child; - GFileInfo *info; - GFileType type; - int i; - FileBrowserNodeDir * dir = FILE_BROWSER_NODE_DIR (directory); - - /* FIXME: We only support .hidden on file: uri's for the moment. - * Need to figure out if we should do this async or sync to extend - * it to all types of uris. - */ - if (directory->file == NULL || !g_file_is_native (directory->file)) { - return; - } - - child = g_file_get_child (directory->file, ".hidden"); - info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); - - type = info ? g_file_info_get_file_type (info) : G_FILE_TYPE_UNKNOWN; - - if (info) - g_object_unref (info); - - if (type != G_FILE_TYPE_REGULAR) { - g_object_unref (child); - - return; - } - - if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { - g_object_unref (child); - return; - } - - g_object_unref (child); - - if (dir->hidden_file_hash == NULL) { - dir->hidden_file_hash = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - } - - /* Now parse the data */ - i = 0; - while (i < file_size) { - int start; - - start = i; - while (i < file_size && file_contents[i] != '\n') { - i++; - } - - if (i > start) { - char *hidden_filename; - - hidden_filename = g_strndup (file_contents + start, i - start); - g_hash_table_insert (dir->hidden_file_hash, - hidden_filename, hidden_filename); - } - - i++; - - } - - g_free (file_contents); -} - -static void -on_directory_monitor_event (GFileMonitor * monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - FileBrowserNode * parent) -{ - FileBrowserNode *node; - FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - node = node_list_contains_file (dir->children, file); - - if (node != NULL) { - model_remove_node (dir->model, node, NULL, TRUE); - } - break; - case G_FILE_MONITOR_EVENT_CREATED: - if (g_file_query_exists (file, NULL)) { - model_add_node_from_file (dir->model, parent, file, NULL); - } - - break; - default: - break; - } -} - -static void -async_node_free (AsyncNode *async) -{ - g_object_unref (async->cancellable); - g_slist_free (async->original_children); - g_free (async); -} - -static void -model_iterate_next_files_cb (GFileEnumerator * enumerator, - GAsyncResult * result, - AsyncNode * async) -{ - GList * files; - GError * error = NULL; - FileBrowserNodeDir * dir = async->dir; - FileBrowserNode * parent = (FileBrowserNode *)dir; - - files = g_file_enumerator_next_files_finish (enumerator, result, &error); - - if (files == NULL) { - g_file_enumerator_close (enumerator, NULL, NULL); - async_node_free (async); - - if (!error) - { - /* We're done loading */ - g_object_unref (dir->cancellable); - dir->cancellable = NULL; - -/* - * FIXME: This is temporarly, it is a bug in gio: - * http://bugzilla.mate.org/show_bug.cgi?id=565924 - */ -#ifndef G_OS_WIN32 - if (g_file_is_native (parent->file) && dir->monitor == NULL) { - dir->monitor = g_file_monitor_directory (parent->file, - G_FILE_MONITOR_NONE, - NULL, - NULL); - if (dir->monitor != NULL) - { - g_signal_connect (dir->monitor, - "changed", - G_CALLBACK (on_directory_monitor_event), - parent); - } - } -#endif - - model_check_dummy (dir->model, parent); - model_end_loading (dir->model, parent); - } else { - /* Simply return if we were cancelled */ - if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED) - return; - - /* Otherwise handle the error appropriately */ - g_signal_emit (dir->model, - model_signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY, - error->message); - - file_browser_node_unload (dir->model, (FileBrowserNode *)parent, TRUE); - g_error_free (error); - } - } else if (g_cancellable_is_cancelled (async->cancellable)) { - /* Check cancel state manually */ - g_file_enumerator_close (enumerator, NULL, NULL); - async_node_free (async); - } else { - model_add_nodes_from_files (dir->model, parent, async->original_children, files); - - g_list_free (files); - next_files_async (enumerator, async); - } -} - -static void -next_files_async (GFileEnumerator * enumerator, - AsyncNode * async) -{ - g_file_enumerator_next_files_async (enumerator, - DIRECTORY_LOAD_ITEMS_PER_CALLBACK, - G_PRIORITY_DEFAULT, - async->cancellable, - (GAsyncReadyCallback)model_iterate_next_files_cb, - async); -} - -static void -model_iterate_children_cb (GFile * file, - GAsyncResult * result, - AsyncNode * async) -{ - GError * error = NULL; - GFileEnumerator * enumerator; - - if (g_cancellable_is_cancelled (async->cancellable)) - { - async_node_free (async); - return; - } - - enumerator = g_file_enumerate_children_finish (file, result, &error); - - if (enumerator == NULL) { - /* Simply return if we were cancelled or if the dir is not there */ - FileBrowserNodeDir *dir = async->dir; - - /* Otherwise handle the error appropriately */ - g_signal_emit (dir->model, - model_signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_LOAD_DIRECTORY, - error->message); - - file_browser_node_unload (dir->model, (FileBrowserNode *)dir, TRUE); - g_error_free (error); - async_node_free (async); - } else { - next_files_async (enumerator, async); - } -} - -static void -model_load_directory (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - FileBrowserNodeDir *dir; - AsyncNode *async; - - g_return_if_fail (NODE_IS_DIR (node)); - - dir = FILE_BROWSER_NODE_DIR (node); - - /* Cancel a previous load */ - if (dir->cancellable != NULL) { - file_browser_node_unload (dir->model, node, TRUE); - } - - node->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_LOADED; - model_begin_loading (model, node); - - /* Read the '.hidden' file first (if any) */ - parse_dot_hidden_file (node); - - dir->cancellable = g_cancellable_new (); - - async = g_new (AsyncNode, 1); - async->dir = dir; - async->cancellable = g_object_ref (dir->cancellable); - async->original_children = g_slist_copy (dir->children); - - /* Start loading async */ - g_file_enumerate_children_async (node->file, - STANDARD_ATTRIBUTE_TYPES, - G_FILE_QUERY_INFO_NONE, - G_PRIORITY_DEFAULT, - async->cancellable, - (GAsyncReadyCallback)model_iterate_children_cb, - async); -} - -static GList * -get_parent_files (GeditFileBrowserStore * model, GFile * file) -{ - GList * result = NULL; - - result = g_list_prepend (result, g_object_ref (file)); - - while ((file = g_file_get_parent (file))) { - if (g_file_equal (file, model->priv->root->file)) { - g_object_unref (file); - break; - } - - result = g_list_prepend (result, file); - } - - return result; -} - -static void -model_fill (GeditFileBrowserStore * model, FileBrowserNode * node, - GtkTreePath ** path) -{ - gboolean free_path = FALSE; - GtkTreeIter iter = {0,}; - GSList *item; - FileBrowserNode *child; - - if (node == NULL) { - node = model->priv->virtual_root; - *path = gtk_tree_path_new (); - free_path = TRUE; - } - - if (*path == NULL) { - *path = - gedit_file_browser_store_get_path_real (model, node); - free_path = TRUE; - } - - if (!model_node_visibility (model, node)) { - if (free_path) - gtk_tree_path_free (*path); - - return; - } - - if (node != model->priv->virtual_root) { - /* Insert node */ - iter.user_data = node; - - row_inserted(model, path, &iter); - } - - if (NODE_IS_DIR (node)) { - /* Go to the first child */ - gtk_tree_path_down (*path); - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; - item = item->next) { - child = (FileBrowserNode *) (item->data); - - if (model_node_visibility (model, child)) { - model_fill (model, child, path); - - /* Increase path for next child */ - gtk_tree_path_next (*path); - } - } - - /* Move back up to node path */ - gtk_tree_path_up (*path); - } - - model_check_dummy (model, node); - - if (free_path) - gtk_tree_path_free (*path); -} - -static void -set_virtual_root_from_node (GeditFileBrowserStore * model, - FileBrowserNode * node) -{ - FileBrowserNode *next; - FileBrowserNode *prev; - FileBrowserNode *check; - FileBrowserNodeDir *dir; - GSList *item; - GSList *copy; - GtkTreePath *empty = NULL; - - prev = node; - next = prev->parent; - - /* Free all the nodes below that we don't need in cache */ - while (prev != model->priv->root) { - dir = FILE_BROWSER_NODE_DIR (next); - copy = g_slist_copy (dir->children); - - for (item = copy; item; item = item->next) { - check = (FileBrowserNode *) (item->data); - - if (prev == node) { - /* Only free the children, keeping this depth in cache */ - if (check != node) { - file_browser_node_free_children - (model, check); - file_browser_node_unload (model, - check, - FALSE); - } - } else if (check != prev) { - /* Only free when the node is not in the chain */ - dir->children = - g_slist_remove (dir->children, check); - file_browser_node_free (model, check); - } - } - - if (prev != node) - file_browser_node_unload (model, next, FALSE); - - g_slist_free (copy); - prev = next; - next = prev->parent; - } - - /* Free all the nodes up that we don't need in cache */ - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; - item = item->next) { - check = (FileBrowserNode *) (item->data); - - if (NODE_IS_DIR (check)) { - for (copy = - FILE_BROWSER_NODE_DIR (check)->children; copy; - copy = copy->next) { - file_browser_node_free_children (model, - (FileBrowserNode - *) - (copy-> - data)); - file_browser_node_unload (model, - (FileBrowserNode - *) (copy->data), - FALSE); - } - } else if (NODE_IS_DUMMY (check)) { - check->flags |= - GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; - } - } - - /* Now finally, set the virtual root, and load it up! */ - model->priv->virtual_root = node; - - /* Notify that the virtual-root has changed before loading up new nodes so that the - "root_changed" signal can be emitted before any "inserted" signals */ - g_object_notify (G_OBJECT (model), "virtual-root"); - - model_fill (model, NULL, &empty); - - if (!NODE_LOADED (node)) - model_load_directory (model, node); -} - -static void -set_virtual_root_from_file (GeditFileBrowserStore * model, - GFile * file) -{ - GList * files; - GList * item; - FileBrowserNode * parent; - GFile * check; - - /* Always clear the model before altering the nodes */ - model_clear (model, FALSE); - - /* Create the node path, get all the uri's */ - files = get_parent_files (model, file); - parent = model->priv->root; - - for (item = files; item; item = item->next) { - check = G_FILE (item->data); - - parent = model_add_node_from_dir (model, parent, check); - g_object_unref (check); - } - - g_list_free (files); - set_virtual_root_from_node (model, parent); -} - -static FileBrowserNode * -model_find_node_children (GeditFileBrowserStore * model, - FileBrowserNode * parent, - GFile * file) -{ - FileBrowserNodeDir *dir; - FileBrowserNode *child; - FileBrowserNode *result; - GSList *children; - - if (!NODE_IS_DIR (parent)) - return NULL; - - dir = FILE_BROWSER_NODE_DIR (parent); - - for (children = dir->children; children; children = children->next) { - child = (FileBrowserNode *)(children->data); - - result = model_find_node (model, child, file); - - if (result) - return result; - } - - return NULL; -} - -static FileBrowserNode * -model_find_node (GeditFileBrowserStore * model, - FileBrowserNode * node, - GFile * file) -{ - if (node == NULL) - node = model->priv->root; - - if (node->file && g_file_equal (node->file, file)) - return node; - - if (NODE_IS_DIR (node) && g_file_has_prefix (file, node->file)) - return model_find_node_children (model, node, file); - - return NULL; -} - -static GQuark -gedit_file_browser_store_error_quark (void) -{ - static GQuark quark = 0; - - if (G_UNLIKELY (quark == 0)) { - quark = g_quark_from_string ("gedit_file_browser_store_error"); - } - - return quark; -} - -static GFile * -unique_new_name (GFile * directory, gchar const * name) -{ - GFile * newuri = NULL; - guint num = 0; - gchar * newname; - - while (newuri == NULL || g_file_query_exists (newuri, NULL)) { - if (newuri != NULL) - g_object_unref (newuri); - - if (num == 0) - newname = g_strdup (name); - else - newname = g_strdup_printf ("%s(%d)", name, num); - - newuri = g_file_get_child (directory, newname); - g_free (newname); - - ++num; - } - - return newuri; -} - -static GeditFileBrowserStoreResult -model_root_mounted (GeditFileBrowserStore * model, gchar const * virtual_root) -{ - model_check_dummy (model, model->priv->root); - g_object_notify (G_OBJECT (model), "root"); - - if (virtual_root != NULL) - return - gedit_file_browser_store_set_virtual_root_from_string - (model, virtual_root); - else - set_virtual_root_from_node (model, - model->priv->root); - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -static void -handle_root_error (GeditFileBrowserStore * model, GError *error) -{ - FileBrowserNode * root; - - g_signal_emit (model, - model_signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_SET_ROOT, - error->message); - - /* Set the virtual root to the root */ - root = model->priv->root; - model->priv->virtual_root = root; - - /* Set the root to be loaded */ - root->flags |= GEDIT_FILE_BROWSER_STORE_FLAG_LOADED; - - /* Check the dummy */ - model_check_dummy (model, root); - - g_object_notify (G_OBJECT (model), "root"); - g_object_notify (G_OBJECT (model), "virtual-root"); -} - -static void -mount_cb (GFile * file, - GAsyncResult * res, - MountInfo * mount_info) -{ - gboolean mounted; - GError * error = NULL; - GeditFileBrowserStore * model = mount_info->model; - - mounted = g_file_mount_enclosing_volume_finish (file, res, &error); - - if (mount_info->model) - { - model->priv->mount_info = NULL; - model_end_loading (model, model->priv->root); - } - - if (!mount_info->model || g_cancellable_is_cancelled (mount_info->cancellable)) - { - // Reset because it might be reused? - g_cancellable_reset (mount_info->cancellable); - } - else if (mounted) - { - model_root_mounted (model, mount_info->virtual_root); - } - else if (error->code != G_IO_ERROR_CANCELLED) - { - handle_root_error (model, error); - } - - if (error) - g_error_free (error); - - g_object_unref (mount_info->operation); - g_object_unref (mount_info->cancellable); - g_free (mount_info->virtual_root); - - g_free (mount_info); -} - -static GeditFileBrowserStoreResult -model_mount_root (GeditFileBrowserStore * model, gchar const * virtual_root) -{ - GFileInfo * info; - GError * error = NULL; - MountInfo * mount_info; - - info = g_file_query_info (model->priv->root->file, - G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NONE, - NULL, - &error); - - if (!info) { - if (error->code == G_IO_ERROR_NOT_MOUNTED) { - /* Try to mount it */ - FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable = g_cancellable_new (); - - mount_info = g_new(MountInfo, 1); - mount_info->model = model; - mount_info->virtual_root = g_strdup (virtual_root); - - /* FIXME: we should be setting the correct window */ - mount_info->operation = gtk_mount_operation_new (NULL); - mount_info->cancellable = g_object_ref (FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable); - - model_begin_loading (model, model->priv->root); - g_file_mount_enclosing_volume (model->priv->root->file, - G_MOUNT_MOUNT_NONE, - mount_info->operation, - mount_info->cancellable, - (GAsyncReadyCallback)mount_cb, - mount_info); - - model->priv->mount_info = mount_info; - return GEDIT_FILE_BROWSER_STORE_RESULT_MOUNTING; - } - else - { - handle_root_error (model, error); - } - - g_error_free (error); - } else { - g_object_unref (info); - - return model_root_mounted (model, virtual_root); - } - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -/* Public */ -GeditFileBrowserStore * -gedit_file_browser_store_new (gchar const *root) -{ - GeditFileBrowserStore *obj = - GEDIT_FILE_BROWSER_STORE (g_object_new - (GEDIT_TYPE_FILE_BROWSER_STORE, - NULL)); - - gedit_file_browser_store_set_root (obj, root); - return obj; -} - -void -gedit_file_browser_store_set_value (GeditFileBrowserStore * tree_model, - GtkTreeIter * iter, gint column, - GValue * value) -{ - gpointer data; - FileBrowserNode *node; - GtkTreePath *path; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (tree_model)); - g_return_if_fail (column == - GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM); - g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - data = g_value_get_object (value); - - if (data) - g_return_if_fail (GDK_IS_PIXBUF (data)); - - node = (FileBrowserNode *) (iter->user_data); - - if (node->emblem) - g_object_unref (node->emblem); - - if (data) - node->emblem = g_object_ref (GDK_PIXBUF (data)); - else - node->emblem = NULL; - - model_recomposite_icon (tree_model, iter); - - if (model_node_visibility (tree_model, node)) { - path = gedit_file_browser_store_get_path (GTK_TREE_MODEL (tree_model), - iter); - row_changed (tree_model, &path, iter); - gtk_tree_path_free (path); - } -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root (GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - g_return_val_if_fail (iter != NULL, - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - g_return_val_if_fail (iter->user_data != NULL, - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - model_clear (model, FALSE); - set_virtual_root_from_node (model, - (FileBrowserNode *) (iter->user_data)); - - return TRUE; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_from_string - (GeditFileBrowserStore * model, gchar const *root) { - GFile *file; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - file = g_file_new_for_uri (root); - if (file == NULL) { - g_warning ("Invalid uri (%s)", root); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - - /* Check if uri is already the virtual root */ - if (model->priv->virtual_root && - g_file_equal (model->priv->virtual_root->file, file)) { - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - - /* Check if uri is the root itself */ - if (g_file_equal (model->priv->root->file, file)) { - g_object_unref (file); - - /* Always clear the model before altering the nodes */ - model_clear (model, FALSE); - set_virtual_root_from_node (model, model->priv->root); - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; - } - - if (!g_file_has_prefix (file, model->priv->root->file)) { - gchar *str, *str1; - - str = g_file_get_parse_name (model->priv->root->file); - str1 = g_file_get_parse_name (file); - - g_warning - ("Virtual root (%s) is not below actual root (%s)", - str1, str); - - g_free (str); - g_free (str1); - - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_ERROR; - } - - set_virtual_root_from_file (model, file); - g_object_unref (file); - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_top (GeditFileBrowserStore * - model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - if (model->priv->virtual_root == model->priv->root) - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - - model_clear (model, FALSE); - set_virtual_root_from_node (model, model->priv->root); - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_up (GeditFileBrowserStore * - model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - if (model->priv->virtual_root == model->priv->root) - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - - model_clear (model, FALSE); - set_virtual_root_from_node (model, - model->priv->virtual_root->parent); - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -gboolean -gedit_file_browser_store_get_iter_virtual_root (GeditFileBrowserStore * - model, GtkTreeIter * iter) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - if (model->priv->virtual_root == NULL) - return FALSE; - - iter->user_data = model->priv->virtual_root; - return TRUE; -} - -gboolean -gedit_file_browser_store_get_iter_root (GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - if (model->priv->root == NULL) - return FALSE; - - iter->user_data = model->priv->root; - return TRUE; -} - -gboolean -gedit_file_browser_store_iter_equal (GeditFileBrowserStore * model, - GtkTreeIter * iter1, - GtkTreeIter * iter2) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (iter1 != NULL, FALSE); - g_return_val_if_fail (iter2 != NULL, FALSE); - g_return_val_if_fail (iter1->user_data != NULL, FALSE); - g_return_val_if_fail (iter2->user_data != NULL, FALSE); - - return (iter1->user_data == iter2->user_data); -} - -void -gedit_file_browser_store_cancel_mount_operation (GeditFileBrowserStore *store) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (store)); - - cancel_mount_operation (store); -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root_and_virtual_root (GeditFileBrowserStore * - model, - gchar const *root, - gchar const *virtual_root) -{ - GFile * file = NULL; - GFile * vfile = NULL; - FileBrowserNode * node; - gboolean equal = FALSE; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - if (root == NULL && model->priv->root == NULL) - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - - if (root != NULL) { - file = g_file_new_for_uri (root); - } - - if (root != NULL && model->priv->root != NULL) { - equal = g_file_equal (file, model->priv->root->file); - - if (equal && virtual_root == NULL) { - g_object_unref (file); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - } - - if (virtual_root) { - vfile = g_file_new_for_uri (virtual_root); - - if (equal && g_file_equal (vfile, model->priv->virtual_root->file)) { - if (file) - g_object_unref (file); - - g_object_unref (vfile); - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - } - - g_object_unref (vfile); - } - - /* make sure to cancel any previous mount operations */ - cancel_mount_operation (model); - - /* Always clear the model before altering the nodes */ - model_clear (model, TRUE); - file_browser_node_free (model, model->priv->root); - - model->priv->root = NULL; - model->priv->virtual_root = NULL; - - if (file != NULL) { - /* Create the root node */ - node = file_browser_node_dir_new (model, file, NULL); - - g_object_unref (file); - - model->priv->root = node; - return model_mount_root (model, virtual_root); - } else { - g_object_notify (G_OBJECT (model), "root"); - g_object_notify (G_OBJECT (model), "virtual-root"); - } - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root (GeditFileBrowserStore * model, - gchar const *root) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - return gedit_file_browser_store_set_root_and_virtual_root (model, - root, - NULL); -} - -gchar * -gedit_file_browser_store_get_root (GeditFileBrowserStore * model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), NULL); - - if (model->priv->root == NULL || model->priv->root->file == NULL) - return NULL; - else - return g_file_get_uri (model->priv->root->file); -} - -gchar * -gedit_file_browser_store_get_virtual_root (GeditFileBrowserStore * model) -{ - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), NULL); - - if (model->priv->virtual_root == NULL || model->priv->virtual_root->file == NULL) - return NULL; - else - return g_file_get_uri (model->priv->virtual_root->file); -} - -void -_gedit_file_browser_store_iter_expanded (GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - FileBrowserNode *node; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - node = (FileBrowserNode *) (iter->user_data); - - if (NODE_IS_DIR (node) && !NODE_LOADED (node)) { - /* Load it now */ - model_load_directory (model, node); - } -} - -void -_gedit_file_browser_store_iter_collapsed (GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - FileBrowserNode *node; - GSList *item; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model)); - g_return_if_fail (iter != NULL); - g_return_if_fail (iter->user_data != NULL); - - node = (FileBrowserNode *) (iter->user_data); - - if (NODE_IS_DIR (node) && NODE_LOADED (node)) { - /* Unload children of the children, keeping 1 depth in cache */ - - for (item = FILE_BROWSER_NODE_DIR (node)->children; item; - item = item->next) { - node = (FileBrowserNode *) (item->data); - - if (NODE_IS_DIR (node) && NODE_LOADED (node)) { - file_browser_node_unload (model, node, - TRUE); - model_check_dummy (model, node); - } - } - } -} - -GeditFileBrowserStoreFilterMode -gedit_file_browser_store_get_filter_mode (GeditFileBrowserStore * model) -{ - return model->priv->filter_mode; -} - -void -gedit_file_browser_store_set_filter_mode (GeditFileBrowserStore * model, - GeditFileBrowserStoreFilterMode - mode) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model)); - - if (model->priv->filter_mode == mode) - return; - - model->priv->filter_mode = mode; - model_refilter (model); - - g_object_notify (G_OBJECT (model), "filter-mode"); -} - -void -gedit_file_browser_store_set_filter_func (GeditFileBrowserStore * model, - GeditFileBrowserStoreFilterFunc - func, gpointer user_data) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model)); - - model->priv->filter_func = func; - model->priv->filter_user_data = user_data; - model_refilter (model); -} - -void -gedit_file_browser_store_refilter (GeditFileBrowserStore * model) -{ - model_refilter (model); -} - -GeditFileBrowserStoreFilterMode -gedit_file_browser_store_filter_mode_get_default (void) -{ - return GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; -} - -void -gedit_file_browser_store_refresh (GeditFileBrowserStore * model) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model)); - - if (model->priv->root == NULL || model->priv->virtual_root == NULL) - return; - - /* Clear the model */ - g_signal_emit (model, model_signals[BEGIN_REFRESH], 0); - file_browser_node_unload (model, model->priv->virtual_root, TRUE); - model_load_directory (model, model->priv->virtual_root); - g_signal_emit (model, model_signals[END_REFRESH], 0); -} - -static void -reparent_node (FileBrowserNode * node, gboolean reparent) -{ - FileBrowserNodeDir * dir; - GSList * child; - GFile * parent; - gchar * base; - - if (!node->file) { - return; - } - - if (reparent) { - parent = node->parent->file; - base = g_file_get_basename (node->file); - g_object_unref (node->file); - - node->file = g_file_get_child (parent, base); - g_free (base); - } - - if (NODE_IS_DIR (node)) { - dir = FILE_BROWSER_NODE_DIR (node); - - for (child = dir->children; child; child = child->next) { - reparent_node ((FileBrowserNode *)child->data, TRUE); - } - } -} - -gboolean -gedit_file_browser_store_rename (GeditFileBrowserStore * model, - GtkTreeIter * iter, - const gchar * new_name, - GError ** error) -{ - FileBrowserNode *node; - GFile * file; - GFile * parent; - GFile * previous; - GError * err = NULL; - gchar * olduri; - gchar * newuri; - GtkTreePath *path; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (iter->user_data != NULL, FALSE); - - node = (FileBrowserNode *) (iter->user_data); - - parent = g_file_get_parent (node->file); - g_return_val_if_fail (parent != NULL, FALSE); - - file = g_file_get_child (parent, new_name); - g_object_unref (parent); - - if (g_file_equal (node->file, file)) { - g_object_unref (file); - return TRUE; - } - - if (g_file_move (node->file, file, G_FILE_COPY_NONE, NULL, NULL, NULL, &err)) { - previous = node->file; - node->file = file; - - /* This makes sure the actual info for the node is requeried */ - file_browser_node_set_name (node); - file_browser_node_set_from_info (model, node, NULL, TRUE); - - reparent_node (node, FALSE); - - if (model_node_visibility (model, node)) { - path = gedit_file_browser_store_get_path_real (model, node); - row_changed (model, &path, iter); - gtk_tree_path_free (path); - - /* Reorder this item */ - model_resort_node (model, node); - } else { - g_object_unref (previous); - - if (error != NULL) - *error = g_error_new_literal (gedit_file_browser_store_error_quark (), - GEDIT_FILE_BROWSER_ERROR_RENAME, - _("The renamed file is currently filtered out. You need to adjust your filter settings to make the file visible")); - return FALSE; - } - - olduri = g_file_get_uri (previous); - newuri = g_file_get_uri (node->file); - - g_signal_emit (model, model_signals[RENAME], 0, olduri, newuri); - - g_object_unref (previous); - g_free (olduri); - g_free (newuri); - - return TRUE; - } else { - g_object_unref (file); - - if (err) { - if (error != NULL) { - *error = - g_error_new_literal - (gedit_file_browser_store_error_quark (), - GEDIT_FILE_BROWSER_ERROR_RENAME, - err->message); - } - - g_error_free (err); - } - - return FALSE; - } -} - -static void -async_data_free (AsyncData * data) -{ - g_object_unref (data->cancellable); - - g_list_foreach (data->files, (GFunc)g_object_unref, NULL); - g_list_free (data->files); - - if (!data->removed) - data->model->priv->async_handles = g_slist_remove (data->model->priv->async_handles, data); - - g_free (data); -} - -static gboolean -emit_no_trash (AsyncData * data) -{ - /* Emit the no trash error */ - gboolean ret; - - g_signal_emit (data->model, model_signals[NO_TRASH], 0, data->files, &ret); - return ret; -} - -typedef struct { - GeditFileBrowserStore * model; - GFile * file; -} IdleDelete; - -static gboolean -file_deleted (IdleDelete * data) -{ - FileBrowserNode * node; - node = model_find_node (data->model, NULL, data->file); - - if (node != NULL) - model_remove_node (data->model, node, NULL, TRUE); - - return FALSE; -} - -static gboolean -delete_files (GIOSchedulerJob * job, - GCancellable * cancellable, - AsyncData * data) -{ - GFile * file; - GError * error = NULL; - gboolean ret; - gint code; - IdleDelete delete; - - /* Check if our job is done */ - if (!data->iter) - return FALSE; - - /* Move a file to the trash */ - file = G_FILE (data->iter->data); - - if (data->trash) - ret = g_file_trash (file, cancellable, &error); - else - ret = g_file_delete (file, cancellable, &error); - - if (ret) { - delete.model = data->model; - delete.file = file; - - /* Remove the file from the model in the main loop */ - g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)file_deleted, &delete, NULL); - } else if (!ret && error) { - code = error->code; - g_error_free (error); - - if (data->trash && code == G_IO_ERROR_NOT_SUPPORTED) { - /* Trash is not supported on this system ... */ - if (g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)emit_no_trash, data, NULL)) - { - /* Changes this into a delete job */ - data->trash = FALSE; - data->iter = data->files; - - return TRUE; - } - - /* End the job */ - return FALSE; - } else if (code == G_IO_ERROR_CANCELLED) { - /* Job has been cancelled, just let the job end */ - return FALSE; - } - } - - /* Process the next item */ - data->iter = data->iter->next; - return TRUE; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_delete_all (GeditFileBrowserStore *model, - GList *rows, gboolean trash) -{ - FileBrowserNode * node; - AsyncData * data; - GList * files = NULL; - GList * row; - GtkTreeIter iter; - GtkTreePath * prev = NULL; - GtkTreePath * path; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - if (rows == NULL) - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - - /* First we sort the paths so that we can later on remove any - files/directories that are actually subfiles/directories of - a directory that's also deleted */ - rows = g_list_sort (g_list_copy (rows), (GCompareFunc)gtk_tree_path_compare); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) - continue; - - /* Skip if the current path is actually a descendant of the - previous path */ - if (prev != NULL && gtk_tree_path_is_descendant (path, prev)) - continue; - - prev = path; - node = (FileBrowserNode *)(iter.user_data); - files = g_list_prepend (files, g_object_ref (node->file)); - } - - data = g_new (AsyncData, 1); - - data->model = model; - data->cancellable = g_cancellable_new (); - data->files = files; - data->trash = trash; - data->iter = files; - data->removed = FALSE; - - model->priv->async_handles = - g_slist_prepend (model->priv->async_handles, data); - - g_io_scheduler_push_job ((GIOSchedulerJobFunc)delete_files, - data, - (GDestroyNotify)async_data_free, - G_PRIORITY_DEFAULT, - data->cancellable); - g_list_free (rows); - - return GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -GeditFileBrowserStoreResult -gedit_file_browser_store_delete (GeditFileBrowserStore * model, - GtkTreeIter * iter, gboolean trash) -{ - FileBrowserNode *node; - GList *rows = NULL; - GeditFileBrowserStoreResult result; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - g_return_val_if_fail (iter != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - g_return_val_if_fail (iter->user_data != NULL, GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE); - - node = (FileBrowserNode *) (iter->user_data); - - if (NODE_IS_DUMMY (node)) - return GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE; - - rows = g_list_append(NULL, gedit_file_browser_store_get_path_real (model, node)); - result = gedit_file_browser_store_delete_all (model, rows, trash); - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result; -} - -gboolean -gedit_file_browser_store_new_file (GeditFileBrowserStore * model, - GtkTreeIter * parent, - GtkTreeIter * iter) -{ - GFile * file; - GFileOutputStream * stream; - FileBrowserNodeDir *parent_node; - gboolean result = FALSE; - FileBrowserNode *node; - GError * error = NULL; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (parent != NULL, FALSE); - g_return_val_if_fail (parent->user_data != NULL, FALSE); - g_return_val_if_fail (NODE_IS_DIR - ((FileBrowserNode *) (parent->user_data)), - FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - parent_node = FILE_BROWSER_NODE_DIR (parent->user_data); - /* Translators: This is the default name of new files created by the file browser pane. */ - file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("file")); - - stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error); - - if (!stream) - { - g_signal_emit (model, model_signals[ERROR], 0, - GEDIT_FILE_BROWSER_ERROR_NEW_FILE, - error->message); - g_error_free (error); - } else { - g_object_unref (stream); - node = model_add_node_from_file (model, - (FileBrowserNode *)parent_node, - file, - NULL); - - if (model_node_visibility (model, node)) { - iter->user_data = node; - result = TRUE; - } else { - g_signal_emit (model, model_signals[ERROR], 0, - GEDIT_FILE_BROWSER_ERROR_NEW_FILE, - _ - ("The new file is currently filtered out. You need to adjust your filter settings to make the file visible")); - } - } - - g_object_unref (file); - return result; -} - -gboolean -gedit_file_browser_store_new_directory (GeditFileBrowserStore * model, - GtkTreeIter * parent, - GtkTreeIter * iter) -{ - GFile * file; - FileBrowserNodeDir *parent_node; - GError * error = NULL; - FileBrowserNode *node; - gboolean result = FALSE; - - g_return_val_if_fail (GEDIT_IS_FILE_BROWSER_STORE (model), FALSE); - g_return_val_if_fail (parent != NULL, FALSE); - g_return_val_if_fail (parent->user_data != NULL, FALSE); - g_return_val_if_fail (NODE_IS_DIR - ((FileBrowserNode *) (parent->user_data)), - FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - parent_node = FILE_BROWSER_NODE_DIR (parent->user_data); - /* Translators: This is the default name of new directories created by the file browser pane. */ - file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("directory")); - - if (!g_file_make_directory (file, NULL, &error)) { - g_signal_emit (model, model_signals[ERROR], 0, - GEDIT_FILE_BROWSER_ERROR_NEW_DIRECTORY, - error->message); - g_error_free (error); - } else { - node = model_add_node_from_file (model, - (FileBrowserNode *)parent_node, - file, - NULL); - - if (model_node_visibility (model, node)) { - iter->user_data = node; - result = TRUE; - } else { - g_signal_emit (model, model_signals[ERROR], 0, - GEDIT_FILE_BROWSER_ERROR_NEW_FILE, - _ - ("The new directory is currently filtered out. You need to adjust your filter settings to make the directory visible")); - } - } - - g_object_unref (file); - return result; -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-store.h b/plugins/filebrowser/gedit-file-browser-store.h deleted file mode 100755 index f31da327..00000000 --- a/plugins/filebrowser/gedit-file-browser-store.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * gedit-file-browser-store.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_STORE_H__ -#define __GEDIT_FILE_BROWSER_STORE_H__ - -#include - -G_BEGIN_DECLS -#define GEDIT_TYPE_FILE_BROWSER_STORE (gedit_file_browser_store_get_type ()) -#define GEDIT_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStore)) -#define GEDIT_FILE_BROWSER_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStore const)) -#define GEDIT_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStoreClass)) -#define GEDIT_IS_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_STORE)) -#define GEDIT_IS_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_STORE)) -#define GEDIT_FILE_BROWSER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_STORE, GeditFileBrowserStoreClass)) - -typedef enum -{ - GEDIT_FILE_BROWSER_STORE_COLUMN_ICON = 0, - GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, - GEDIT_FILE_BROWSER_STORE_COLUMN_EMBLEM, - GEDIT_FILE_BROWSER_STORE_COLUMN_NUM -} GeditFileBrowserStoreColumn; - -typedef enum -{ - GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY = 1 << 0, - GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN = 1 << 1, - GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT = 1 << 2, - GEDIT_FILE_BROWSER_STORE_FLAG_LOADED = 1 << 3, - GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED = 1 << 4, - GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY = 1 << 5 -} GeditFileBrowserStoreFlag; - -typedef enum -{ - GEDIT_FILE_BROWSER_STORE_RESULT_OK, - GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE, - GEDIT_FILE_BROWSER_STORE_RESULT_ERROR, - GEDIT_FILE_BROWSER_STORE_RESULT_NO_TRASH, - GEDIT_FILE_BROWSER_STORE_RESULT_MOUNTING, - GEDIT_FILE_BROWSER_STORE_RESULT_NUM -} GeditFileBrowserStoreResult; - -typedef enum -{ - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_NONE = 0, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN = 1 << 0, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY = 1 << 1 -} GeditFileBrowserStoreFilterMode; - -#define FILE_IS_DIR(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY) -#define FILE_IS_HIDDEN(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_HIDDEN) -#define FILE_IS_TEXT(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_TEXT) -#define FILE_LOADED(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_LOADED) -#define FILE_IS_FILTERED(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_FILTERED) -#define FILE_IS_DUMMY(flags) (flags & GEDIT_FILE_BROWSER_STORE_FLAG_IS_DUMMY) - -typedef struct _GeditFileBrowserStore GeditFileBrowserStore; -typedef struct _GeditFileBrowserStoreClass GeditFileBrowserStoreClass; -typedef struct _GeditFileBrowserStorePrivate GeditFileBrowserStorePrivate; - -typedef gboolean (*GeditFileBrowserStoreFilterFunc) (GeditFileBrowserStore - * model, - GtkTreeIter * iter, - gpointer user_data); - -struct _GeditFileBrowserStore -{ - GObject parent; - - GeditFileBrowserStorePrivate *priv; -}; - -struct _GeditFileBrowserStoreClass { - GObjectClass parent_class; - - /* Signals */ - void (*begin_loading) (GeditFileBrowserStore * model, - GtkTreeIter * iter); - void (*end_loading) (GeditFileBrowserStore * model, - GtkTreeIter * iter); - void (*error) (GeditFileBrowserStore * model, - guint code, - gchar * message); - gboolean (*no_trash) (GeditFileBrowserStore * model, - GList * files); - void (*rename) (GeditFileBrowserStore * model, - const gchar * olduri, - const gchar * newuri); - void (*begin_refresh) (GeditFileBrowserStore * model); - void (*end_refresh) (GeditFileBrowserStore * model); - void (*unload) (GeditFileBrowserStore * model, - const gchar * uri); -}; - -GType gedit_file_browser_store_get_type (void) G_GNUC_CONST; -GType gedit_file_browser_store_register_type (GTypeModule * module); - -GeditFileBrowserStore *gedit_file_browser_store_new (gchar const *root); - -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root_and_virtual_root (GeditFileBrowserStore * model, - gchar const *root, - gchar const *virtual_root); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_root (GeditFileBrowserStore * model, - gchar const *root); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root (GeditFileBrowserStore * model, - GtkTreeIter * iter); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_from_string (GeditFileBrowserStore * model, - gchar const *root); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_up (GeditFileBrowserStore * model); -GeditFileBrowserStoreResult -gedit_file_browser_store_set_virtual_root_top (GeditFileBrowserStore * model); - -gboolean -gedit_file_browser_store_get_iter_virtual_root (GeditFileBrowserStore * model, - GtkTreeIter * iter); -gboolean gedit_file_browser_store_get_iter_root (GeditFileBrowserStore * model, - GtkTreeIter * iter); -gchar * gedit_file_browser_store_get_root (GeditFileBrowserStore * model); -gchar * gedit_file_browser_store_get_virtual_root (GeditFileBrowserStore * model); - -gboolean gedit_file_browser_store_iter_equal (GeditFileBrowserStore * model, - GtkTreeIter * iter1, - GtkTreeIter * iter2); - -void gedit_file_browser_store_set_value (GeditFileBrowserStore * tree_model, - GtkTreeIter * iter, - gint column, - GValue * value); - -void _gedit_file_browser_store_iter_expanded (GeditFileBrowserStore * model, - GtkTreeIter * iter); -void _gedit_file_browser_store_iter_collapsed (GeditFileBrowserStore * model, - GtkTreeIter * iter); - -GeditFileBrowserStoreFilterMode -gedit_file_browser_store_get_filter_mode (GeditFileBrowserStore * model); -void gedit_file_browser_store_set_filter_mode (GeditFileBrowserStore * model, - GeditFileBrowserStoreFilterMode mode); -void gedit_file_browser_store_set_filter_func (GeditFileBrowserStore * model, - GeditFileBrowserStoreFilterFunc func, - gpointer user_data); -void gedit_file_browser_store_refilter (GeditFileBrowserStore * model); -GeditFileBrowserStoreFilterMode -gedit_file_browser_store_filter_mode_get_default (void); - -void gedit_file_browser_store_refresh (GeditFileBrowserStore * model); -gboolean gedit_file_browser_store_rename (GeditFileBrowserStore * model, - GtkTreeIter * iter, - gchar const *new_name, - GError ** error); -GeditFileBrowserStoreResult -gedit_file_browser_store_delete (GeditFileBrowserStore * model, - GtkTreeIter * iter, - gboolean trash); -GeditFileBrowserStoreResult -gedit_file_browser_store_delete_all (GeditFileBrowserStore * model, - GList *rows, - gboolean trash); - -gboolean gedit_file_browser_store_new_file (GeditFileBrowserStore * model, - GtkTreeIter * parent, - GtkTreeIter * iter); -gboolean gedit_file_browser_store_new_directory (GeditFileBrowserStore * model, - GtkTreeIter * parent, - GtkTreeIter * iter); - -void gedit_file_browser_store_cancel_mount_operation (GeditFileBrowserStore *store); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_STORE_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-utils.c b/plugins/filebrowser/gedit-file-browser-utils.c deleted file mode 100755 index d8f4028a..00000000 --- a/plugins/filebrowser/gedit-file-browser-utils.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * gedit-file-bookmarks-store.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include "gedit-file-browser-utils.h" -#include - -static GdkPixbuf * -process_icon_pixbuf (GdkPixbuf * pixbuf, - gchar const * name, - gint size, - GError * error) -{ - GdkPixbuf * scale; - - if (error != NULL) { - g_warning ("Could not load theme icon %s: %s", - name, - error->message); - g_error_free (error); - } - - if (pixbuf && gdk_pixbuf_get_width (pixbuf) > size) { - scale = gdk_pixbuf_scale_simple (pixbuf, - size, - size, - GDK_INTERP_BILINEAR); - g_object_unref (pixbuf); - pixbuf = scale; - } - - return pixbuf; -} - -GdkPixbuf * -gedit_file_browser_utils_pixbuf_from_theme (gchar const * name, - GtkIconSize size) -{ - gint width; - GError *error = NULL; - GdkPixbuf *pixbuf; - - gtk_icon_size_lookup (size, &width, NULL); - - pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), - name, - width, - 0, - &error); - - pixbuf = process_icon_pixbuf (pixbuf, name, width, error); - - return pixbuf; -} - -GdkPixbuf * -gedit_file_browser_utils_pixbuf_from_icon (GIcon * icon, - GtkIconSize size) -{ - GdkPixbuf * ret = NULL; - GtkIconTheme *theme; - GtkIconInfo *info; - gint width; - - if (!icon) - return NULL; - - theme = gtk_icon_theme_get_default (); - gtk_icon_size_lookup (size, &width, NULL); - - info = gtk_icon_theme_lookup_by_gicon (theme, - icon, - width, - GTK_ICON_LOOKUP_USE_BUILTIN); - - if (!info) - return NULL; - - ret = gtk_icon_info_load_icon (info, NULL); - gtk_icon_info_free (info); - - return ret; -} - -GdkPixbuf * -gedit_file_browser_utils_pixbuf_from_file (GFile * file, - GtkIconSize size) -{ - GIcon * icon; - GFileInfo * info; - GdkPixbuf * ret = NULL; - - info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_ICON, - G_FILE_QUERY_INFO_NONE, - NULL, - NULL); - - if (!info) - return NULL; - - icon = g_file_info_get_icon (info); - if (icon != NULL) - ret = gedit_file_browser_utils_pixbuf_from_icon (icon, size); - - g_object_unref (info); - - return ret; -} - -gchar * -gedit_file_browser_utils_file_basename (GFile * file) -{ - gchar *uri; - gchar *ret; - - uri = g_file_get_uri (file); - ret = gedit_file_browser_utils_uri_basename (uri); - g_free (uri); - - return ret; -} - -gchar * -gedit_file_browser_utils_uri_basename (gchar const * uri) -{ - return gedit_utils_basename_for_display (uri); -} - -gboolean -gedit_file_browser_utils_confirmation_dialog (GeditWindow * window, - GtkMessageType type, - gchar const *message, - gchar const *secondary, - gchar const * button_stock, - gchar const * button_label) -{ - GtkWidget *dlg; - gint ret; - GtkWidget *button; - - dlg = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT, - type, - GTK_BUTTONS_NONE, "%s", message); - - if (secondary) - gtk_message_dialog_format_secondary_text - (GTK_MESSAGE_DIALOG (dlg), "%s", secondary); - - /* Add a cancel button */ - button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - gtk_widget_show (button); - - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - GTK_RESPONSE_CANCEL); - - /* Add custom button */ - button = gtk_button_new_from_stock (button_stock); - - if (button_label) { - gtk_button_set_use_stock (GTK_BUTTON (button), FALSE); - gtk_button_set_label (GTK_BUTTON (button), button_label); - } - - gtk_widget_show (button); - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - GTK_RESPONSE_OK); - - ret = gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); - - return (ret == GTK_RESPONSE_OK); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-utils.h b/plugins/filebrowser/gedit-file-browser-utils.h deleted file mode 100755 index fc9acbce..00000000 --- a/plugins/filebrowser/gedit-file-browser-utils.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __GEDIT_FILE_BROWSER_UTILS_H__ -#define __GEDIT_FILE_BROWSER_UTILS_H__ - -#include -#include - -GdkPixbuf *gedit_file_browser_utils_pixbuf_from_theme (gchar const *name, - GtkIconSize size); - -GdkPixbuf *gedit_file_browser_utils_pixbuf_from_icon (GIcon * icon, - GtkIconSize size); -GdkPixbuf *gedit_file_browser_utils_pixbuf_from_file (GFile * file, - GtkIconSize size); - -gchar * gedit_file_browser_utils_file_basename (GFile * file); -gchar * gedit_file_browser_utils_uri_basename (gchar const * uri); - -gboolean gedit_file_browser_utils_confirmation_dialog (GeditWindow * window, - GtkMessageType type, - gchar const *message, - gchar const *secondary, - gchar const * button_stock, - gchar const * button_label); - -#endif /* __GEDIT_FILE_BROWSER_UTILS_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-view.c b/plugins/filebrowser/gedit-file-browser-view.c deleted file mode 100755 index 05733da1..00000000 --- a/plugins/filebrowser/gedit-file-browser-view.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* - * gedit-file-browser-view.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include - -#include "gedit-file-browser-store.h" -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-view.h" -#include "gedit-file-browser-marshal.h" -#include "gedit-file-browser-enum-types.h" - -#define GEDIT_FILE_BROWSER_VIEW_GET_PRIVATE(object)( \ - G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewPrivate)) - -struct _GeditFileBrowserViewPrivate -{ - GtkTreeViewColumn *column; - GtkCellRenderer *pixbuf_renderer; - GtkCellRenderer *text_renderer; - - GtkTreeModel *model; - GtkTreeRowReference *editable; - - GdkCursor *busy_cursor; - - /* CLick policy */ - GeditFileBrowserViewClickPolicy click_policy; - GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */ - GtkTreePath *hover_path; - GdkCursor *hand_cursor; - gboolean ignore_release; - gboolean selected_on_button_down; - gint drag_button; - gboolean drag_started; - - gboolean restore_expand_state; - gboolean is_refresh; - GHashTable * expand_state; -}; - -/* Properties */ -enum -{ - PROP_0, - - PROP_CLICK_POLICY, - PROP_RESTORE_EXPAND_STATE -}; - -/* Signals */ -enum -{ - ERROR, - FILE_ACTIVATED, - DIRECTORY_ACTIVATED, - BOOKMARK_ACTIVATED, - NUM_SIGNALS -}; - -static guint signals[NUM_SIGNALS] = { 0 }; - -static const GtkTargetEntry drag_source_targets[] = { - { "text/uri-list", 0, 0 } -}; - -GEDIT_PLUGIN_DEFINE_TYPE (GeditFileBrowserView, gedit_file_browser_view, - GTK_TYPE_TREE_VIEW) - -static void on_cell_edited (GtkCellRendererText * cell, - gchar * path, - gchar * new_text, - GeditFileBrowserView * tree_view); - -static void on_begin_refresh (GeditFileBrowserStore * model, - GeditFileBrowserView * view); -static void on_end_refresh (GeditFileBrowserStore * model, - GeditFileBrowserView * view); - -static void on_unload (GeditFileBrowserStore * model, - gchar const * uri, - GeditFileBrowserView * view); - -static void on_row_inserted (GeditFileBrowserStore * model, - GtkTreePath * path, - GtkTreeIter * iter, - GeditFileBrowserView * view); - -static void -gedit_file_browser_view_finalize (GObject * object) -{ - GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW(object); - - if (obj->priv->hand_cursor) - gdk_cursor_unref(obj->priv->hand_cursor); - - if (obj->priv->hover_path) - gtk_tree_path_free (obj->priv->hover_path); - - if (obj->priv->expand_state) - { - g_hash_table_destroy (obj->priv->expand_state); - obj->priv->expand_state = NULL; - } - - gdk_cursor_unref (obj->priv->busy_cursor); - - G_OBJECT_CLASS (gedit_file_browser_view_parent_class)-> - finalize (object); -} - -static void -add_expand_state (GeditFileBrowserView * view, - gchar const * uri) -{ - GFile * file; - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - - if (view->priv->expand_state) - g_hash_table_insert (view->priv->expand_state, file, file); - else - g_object_unref (file); -} - -static void -remove_expand_state (GeditFileBrowserView * view, - gchar const * uri) -{ - GFile * file; - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - - if (view->priv->expand_state) - g_hash_table_remove (view->priv->expand_state, file); - - g_object_unref (file); -} - -static void -row_expanded (GtkTreeView * tree_view, - GtkTreeIter * iter, - GtkTreePath * path) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (tree_view); - gchar * uri; - - if (GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_expanded) - GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_expanded (tree_view, iter, path); - - if (!GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - return; - - if (view->priv->restore_expand_state) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - add_expand_state (view, uri); - g_free (uri); - } - - _gedit_file_browser_store_iter_expanded (GEDIT_FILE_BROWSER_STORE (view->priv->model), - iter); -} - -static void -row_collapsed (GtkTreeView * tree_view, - GtkTreeIter * iter, - GtkTreePath * path) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (tree_view); - gchar * uri; - - if (GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_collapsed) - GTK_TREE_VIEW_CLASS (gedit_file_browser_view_parent_class)->row_collapsed (tree_view, iter, path); - - if (!GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - return; - - if (view->priv->restore_expand_state) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - remove_expand_state (view, uri); - g_free (uri); - } - - _gedit_file_browser_store_iter_collapsed (GEDIT_FILE_BROWSER_STORE (view->priv->model), - iter); -} - -static gboolean -leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget); - - if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE && - view->priv->hover_path != NULL) { - gtk_tree_path_free (view->priv->hover_path); - view->priv->hover_path = NULL; - } - - // Chainup - return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->leave_notify_event (widget, event); -} - -static gboolean -enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget); - - if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { - if (view->priv->hover_path != NULL) - gtk_tree_path_free (view->priv->hover_path); - - gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - event->x, event->y, - &view->priv->hover_path, - NULL, NULL, NULL); - - if (view->priv->hover_path != NULL) - gdk_window_set_cursor (gtk_widget_get_window (widget), - view->priv->hand_cursor); - } - - // Chainup - return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->enter_notify_event (widget, event); -} - -static gboolean -motion_notify_event (GtkWidget * widget, - GdkEventMotion * event) -{ - GtkTreePath *old_hover_path; - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget); - - if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { - old_hover_path = view->priv->hover_path; - gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - event->x, event->y, - &view->priv->hover_path, - NULL, NULL, NULL); - - if ((old_hover_path != NULL) != (view->priv->hover_path != NULL)) { - if (view->priv->hover_path != NULL) - gdk_window_set_cursor (gtk_widget_get_window (widget), - view->priv->hand_cursor); - else - gdk_window_set_cursor (gtk_widget_get_window (widget), - NULL); - } - - if (old_hover_path != NULL) - gtk_tree_path_free (old_hover_path); - } - - // Chainup - return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->motion_notify_event (widget, event); -} - -static void -set_click_policy_property (GeditFileBrowserView *obj, - GeditFileBrowserViewClickPolicy click_policy) -{ - GtkTreeIter iter; - GdkDisplay *display; - GdkWindow *win; - - obj->priv->click_policy = click_policy; - - if (click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { - if (obj->priv->hand_cursor == NULL) - obj->priv->hand_cursor = gdk_cursor_new(GDK_HAND2); - } else if (click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE) { - if (obj->priv->hover_path != NULL) { - if (gtk_tree_model_get_iter (GTK_TREE_MODEL (obj->priv->model), - &iter, obj->priv->hover_path)) - gtk_tree_model_row_changed (GTK_TREE_MODEL (obj->priv->model), - obj->priv->hover_path, &iter); - - gtk_tree_path_free (obj->priv->hover_path); - obj->priv->hover_path = NULL; - } - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (obj))) { - win = gtk_widget_get_window (GTK_WIDGET (obj)); - gdk_window_set_cursor (win, NULL); - - display = gtk_widget_get_display (GTK_WIDGET (obj)); - - if (display != NULL) - gdk_display_flush (display); - } - - if (obj->priv->hand_cursor) { - gdk_cursor_unref (obj->priv->hand_cursor); - obj->priv->hand_cursor = NULL; - } - } -} - -static void -directory_activated (GeditFileBrowserView *view, - GtkTreeIter *iter) -{ - gedit_file_browser_store_set_virtual_root (GEDIT_FILE_BROWSER_STORE (view->priv->model), iter); -} - -static void -activate_selected_files (GeditFileBrowserView *view) { - GtkTreeView *tree_view = GTK_TREE_VIEW (view); - GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); - GList *rows, *row; - GtkTreePath *directory = NULL; - GtkTreePath *path; - GtkTreeIter iter; - GeditFileBrowserStoreFlag flags; - - rows = gtk_tree_selection_get_selected_rows (selection, &view->priv->model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - /* Get iter from path */ - if (!gtk_tree_model_get_iter (view->priv->model, &iter, path)) - continue; - - gtk_tree_model_get (view->priv->model, &iter, GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, -1); - - if (FILE_IS_DIR (flags)) { - if (directory == NULL) - directory = path; - - } else if (!FILE_IS_DUMMY (flags)) { - g_signal_emit (view, signals[FILE_ACTIVATED], 0, &iter); - } - } - - if (directory != NULL) { - if (gtk_tree_model_get_iter (view->priv->model, &iter, directory)) - g_signal_emit (view, signals[DIRECTORY_ACTIVATED], 0, &iter); - } - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); -} - -static void -activate_selected_bookmark (GeditFileBrowserView *view) { - GtkTreeView *tree_view = GTK_TREE_VIEW (view); - GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); - GtkTreeIter iter; - - if (gtk_tree_selection_get_selected (selection, &view->priv->model, &iter)) - g_signal_emit (view, signals[BOOKMARK_ACTIVATED], 0, &iter); -} - -static void -activate_selected_items (GeditFileBrowserView *view) -{ - if (GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - activate_selected_files (view); - else if (GEDIT_IS_FILE_BOOKMARKS_STORE (view->priv->model)) - activate_selected_bookmark (view); -} - -static void -toggle_hidden_filter (GeditFileBrowserView *view) -{ - GeditFileBrowserStoreFilterMode mode; - - if (GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - { - mode = gedit_file_browser_store_get_filter_mode - (GEDIT_FILE_BROWSER_STORE (view->priv->model)); - mode ^= GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; - gedit_file_browser_store_set_filter_mode - (GEDIT_FILE_BROWSER_STORE (view->priv->model), mode); - } -} - -static gboolean -button_event_modifies_selection (GdkEventButton *event) -{ - return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0; -} - -static void -drag_begin (GtkWidget *widget, - GdkDragContext *context) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget); - - view->priv->drag_button = 0; - view->priv->drag_started = TRUE; - - /* Chain up */ - GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->drag_begin (widget, context); -} - -static void -did_not_drag (GeditFileBrowserView *view, - GdkEventButton *event) -{ - GtkTreeView *tree_view; - GtkTreeSelection *selection; - GtkTreePath *path; - - tree_view = GTK_TREE_VIEW (view); - selection = gtk_tree_view_get_selection (tree_view); - - if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, - &path, NULL, NULL, NULL)) { - if ((view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) - && !button_event_modifies_selection(event) - && (event->button == 1 || event->button == 2)) { - /* Activate all selected items, and leave them selected */ - activate_selected_items (view); - } else if ((event->button == 1 || event->button == 2) - && ((event->state & GDK_CONTROL_MASK) != 0 || - (event->state & GDK_SHIFT_MASK) == 0) - && view->priv->selected_on_button_down) { - if (!button_event_modifies_selection (event)) { - gtk_tree_selection_unselect_all (selection); - gtk_tree_selection_select_path (selection, path); - } else { - gtk_tree_selection_unselect_path (selection, path); - } - } - - gtk_tree_path_free (path); - } -} - -static gboolean -button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - GeditFileBrowserView *view = GEDIT_FILE_BROWSER_VIEW (widget); - - if (event->button == view->priv->drag_button) { - view->priv->drag_button = 0; - - if (!view->priv->drag_started && - !view->priv->ignore_release) - did_not_drag (view, event); - } - - /* Chain up */ - return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->button_release_event (widget, event); -} - -static gboolean -button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - int double_click_time; - static int click_count = 0; - static guint32 last_click_time = 0; - GeditFileBrowserView *view; - GtkTreeView *tree_view; - GtkTreeSelection *selection; - GtkTreePath *path; - int expander_size; - int horizontal_separator; - gboolean on_expander; - gboolean call_parent; - gboolean selected; - GtkWidgetClass *widget_parent = GTK_WIDGET_CLASS(gedit_file_browser_view_parent_class); - - tree_view = GTK_TREE_VIEW (widget); - view = GEDIT_FILE_BROWSER_VIEW (widget); - selection = gtk_tree_view_get_selection (tree_view); - - /* Get double click time */ - g_object_get (G_OBJECT (gtk_widget_get_settings (widget)), - "gtk-double-click-time", &double_click_time, - NULL); - - /* Determine click count */ - if (event->time - last_click_time < double_click_time) - click_count++; - else - click_count = 0; - - last_click_time = event->time; - - /* Ignore double click if we are in single click mode */ - if (view->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE && - click_count >= 2) { - return TRUE; - } - - view->priv->ignore_release = FALSE; - call_parent = TRUE; - - if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, - &path, NULL, NULL, NULL)) { - /* Keep track of path of last click so double clicks only happen - * on the same item */ - if ((event->button == 1 || event->button == 2) && - event->type == GDK_BUTTON_PRESS) { - if (view->priv->double_click_path[1]) - gtk_tree_path_free (view->priv->double_click_path[1]); - - view->priv->double_click_path[1] = view->priv->double_click_path[0]; - view->priv->double_click_path[0] = gtk_tree_path_copy (path); - } - - if (event->type == GDK_2BUTTON_PRESS) { - if (view->priv->double_click_path[1] && - gtk_tree_path_compare (view->priv->double_click_path[0], view->priv->double_click_path[1]) == 0) - activate_selected_items (view); - - /* Chain up */ - widget_parent->button_press_event (widget, event); - } else { - /* We're going to filter out some situations where - * we can't let the default code run because all - * but one row would be would be deselected. We don't - * want that; we want the right click menu or single - * click to apply to everything that's currently selected. */ - selected = gtk_tree_selection_path_is_selected (selection, path); - - if (event->button == 3 && selected) - call_parent = FALSE; - - if ((event->button == 1 || event->button == 2) && - ((event->state & GDK_CONTROL_MASK) != 0 || - (event->state & GDK_SHIFT_MASK) == 0)) { - gtk_widget_style_get (widget, - "expander-size", &expander_size, - "horizontal-separator", &horizontal_separator, - NULL); - on_expander = (event->x <= horizontal_separator / 2 + - gtk_tree_path_get_depth (path) * expander_size); - - view->priv->selected_on_button_down = selected; - - if (selected) { - call_parent = on_expander || gtk_tree_selection_count_selected_rows (selection) == 1; - view->priv->ignore_release = call_parent && view->priv->click_policy != GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; - } else if ((event->state & GDK_CONTROL_MASK) != 0) { - call_parent = FALSE; - gtk_tree_selection_select_path (selection, path); - } else { - view->priv->ignore_release = on_expander; - } - } - - if (call_parent) { - /* Chain up */ - widget_parent->button_press_event (widget, event); - } else if (selected) { - gtk_widget_grab_focus (widget); - } - - if ((event->button == 1 || event->button == 2) && - event->type == GDK_BUTTON_PRESS) { - view->priv->drag_started = FALSE; - view->priv->drag_button = event->button; - } - } - - gtk_tree_path_free (path); - } else { - if ((event->button == 1 || event->button == 2) && - event->type == GDK_BUTTON_PRESS) { - if (view->priv->double_click_path[1]) - gtk_tree_path_free (view->priv->double_click_path[1]); - - view->priv->double_click_path[1] = view->priv->double_click_path[0]; - view->priv->double_click_path[0] = NULL; - } - - gtk_tree_selection_unselect_all (selection); - /* Chain up */ - widget_parent->button_press_event (widget, event); - } - - /* We already chained up if nescessary, so just return TRUE */ - return TRUE; -} - -static gboolean -key_press_event (GtkWidget *widget, - GdkEventKey *event) -{ - GeditFileBrowserView *view; - guint modifiers; - gboolean handled; - - view = GEDIT_FILE_BROWSER_VIEW (widget); - handled = FALSE; - - modifiers = gtk_accelerator_get_default_mod_mask (); - - switch (event->keyval) { - case GDK_space: - if (event->state & GDK_CONTROL_MASK) { - handled = FALSE; - break; - } - if (!GTK_WIDGET_HAS_FOCUS (widget)) { - handled = FALSE; - break; - } - - activate_selected_items (view); - handled = TRUE; - break; - - case GDK_Return: - case GDK_KP_Enter: - activate_selected_items (view); - handled = TRUE; - break; - - case GDK_h: - if ((event->state & modifiers) == GDK_CONTROL_MASK) { - toggle_hidden_filter (view); - handled = TRUE; - break; - } - - default: - handled = FALSE; - } - - /* Chain up */ - if (!handled) - return GTK_WIDGET_CLASS (gedit_file_browser_view_parent_class)->key_press_event (widget, event); - - return TRUE; -} - -static void -fill_expand_state (GeditFileBrowserView * view, GtkTreeIter * iter) -{ - GtkTreePath * path; - GtkTreeIter child; - gchar * uri; - - if (!gtk_tree_model_iter_has_child (view->priv->model, iter)) - return; - - path = gtk_tree_model_get_path (view->priv->model, iter); - - if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), path)) - { - gtk_tree_model_get (view->priv->model, - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - add_expand_state (view, uri); - g_free (uri); - } - - if (gtk_tree_model_iter_children (view->priv->model, &child, iter)) - { - do { - fill_expand_state (view, &child); - } while (gtk_tree_model_iter_next (view->priv->model, &child)); - } - - gtk_tree_path_free (path); -} - -static void -uninstall_restore_signals (GeditFileBrowserView * tree_view, - GtkTreeModel * model) -{ - g_signal_handlers_disconnect_by_func (model, - on_begin_refresh, - tree_view); - - g_signal_handlers_disconnect_by_func (model, - on_end_refresh, - tree_view); - - g_signal_handlers_disconnect_by_func (model, - on_unload, - tree_view); - - g_signal_handlers_disconnect_by_func (model, - on_row_inserted, - tree_view); -} - -static void -install_restore_signals (GeditFileBrowserView * tree_view, - GtkTreeModel * model) -{ - g_signal_connect (model, - "begin-refresh", - G_CALLBACK (on_begin_refresh), - tree_view); - - g_signal_connect (model, - "end-refresh", - G_CALLBACK (on_end_refresh), - tree_view); - - g_signal_connect (model, - "unload", - G_CALLBACK (on_unload), - tree_view); - - g_signal_connect_after (model, - "row-inserted", - G_CALLBACK (on_row_inserted), - tree_view); -} - -static void -set_restore_expand_state (GeditFileBrowserView * view, - gboolean state) -{ - if (state == view->priv->restore_expand_state) - return; - - if (view->priv->expand_state) - { - g_hash_table_destroy (view->priv->expand_state); - view->priv->expand_state = NULL; - } - - if (state) - { - view->priv->expand_state = g_hash_table_new_full (g_file_hash, - (GEqualFunc)g_file_equal, - g_object_unref, - NULL); - - if (view->priv->model && GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - { - fill_expand_state (view, NULL); - - install_restore_signals (view, view->priv->model); - } - } - else if (view->priv->model && GEDIT_IS_FILE_BROWSER_STORE (view->priv->model)) - { - uninstall_restore_signals (view, view->priv->model); - } - - view->priv->restore_expand_state = state; -} - -static void -get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (object); - - switch (prop_id) - { - case PROP_CLICK_POLICY: - g_value_set_enum (value, obj->priv->click_policy); - break; - case PROP_RESTORE_EXPAND_STATE: - g_value_set_boolean (value, obj->priv->restore_expand_state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserView *obj = GEDIT_FILE_BROWSER_VIEW (object); - - switch (prop_id) - { - case PROP_CLICK_POLICY: - set_click_policy_property (obj, g_value_get_enum (value)); - break; - case PROP_RESTORE_EXPAND_STATE: - set_restore_expand_state (obj, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_file_browser_view_class_init (GeditFileBrowserViewClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkTreeViewClass *tree_view_class = GTK_TREE_VIEW_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = gedit_file_browser_view_finalize; - object_class->get_property = get_property; - object_class->set_property = set_property; - - /* Event handlers */ - widget_class->motion_notify_event = motion_notify_event; - widget_class->enter_notify_event = enter_notify_event; - widget_class->leave_notify_event = leave_notify_event; - widget_class->button_press_event = button_press_event; - widget_class->button_release_event = button_release_event; - widget_class->drag_begin = drag_begin; - widget_class->key_press_event = key_press_event; - - /* Tree view handlers */ - tree_view_class->row_expanded = row_expanded; - tree_view_class->row_collapsed = row_collapsed; - - /* Default handlers */ - klass->directory_activated = directory_activated; - - g_object_class_install_property (object_class, PROP_CLICK_POLICY, - g_param_spec_enum ("click-policy", - "Click Policy", - "The click policy", - GEDIT_TYPE_FILE_BROWSER_VIEW_CLICK_POLICY, - GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, PROP_RESTORE_EXPAND_STATE, - g_param_spec_boolean ("restore-expand-state", - "Restore Expand State", - "Restore expanded state of loaded directories", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserViewClass, - error), NULL, NULL, - gedit_file_browser_marshal_VOID__UINT_STRING, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); - signals[FILE_ACTIVATED] = - g_signal_new ("file-activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserViewClass, - file_activated), NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); - signals[DIRECTORY_ACTIVATED] = - g_signal_new ("directory-activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserViewClass, - directory_activated), NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); - signals[BOOKMARK_ACTIVATED] = - g_signal_new ("bookmark-activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserViewClass, - bookmark_activated), NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserViewPrivate)); -} - -static void -cell_data_cb (GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, - GtkTreeModel * tree_model, GtkTreeIter * iter, - GeditFileBrowserView * obj) -{ - GtkTreePath *path; - PangoUnderline underline = PANGO_UNDERLINE_NONE; - gboolean editable = FALSE; - - path = gtk_tree_model_get_path (tree_model, iter); - - if (obj->priv->click_policy == GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { - if (obj->priv->hover_path != NULL && - gtk_tree_path_compare (path, obj->priv->hover_path) == 0) - underline = PANGO_UNDERLINE_SINGLE; - } - - if (GEDIT_IS_FILE_BROWSER_STORE (tree_model)) - { - if (obj->priv->editable != NULL && - gtk_tree_row_reference_valid (obj->priv->editable)) - { - GtkTreePath *edpath = gtk_tree_row_reference_get_path (obj->priv->editable); - - editable = edpath && gtk_tree_path_compare (path, edpath) == 0; - } - } - - gtk_tree_path_free (path); - g_object_set (cell, "editable", editable, "underline", underline, NULL); -} - -static void -gedit_file_browser_view_init (GeditFileBrowserView * obj) -{ - obj->priv = GEDIT_FILE_BROWSER_VIEW_GET_PRIVATE (obj); - - obj->priv->column = gtk_tree_view_column_new (); - - obj->priv->pixbuf_renderer = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (obj->priv->column, - obj->priv->pixbuf_renderer, - FALSE); - gtk_tree_view_column_add_attribute (obj->priv->column, - obj->priv->pixbuf_renderer, - "pixbuf", - GEDIT_FILE_BROWSER_STORE_COLUMN_ICON); - - obj->priv->text_renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (obj->priv->column, - obj->priv->text_renderer, TRUE); - gtk_tree_view_column_add_attribute (obj->priv->column, - obj->priv->text_renderer, - "text", - GEDIT_FILE_BROWSER_STORE_COLUMN_NAME); - - g_signal_connect (obj->priv->text_renderer, "edited", - G_CALLBACK (on_cell_edited), obj); - - gtk_tree_view_append_column (GTK_TREE_VIEW (obj), - obj->priv->column); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (obj), FALSE); - - gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (obj), - GDK_BUTTON1_MASK, - drag_source_targets, - G_N_ELEMENTS (drag_source_targets), - GDK_ACTION_COPY); - - obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); -} - -static gboolean -bookmarks_separator_func (GtkTreeModel * model, GtkTreeIter * iter, - gpointer user_data) -{ - guint flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, - &flags, -1); - - return (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_SEPARATOR); -} - -/* Public */ -GtkWidget * -gedit_file_browser_view_new (void) -{ - GeditFileBrowserView *obj = - GEDIT_FILE_BROWSER_VIEW (g_object_new - (GEDIT_TYPE_FILE_BROWSER_VIEW, NULL)); - - return GTK_WIDGET (obj); -} - -void -gedit_file_browser_view_set_model (GeditFileBrowserView * tree_view, - GtkTreeModel * model) -{ - GtkTreeSelection *selection; - - if (tree_view->priv->model == model) - return; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); - - if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) { - gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); - gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW - (tree_view), - bookmarks_separator_func, - NULL, NULL); - gtk_tree_view_column_set_cell_data_func (tree_view->priv-> - column, - tree_view->priv-> - text_renderer, - (GtkTreeCellDataFunc) - cell_data_cb, - tree_view, NULL); - } else { - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW - (tree_view), NULL, - NULL, NULL); - gtk_tree_view_column_set_cell_data_func (tree_view->priv-> - column, - tree_view->priv-> - text_renderer, - (GtkTreeCellDataFunc) - cell_data_cb, - tree_view, NULL); - - if (tree_view->priv->restore_expand_state) - install_restore_signals (tree_view, model); - - } - - if (tree_view->priv->hover_path != NULL) { - gtk_tree_path_free (tree_view->priv->hover_path); - tree_view->priv->hover_path = NULL; - } - - if (GEDIT_IS_FILE_BROWSER_STORE (tree_view->priv->model)) { - if (tree_view->priv->restore_expand_state) - uninstall_restore_signals (tree_view, - tree_view->priv->model); - } - - tree_view->priv->model = model; - gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); -} - -void -gedit_file_browser_view_start_rename (GeditFileBrowserView * tree_view, - GtkTreeIter * iter) -{ - guint flags; - GtkTreeRowReference *rowref; - GtkTreePath *path; - - g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view)); - g_return_if_fail (GEDIT_IS_FILE_BROWSER_STORE - (tree_view->priv->model)); - g_return_if_fail (iter != NULL); - - gtk_tree_model_get (tree_view->priv->model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!(FILE_IS_DIR (flags) || !FILE_IS_DUMMY (flags))) - return; - - path = gtk_tree_model_get_path (tree_view->priv->model, iter); - rowref = gtk_tree_row_reference_new (tree_view->priv->model, path); - - /* Start editing */ - gtk_widget_grab_focus (GTK_WIDGET (tree_view)); - - if (gtk_tree_path_up (path)) - gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree_view), - path); - - gtk_tree_path_free (path); - tree_view->priv->editable = rowref; - - gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), - gtk_tree_row_reference_get_path (tree_view->priv->editable), - tree_view->priv->column, TRUE); - - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), - gtk_tree_row_reference_get_path (tree_view->priv->editable), - tree_view->priv->column, - FALSE, 0.0, 0.0); -} - -void -gedit_file_browser_view_set_click_policy (GeditFileBrowserView *tree_view, - GeditFileBrowserViewClickPolicy policy) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view)); - - set_click_policy_property (tree_view, policy); - - g_object_notify (G_OBJECT (tree_view), "click-policy"); -} - -void -gedit_file_browser_view_set_restore_expand_state (GeditFileBrowserView * tree_view, - gboolean restore_expand_state) -{ - g_return_if_fail (GEDIT_IS_FILE_BROWSER_VIEW (tree_view)); - - set_restore_expand_state (tree_view, restore_expand_state); - g_object_notify (G_OBJECT (tree_view), "restore-expand-state"); -} - -/* Signal handlers */ -static void -on_cell_edited (GtkCellRendererText * cell, gchar * path, gchar * new_text, - GeditFileBrowserView * tree_view) -{ - GtkTreePath * treepath; - GtkTreeIter iter; - gboolean ret; - GError * error = NULL; - - gtk_tree_row_reference_free (tree_view->priv->editable); - tree_view->priv->editable = NULL; - - if (new_text == NULL || *new_text == '\0') - return; - - treepath = gtk_tree_path_new_from_string (path); - ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), &iter, treepath); - gtk_tree_path_free (treepath); - - if (ret) { - if (gedit_file_browser_store_rename (GEDIT_FILE_BROWSER_STORE (tree_view->priv->model), - &iter, new_text, &error)) { - treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_view->priv->model), &iter); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), - treepath, NULL, - FALSE, 0.0, 0.0); - gtk_tree_path_free (treepath); - } - else { - if (error) { - g_signal_emit (tree_view, signals[ERROR], 0, - error->code, error->message); - g_error_free (error); - } - } - } -} - -static void -on_begin_refresh (GeditFileBrowserStore * model, - GeditFileBrowserView * view) -{ - /* Store the refresh state, so we can handle unloading of nodes while - refreshing properly */ - view->priv->is_refresh = TRUE; -} - -static void -on_end_refresh (GeditFileBrowserStore * model, - GeditFileBrowserView * view) -{ - /* Store the refresh state, so we can handle unloading of nodes while - refreshing properly */ - view->priv->is_refresh = FALSE; -} - -static void -on_unload (GeditFileBrowserStore * model, - gchar const * uri, - GeditFileBrowserView * view) -{ - /* Don't remove the expand state if we are refreshing */ - if (!view->priv->restore_expand_state || view->priv->is_refresh) - return; - - remove_expand_state (view, uri); -} - -static void -restore_expand_state (GeditFileBrowserView * view, - GeditFileBrowserStore * model, - GtkTreeIter * iter) -{ - gchar * uri; - GFile * file; - GtkTreePath * path; - - gtk_tree_model_get (GTK_TREE_MODEL (model), - iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, - -1); - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); - - if (g_hash_table_lookup (view->priv->expand_state, file)) - { - gtk_tree_view_expand_row (GTK_TREE_VIEW (view), - path, - FALSE); - } - - gtk_tree_path_free (path); - - g_object_unref (file); - g_free (uri); -} - -static void -on_row_inserted (GeditFileBrowserStore * model, - GtkTreePath * path, - GtkTreeIter * iter, - GeditFileBrowserView * view) -{ - GtkTreeIter parent; - GtkTreePath * copy; - - if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (model), iter)) - restore_expand_state (view, model, iter); - - copy = gtk_tree_path_copy (path); - - if (gtk_tree_path_up (copy) && - (gtk_tree_path_get_depth (copy) != 0) && - gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &parent, copy)) - { - restore_expand_state (view, model, &parent); - } - - gtk_tree_path_free (copy); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-view.h b/plugins/filebrowser/gedit-file-browser-view.h deleted file mode 100755 index a5ada255..00000000 --- a/plugins/filebrowser/gedit-file-browser-view.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * gedit-file-browser-view.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_VIEW_H__ -#define __GEDIT_FILE_BROWSER_VIEW_H__ - -#include - -G_BEGIN_DECLS -#define GEDIT_TYPE_FILE_BROWSER_VIEW (gedit_file_browser_view_get_type ()) -#define GEDIT_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserView)) -#define GEDIT_FILE_BROWSER_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserView const)) -#define GEDIT_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewClass)) -#define GEDIT_IS_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW)) -#define GEDIT_IS_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_VIEW)) -#define GEDIT_FILE_BROWSER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_VIEW, GeditFileBrowserViewClass)) - -typedef struct _GeditFileBrowserView GeditFileBrowserView; -typedef struct _GeditFileBrowserViewClass GeditFileBrowserViewClass; -typedef struct _GeditFileBrowserViewPrivate GeditFileBrowserViewPrivate; - -typedef enum { - GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE, - GEDIT_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE -} GeditFileBrowserViewClickPolicy; - -struct _GeditFileBrowserView -{ - GtkTreeView parent; - - GeditFileBrowserViewPrivate *priv; -}; - -struct _GeditFileBrowserViewClass -{ - GtkTreeViewClass parent_class; - - /* Signals */ - void (*error) (GeditFileBrowserView * filetree, - guint code, - gchar const *message); - void (*file_activated) (GeditFileBrowserView * filetree, - GtkTreeIter *iter); - void (*directory_activated) (GeditFileBrowserView * filetree, - GtkTreeIter *iter); - void (*bookmark_activated) (GeditFileBrowserView * filetree, - GtkTreeIter *iter); -}; - -GType gedit_file_browser_view_get_type (void) G_GNUC_CONST; -GType gedit_file_browser_view_register_type (GTypeModule * module); - -GtkWidget *gedit_file_browser_view_new (void); -void gedit_file_browser_view_set_model (GeditFileBrowserView * tree_view, - GtkTreeModel * model); -void gedit_file_browser_view_start_rename (GeditFileBrowserView * tree_view, - GtkTreeIter * iter); -void gedit_file_browser_view_set_click_policy (GeditFileBrowserView * tree_view, - GeditFileBrowserViewClickPolicy policy); -void gedit_file_browser_view_set_restore_expand_state (GeditFileBrowserView * tree_view, - gboolean restore_expand_state); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_VIEW_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-widget-ui.xml b/plugins/filebrowser/gedit-file-browser-widget-ui.xml deleted file mode 100755 index 472fd185..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget-ui.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/filebrowser/gedit-file-browser-widget.c b/plugins/filebrowser/gedit-file-browser-widget.c deleted file mode 100755 index e8a73cce..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget.c +++ /dev/null @@ -1,3143 +0,0 @@ -/* - * gedit-file-browser-widget.c - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gedit-file-browser-utils.h" -#include "gedit-file-browser-error.h" -#include "gedit-file-browser-widget.h" -#include "gedit-file-browser-view.h" -#include "gedit-file-browser-store.h" -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-marshal.h" -#include "gedit-file-browser-enum-types.h" - -#define GEDIT_FILE_BROWSER_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ - GEDIT_TYPE_FILE_BROWSER_WIDGET, \ - GeditFileBrowserWidgetPrivate)) - -#define XML_UI_FILE "gedit-file-browser-widget-ui.xml" -#define LOCATION_DATA_KEY "gedit-file-browser-widget-location" - -enum -{ - BOOKMARKS_ID, - SEPARATOR_CUSTOM_ID, - SEPARATOR_ID, - PATH_ID, - NUM_DEFAULT_IDS -}; - -enum -{ - COLUMN_INDENT, - COLUMN_ICON, - COLUMN_NAME, - COLUMN_FILE, - COLUMN_ID, - N_COLUMNS -}; - -/* Properties */ -enum -{ - PROP_0, - - PROP_FILTER_PATTERN, - PROP_ENABLE_DELETE -}; - -/* Signals */ -enum -{ - URI_ACTIVATED, - ERROR, - CONFIRM_DELETE, - CONFIRM_NO_TRASH, - NUM_SIGNALS -}; - -static guint signals[NUM_SIGNALS] = { 0 }; - -typedef struct _SignalNode -{ - GObject *object; - gulong id; -} SignalNode; - -typedef struct -{ - gulong id; - GeditFileBrowserWidgetFilterFunc func; - gpointer user_data; - GDestroyNotify destroy_notify; -} FilterFunc; - -typedef struct -{ - GFile *root; - GFile *virtual_root; -} Location; - -typedef struct -{ - gchar *name; - GdkPixbuf *icon; -} NameIcon; - -struct _GeditFileBrowserWidgetPrivate -{ - GeditFileBrowserView *treeview; - GeditFileBrowserStore *file_store; - GeditFileBookmarksStore *bookmarks_store; - - GHashTable *bookmarks_hash; - - GtkWidget *combo; - GtkTreeStore *combo_model; - - GtkWidget *filter_expander; - GtkWidget *filter_entry; - - GtkUIManager *manager; - GtkActionGroup *action_group; - GtkActionGroup *action_group_selection; - GtkActionGroup *action_group_file_selection; - GtkActionGroup *action_group_single_selection; - GtkActionGroup *action_group_single_most_selection; - GtkActionGroup *action_group_sensitive; - GtkActionGroup *bookmark_action_group; - - GSList *signal_pool; - - GSList *filter_funcs; - gulong filter_id; - gulong glob_filter_id; - GPatternSpec *filter_pattern; - gchar *filter_pattern_str; - - GList *locations; - GList *current_location; - gboolean changing_location; - GtkWidget *location_previous_menu; - GtkWidget *location_next_menu; - GtkWidget *current_location_menu_item; - - gboolean enable_delete; - - GCancellable *cancellable; - - GdkCursor *busy_cursor; -}; - -static void set_enable_delete (GeditFileBrowserWidget *obj, - gboolean enable); -static void on_model_set (GObject * gobject, - GParamSpec * arg1, - GeditFileBrowserWidget * obj); -static void on_treeview_error (GeditFileBrowserView * tree_view, - guint code, - gchar * message, - GeditFileBrowserWidget * obj); -static void on_file_store_error (GeditFileBrowserStore * store, - guint code, - gchar * message, - GeditFileBrowserWidget * obj); -static gboolean on_file_store_no_trash (GeditFileBrowserStore * store, - GList * files, - GeditFileBrowserWidget * obj); -static void on_combo_changed (GtkComboBox * combo, - GeditFileBrowserWidget * obj); -static gboolean on_treeview_popup_menu (GeditFileBrowserView * treeview, - GeditFileBrowserWidget * obj); -static gboolean on_treeview_button_press_event (GeditFileBrowserView * treeview, - GdkEventButton * event, - GeditFileBrowserWidget * obj); -static gboolean on_treeview_key_press_event (GeditFileBrowserView * treeview, - GdkEventKey * event, - GeditFileBrowserWidget * obj); -static void on_selection_changed (GtkTreeSelection * selection, - GeditFileBrowserWidget * obj); - -static void on_virtual_root_changed (GeditFileBrowserStore * model, - GParamSpec *param, - GeditFileBrowserWidget * obj); - -static gboolean on_entry_filter_activate (GeditFileBrowserWidget * obj); -static void on_location_jump_activate (GtkMenuItem * item, - GeditFileBrowserWidget * obj); -static void on_bookmarks_row_changed (GtkTreeModel * model, - GtkTreePath * path, - GtkTreeIter * iter, - GeditFileBrowserWidget * obj); -static void on_bookmarks_row_deleted (GtkTreeModel * model, - GtkTreePath * path, - GeditFileBrowserWidget * obj); -static void on_filter_mode_changed (GeditFileBrowserStore * model, - GParamSpec * param, - GeditFileBrowserWidget * obj); -static void on_action_directory_previous (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_next (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_up (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_new (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_open (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_new (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_rename (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_delete (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_file_move_to_trash (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_refresh (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_directory_open (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_filter_hidden (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_filter_binary (GtkAction * action, - GeditFileBrowserWidget * obj); -static void on_action_bookmark_open (GtkAction * action, - GeditFileBrowserWidget * obj); - -GEDIT_PLUGIN_DEFINE_TYPE (GeditFileBrowserWidget, gedit_file_browser_widget, - GTK_TYPE_VBOX) - -static void -free_name_icon (gpointer data) -{ - NameIcon * item; - - if (data == NULL) - return; - - item = (NameIcon *)(data); - - g_free (item->name); - - if (item->icon) - g_object_unref (item->icon); - - g_free (item); -} - -static FilterFunc * -filter_func_new (GeditFileBrowserWidget * obj, - GeditFileBrowserWidgetFilterFunc func, - gpointer user_data, - GDestroyNotify notify) -{ - FilterFunc *result; - - result = g_new (FilterFunc, 1); - - result->id = ++obj->priv->filter_id; - result->func = func; - result->user_data = user_data; - result->destroy_notify = notify; - return result; -} - -static void -location_free (Location * loc) -{ - if (loc->root) - g_object_unref (loc->root); - - if (loc->virtual_root) - g_object_unref (loc->virtual_root); - - g_free (loc); -} - -static gboolean -combo_find_by_id (GeditFileBrowserWidget * obj, guint id, - GtkTreeIter * iter) -{ - guint checkid; - GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->combo_model); - - if (iter == NULL) - return FALSE; - - if (gtk_tree_model_get_iter_first (model, iter)) { - do { - gtk_tree_model_get (model, iter, COLUMN_ID, - &checkid, -1); - - if (checkid == id) - return TRUE; - } while (gtk_tree_model_iter_next (model, iter)); - } - - return FALSE; -} - -static void -remove_path_items (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - - while (combo_find_by_id (obj, PATH_ID, &iter)) - gtk_tree_store_remove (obj->priv->combo_model, &iter); -} - -static void -cancel_async_operation (GeditFileBrowserWidget *widget) -{ - if (!widget->priv->cancellable) - return; - - g_cancellable_cancel (widget->priv->cancellable); - g_object_unref (widget->priv->cancellable); - - widget->priv->cancellable = NULL; -} - -static void -gedit_file_browser_widget_finalize (GObject * object) -{ - GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object); - GList *loc; - - remove_path_items (obj); - gedit_file_browser_store_set_filter_func (obj->priv->file_store, - NULL, NULL); - - g_object_unref (obj->priv->manager); - g_object_unref (obj->priv->file_store); - g_object_unref (obj->priv->bookmarks_store); - g_object_unref (obj->priv->combo_model); - - g_slist_foreach (obj->priv->filter_funcs, (GFunc) g_free, NULL); - g_slist_free (obj->priv->filter_funcs); - - for (loc = obj->priv->locations; loc; loc = loc->next) - location_free ((Location *) (loc->data)); - - if (obj->priv->current_location_menu_item) - g_object_unref (obj->priv->current_location_menu_item); - - g_list_free (obj->priv->locations); - - g_hash_table_destroy (obj->priv->bookmarks_hash); - - cancel_async_operation (obj); - - gdk_cursor_unref (obj->priv->busy_cursor); - - G_OBJECT_CLASS (gedit_file_browser_widget_parent_class)->finalize (object); -} - -static void -gedit_file_browser_widget_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object); - - switch (prop_id) - { - case PROP_FILTER_PATTERN: - g_value_set_string (value, obj->priv->filter_pattern_str); - break; - case PROP_ENABLE_DELETE: - g_value_set_boolean (value, obj->priv->enable_delete); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_file_browser_widget_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GeditFileBrowserWidget *obj = GEDIT_FILE_BROWSER_WIDGET (object); - - switch (prop_id) - { - case PROP_FILTER_PATTERN: - gedit_file_browser_widget_set_filter_pattern (obj, - g_value_get_string (value)); - break; - case PROP_ENABLE_DELETE: - set_enable_delete (obj, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_file_browser_widget_class_init (GeditFileBrowserWidgetClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gedit_file_browser_widget_finalize; - - object_class->get_property = gedit_file_browser_widget_get_property; - object_class->set_property = gedit_file_browser_widget_set_property; - - g_object_class_install_property (object_class, PROP_FILTER_PATTERN, - g_param_spec_string ("filter-pattern", - "Filter Pattern", - "The filter pattern", - NULL, - G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_ENABLE_DELETE, - g_param_spec_boolean ("enable-delete", - "Enable delete", - "Enable permanently deleting items", - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - signals[URI_ACTIVATED] = - g_signal_new ("uri-activated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - uri_activated), NULL, NULL, - g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, - G_TYPE_STRING); - signals[ERROR] = - g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - error), NULL, NULL, - gedit_file_browser_marshal_VOID__UINT_STRING, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); - - signals[CONFIRM_DELETE] = - g_signal_new ("confirm-delete", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - confirm_delete), - g_signal_accumulator_true_handled, - NULL, - gedit_file_browser_marshal_BOOL__OBJECT_POINTER, - G_TYPE_BOOLEAN, - 2, - G_TYPE_OBJECT, - G_TYPE_POINTER); - - signals[CONFIRM_NO_TRASH] = - g_signal_new ("confirm-no-trash", G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditFileBrowserWidgetClass, - confirm_no_trash), - g_signal_accumulator_true_handled, - NULL, - gedit_file_browser_marshal_BOOL__POINTER, - G_TYPE_BOOLEAN, - 1, - G_TYPE_POINTER); - - g_type_class_add_private (object_class, - sizeof (GeditFileBrowserWidgetPrivate)); -} - -static void -add_signal (GeditFileBrowserWidget * obj, gpointer object, gulong id) -{ - SignalNode *node = g_new (SignalNode, 1); - - node->object = G_OBJECT (object); - node->id = id; - - obj->priv->signal_pool = - g_slist_prepend (obj->priv->signal_pool, node); -} - -static void -clear_signals (GeditFileBrowserWidget * obj) -{ - GSList *item; - SignalNode *node; - - for (item = obj->priv->signal_pool; item; item = item->next) { - node = (SignalNode *) (item->data); - - g_signal_handler_disconnect (node->object, node->id); - g_free (item->data); - } - - g_slist_free (obj->priv->signal_pool); - obj->priv->signal_pool = NULL; -} - -static gboolean -separator_func (GtkTreeModel * model, GtkTreeIter * iter, gpointer data) -{ - guint id; - - gtk_tree_model_get (model, iter, COLUMN_ID, &id, -1); - - return (id == SEPARATOR_ID); -} - -static gboolean -get_from_bookmark_file (GeditFileBrowserWidget * obj, GFile * file, - gchar ** name, GdkPixbuf ** icon) -{ - gpointer data; - NameIcon * item; - - data = g_hash_table_lookup (obj->priv->bookmarks_hash, file); - - if (data == NULL) - return FALSE; - - item = (NameIcon *)data; - - *name = g_strdup (item->name); - *icon = item->icon; - - if (item->icon != NULL) - { - g_object_ref (item->icon); - } - - return TRUE; -} - -static void -insert_path_item (GeditFileBrowserWidget * obj, - GFile * file, - GtkTreeIter * after, - GtkTreeIter * iter, - guint indent) -{ - gchar * unescape; - GdkPixbuf * icon = NULL; - - /* Try to get the icon and name from the bookmarks hash */ - if (!get_from_bookmark_file (obj, file, &unescape, &icon)) { - /* It's not a bookmark, fetch the name and the icon ourselves */ - unescape = gedit_file_browser_utils_file_basename (file); - - /* Get the icon */ - icon = gedit_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); - } - - gtk_tree_store_insert_after (obj->priv->combo_model, iter, NULL, - after); - - gtk_tree_store_set (obj->priv->combo_model, - iter, - COLUMN_INDENT, indent, - COLUMN_ICON, icon, - COLUMN_NAME, unescape, - COLUMN_FILE, file, - COLUMN_ID, PATH_ID, - -1); - - if (icon) - g_object_unref (icon); - - g_free (unescape); -} - -static void -insert_separator_item (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - - gtk_tree_store_insert (obj->priv->combo_model, &iter, NULL, 1); - gtk_tree_store_set (obj->priv->combo_model, &iter, - COLUMN_ICON, NULL, - COLUMN_NAME, NULL, - COLUMN_ID, SEPARATOR_ID, -1); -} - -static void -combo_set_active_by_id (GeditFileBrowserWidget * obj, guint id) -{ - GtkTreeIter iter; - - if (combo_find_by_id (obj, id, &iter)) - gtk_combo_box_set_active_iter (GTK_COMBO_BOX - (obj->priv->combo), &iter); -} - -static guint -uri_num_parents (GFile * from, GFile * to) -{ - /* Determine the number of 'levels' to get from #from to #to. */ - guint parents = 0; - GFile * parent; - - if (from == NULL) - return 0; - - g_object_ref (from); - - while ((parent = g_file_get_parent (from)) && !(to && g_file_equal (from, to))) { - g_object_unref (from); - from = parent; - - ++parents; - } - - g_object_unref (from); - return parents; -} - -static void -insert_location_path (GeditFileBrowserWidget * obj) -{ - Location *loc; - GFile *current = NULL; - GFile * tmp; - GtkTreeIter separator; - GtkTreeIter iter; - guint indent; - - if (!obj->priv->current_location) { - g_message ("insert_location_path: no current location"); - return; - } - - loc = (Location *) (obj->priv->current_location->data); - - current = loc->virtual_root; - combo_find_by_id (obj, SEPARATOR_ID, &separator); - - indent = uri_num_parents (loc->virtual_root, loc->root); - - while (current != NULL) { - insert_path_item (obj, current, &separator, &iter, indent--); - - if (current == loc->virtual_root) { - g_signal_handlers_block_by_func (obj->priv->combo, - on_combo_changed, - obj); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX - (obj->priv->combo), - &iter); - g_signal_handlers_unblock_by_func (obj->priv-> - combo, - on_combo_changed, - obj); - } - - if (g_file_equal (current, loc->root) || !gedit_utils_file_has_parent (current)) { - if (current != loc->virtual_root) - g_object_unref (current); - break; - } - - tmp = g_file_get_parent (current); - - if (current != loc->virtual_root) - g_object_unref (current); - - current = tmp; - } -} - -static void -check_current_item (GeditFileBrowserWidget * obj, gboolean show_path) -{ - GtkTreeIter separator; - gboolean has_sep; - - remove_path_items (obj); - has_sep = combo_find_by_id (obj, SEPARATOR_ID, &separator); - - if (show_path) { - if (!has_sep) - insert_separator_item (obj); - - insert_location_path (obj); - } else if (has_sep) - gtk_tree_store_remove (obj->priv->combo_model, &separator); -} - -static void -fill_combo_model (GeditFileBrowserWidget * obj) -{ - GtkTreeStore *store = obj->priv->combo_model; - GtkTreeIter iter; - GdkPixbuf *icon; - - icon = gedit_file_browser_utils_pixbuf_from_theme (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU); - - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, &iter, - COLUMN_ICON, icon, - COLUMN_NAME, _("Bookmarks"), - COLUMN_ID, BOOKMARKS_ID, -1); - g_object_unref (icon); - - gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (obj->priv->combo), - separator_func, obj, NULL); - gtk_combo_box_set_active (GTK_COMBO_BOX (obj->priv->combo), 0); -} - -static void -indent_cell_data_func (GtkCellLayout * cell_layout, - GtkCellRenderer * cell, - GtkTreeModel * model, - GtkTreeIter * iter, - gpointer data) -{ - gchar * indent; - guint num; - - gtk_tree_model_get (model, iter, COLUMN_INDENT, &num, -1); - - if (num == 0) - g_object_set (cell, "text", "", NULL); - else { - indent = g_strnfill (num * 2, ' '); - - g_object_set (cell, "text", indent, NULL); - g_free (indent); - } -} - -static void -create_combo (GeditFileBrowserWidget * obj) -{ - GtkCellRenderer *renderer; - - obj->priv->combo_model = gtk_tree_store_new (N_COLUMNS, - G_TYPE_UINT, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_FILE, - G_TYPE_UINT); - obj->priv->combo = - gtk_combo_box_new_with_model (GTK_TREE_MODEL - (obj->priv->combo_model)); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, FALSE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT - (obj->priv->combo), renderer, - indent_cell_data_func, obj, NULL); - - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, FALSE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, "pixbuf", COLUMN_ICON); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, TRUE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), - renderer, "text", COLUMN_NAME); - - g_object_set (renderer, "ellipsize-set", TRUE, - "ellipsize", PANGO_ELLIPSIZE_END, NULL); - - gtk_box_pack_start (GTK_BOX (obj), GTK_WIDGET (obj->priv->combo), - FALSE, FALSE, 0); - - fill_combo_model (obj); - g_signal_connect (obj->priv->combo, "changed", - G_CALLBACK (on_combo_changed), obj); - - gtk_widget_show (obj->priv->combo); -} - -static GtkActionEntry toplevel_actions[] = -{ - {"FilterMenuAction", NULL, N_("_Filter")} -}; - -static const GtkActionEntry tree_actions_selection[] = -{ - {"FileMoveToTrash", "mate-stock-trash", N_("_Move to Trash"), NULL, - N_("Move selected file or folder to trash"), - G_CALLBACK (on_action_file_move_to_trash)}, - {"FileDelete", GTK_STOCK_DELETE, N_("_Delete"), NULL, - N_("Delete selected file or folder"), - G_CALLBACK (on_action_file_delete)} -}; - -static const GtkActionEntry tree_actions_file_selection[] = -{ - {"FileOpen", GTK_STOCK_OPEN, NULL, NULL, - N_("Open selected file"), - G_CALLBACK (on_action_file_open)} -}; - -static const GtkActionEntry tree_actions[] = -{ - {"DirectoryUp", GTK_STOCK_GO_UP, N_("Up"), NULL, - N_("Open the parent folder"), G_CALLBACK (on_action_directory_up)} -}; - -static const GtkActionEntry tree_actions_single_most_selection[] = -{ - {"DirectoryNew", GTK_STOCK_ADD, N_("_New Folder"), NULL, - N_("Add new empty folder"), - G_CALLBACK (on_action_directory_new)}, - {"FileNew", GTK_STOCK_NEW, N_("New F_ile"), NULL, - N_("Add new empty file"), G_CALLBACK (on_action_file_new)} -}; - -static const GtkActionEntry tree_actions_single_selection[] = -{ - {"FileRename", NULL, N_("_Rename"), NULL, - N_("Rename selected file or folder"), - G_CALLBACK (on_action_file_rename)} -}; - -static const GtkActionEntry tree_actions_sensitive[] = -{ - {"DirectoryPrevious", GTK_STOCK_GO_BACK, N_("_Previous Location"), - NULL, - N_("Go to the previous visited location"), - G_CALLBACK (on_action_directory_previous)}, - {"DirectoryNext", GTK_STOCK_GO_FORWARD, N_("_Next Location"), NULL, - N_("Go to the next visited location"), G_CALLBACK (on_action_directory_next)}, - {"DirectoryRefresh", GTK_STOCK_REFRESH, N_("Re_fresh View"), NULL, - N_("Refresh the view"), G_CALLBACK (on_action_directory_refresh)}, - {"DirectoryOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, - N_("View folder in file manager"), - G_CALLBACK (on_action_directory_open)} -}; - -static const GtkToggleActionEntry tree_actions_toggle[] = -{ - {"FilterHidden", GTK_STOCK_DIALOG_AUTHENTICATION, - N_("Show _Hidden"), NULL, - N_("Show hidden files and folders"), - G_CALLBACK (on_action_filter_hidden), FALSE}, - {"FilterBinary", NULL, N_("Show _Binary"), NULL, - N_("Show binary files"), G_CALLBACK (on_action_filter_binary), - FALSE} -}; - -static const GtkActionEntry bookmark_actions[] = -{ - {"BookmarkOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, - N_("View folder in file manager"), G_CALLBACK (on_action_bookmark_open)} -}; - -static void -create_toolbar (GeditFileBrowserWidget * obj, - const gchar *data_dir) -{ - GtkUIManager *manager; - GError *error = NULL; - GtkActionGroup *action_group; - GtkWidget *toolbar; - GtkWidget *widget; - GtkAction *action; - gchar *ui_file; - - manager = gtk_ui_manager_new (); - obj->priv->manager = manager; - - ui_file = g_build_filename (data_dir, XML_UI_FILE, NULL); - gtk_ui_manager_add_ui_from_file (manager, ui_file, &error); - - g_free (ui_file); - - if (error != NULL) { - g_warning ("Error in adding ui from file %s: %s", - XML_UI_FILE, error->message); - g_error_free (error); - return; - } - - action_group = gtk_action_group_new ("FileBrowserWidgetActionGroupToplevel"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - toplevel_actions, - G_N_ELEMENTS (toplevel_actions), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - action_group = gtk_action_group_new ("FileBrowserWidgetActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions, - G_N_ELEMENTS (tree_actions), - obj); - gtk_action_group_add_toggle_actions (action_group, - tree_actions_toggle, - G_N_ELEMENTS (tree_actions_toggle), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_selection, - G_N_ELEMENTS (tree_actions_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetFileSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_file_selection, - G_N_ELEMENTS (tree_actions_file_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_file_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSingleSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_single_selection, - G_N_ELEMENTS (tree_actions_single_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_single_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSingleMostSelectionActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_single_most_selection, - G_N_ELEMENTS (tree_actions_single_most_selection), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_single_most_selection = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetSensitiveActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - tree_actions_sensitive, - G_N_ELEMENTS (tree_actions_sensitive), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->action_group_sensitive = action_group; - - action_group = gtk_action_group_new ("FileBrowserWidgetBookmarkActionGroup"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, - bookmark_actions, - G_N_ELEMENTS (bookmark_actions), - obj); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - obj->priv->bookmark_action_group = action_group; - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, FALSE); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryNext"); - gtk_action_set_sensitive (action, FALSE); - - toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); - gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU); - - /* Previous directory menu tool item */ - obj->priv->location_previous_menu = gtk_menu_new (); - gtk_widget_show (obj->priv->location_previous_menu); - - widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_BACK)); - gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), - obj->priv->location_previous_menu); - - g_object_set (widget, "label", _("Previous location"), NULL); - gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), - _("Go to previous location")); - gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), - _("Go to a previously opened location")); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - g_object_set (action, "is_important", TRUE, "short_label", - _("Previous location"), NULL); - gtk_action_connect_proxy (action, widget); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 0); - - /* Next directory menu tool item */ - obj->priv->location_next_menu = gtk_menu_new (); - gtk_widget_show (obj->priv->location_next_menu); - - widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD)); - gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), - obj->priv->location_next_menu); - - g_object_set (widget, "label", _("Next location"), NULL); - gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), - _("Go to next location")); - gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), - _("Go to a previously opened location")); - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryNext"); - g_object_set (action, "is_important", TRUE, "short_label", - _("Previous location"), NULL); - gtk_action_connect_proxy (action, widget); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 1); - - gtk_box_pack_start (GTK_BOX (obj), toolbar, FALSE, FALSE, 0); - gtk_widget_show (toolbar); - - set_enable_delete (obj, obj->priv->enable_delete); -} - -static void -set_enable_delete (GeditFileBrowserWidget *obj, - gboolean enable) -{ - GtkAction *action; - obj->priv->enable_delete = enable; - - if (obj->priv->action_group_selection == NULL) - return; - - action = - gtk_action_group_get_action (obj->priv->action_group_selection, - "FileDelete"); - - g_object_set (action, "visible", enable, "sensitive", enable, NULL); -} - -static gboolean -filter_real (GeditFileBrowserStore * model, GtkTreeIter * iter, - GeditFileBrowserWidget * obj) -{ - GSList *item; - FilterFunc *func; - - for (item = obj->priv->filter_funcs; item; item = item->next) { - func = (FilterFunc *) (item->data); - - if (!func->func (obj, model, iter, func->user_data)) - return FALSE; - } - - return TRUE; -} - -static void -add_bookmark_hash (GeditFileBrowserWidget * obj, - GtkTreeIter * iter) -{ - GtkTreeModel *model; - GdkPixbuf * pixbuf; - gchar * name; - gchar * uri; - GFile * file; - NameIcon * item; - - model = GTK_TREE_MODEL (obj->priv->bookmarks_store); - - uri = gedit_file_bookmarks_store_get_uri (obj->priv-> - bookmarks_store, - iter); - - if (uri == NULL) - return; - - file = g_file_new_for_uri (uri); - g_free (uri); - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_ICON, - &pixbuf, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_NAME, - &name, -1); - - item = g_new (NameIcon, 1); - item->name = name; - item->icon = pixbuf; - - g_hash_table_insert (obj->priv->bookmarks_hash, - file, - item); -} - -static void -init_bookmarks_hash (GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - GtkTreeModel *model; - - model = GTK_TREE_MODEL (obj->priv->bookmarks_store); - - if (!gtk_tree_model_get_iter_first (model, &iter)) - return; - - do { - add_bookmark_hash (obj, &iter); - } while (gtk_tree_model_iter_next (model, &iter)); - - g_signal_connect (obj->priv->bookmarks_store, - "row-changed", - G_CALLBACK (on_bookmarks_row_changed), - obj); - - g_signal_connect (obj->priv->bookmarks_store, - "row-deleted", - G_CALLBACK (on_bookmarks_row_deleted), - obj); -} - -static void -on_begin_loading (GeditFileBrowserStore *model, - GtkTreeIter *iter, - GeditFileBrowserWidget *obj) -{ - if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)))) - return; - - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)), - obj->priv->busy_cursor); -} - -static void -on_end_loading (GeditFileBrowserStore *model, - GtkTreeIter *iter, - GeditFileBrowserWidget *obj) -{ - if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)))) - return; - - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)), NULL); -} - -static void -create_tree (GeditFileBrowserWidget * obj) -{ - GtkWidget *sw; - - obj->priv->file_store = gedit_file_browser_store_new (NULL); - obj->priv->bookmarks_store = gedit_file_bookmarks_store_new (); - obj->priv->treeview = - GEDIT_FILE_BROWSER_VIEW (gedit_file_browser_view_new ()); - - gedit_file_browser_view_set_restore_expand_state (obj->priv->treeview, TRUE); - - gedit_file_browser_store_set_filter_mode (obj->priv->file_store, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN - | - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); - gedit_file_browser_store_set_filter_func (obj->priv->file_store, - (GeditFileBrowserStoreFilterFunc) - filter_real, obj); - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), - GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_container_add (GTK_CONTAINER (sw), - GTK_WIDGET (obj->priv->treeview)); - gtk_box_pack_start (GTK_BOX (obj), sw, TRUE, TRUE, 0); - - g_signal_connect (obj->priv->treeview, "notify::model", - G_CALLBACK (on_model_set), obj); - g_signal_connect (obj->priv->treeview, "error", - G_CALLBACK (on_treeview_error), obj); - g_signal_connect (obj->priv->treeview, "popup-menu", - G_CALLBACK (on_treeview_popup_menu), obj); - g_signal_connect (obj->priv->treeview, "button-press-event", - G_CALLBACK (on_treeview_button_press_event), - obj); - g_signal_connect (obj->priv->treeview, "key-press-event", - G_CALLBACK (on_treeview_key_press_event), obj); - - g_signal_connect (gtk_tree_view_get_selection - (GTK_TREE_VIEW (obj->priv->treeview)), "changed", - G_CALLBACK (on_selection_changed), obj); - g_signal_connect (obj->priv->file_store, "notify::filter-mode", - G_CALLBACK (on_filter_mode_changed), obj); - - g_signal_connect (obj->priv->file_store, "notify::virtual-root", - G_CALLBACK (on_virtual_root_changed), obj); - - g_signal_connect (obj->priv->file_store, "begin-loading", - G_CALLBACK (on_begin_loading), obj); - - g_signal_connect (obj->priv->file_store, "end-loading", - G_CALLBACK (on_end_loading), obj); - - g_signal_connect (obj->priv->file_store, "error", - G_CALLBACK (on_file_store_error), obj); - - init_bookmarks_hash (obj); - - gtk_widget_show (sw); - gtk_widget_show (GTK_WIDGET (obj->priv->treeview)); -} - -static void -create_filter (GeditFileBrowserWidget * obj) -{ - GtkWidget *expander; - GtkWidget *vbox; - GtkWidget *entry; - - expander = gtk_expander_new_with_mnemonic (_("_Match Filename")); - gtk_widget_show (expander); - gtk_box_pack_start (GTK_BOX (obj), expander, FALSE, FALSE, 0); - - vbox = gtk_vbox_new (FALSE, 3); - gtk_widget_show (vbox); - - obj->priv->filter_expander = expander; - - entry = gtk_entry_new (); - gtk_widget_show (entry); - - obj->priv->filter_entry = entry; - - g_signal_connect_swapped (entry, "activate", - G_CALLBACK (on_entry_filter_activate), - obj); - g_signal_connect_swapped (entry, "focus_out_event", - G_CALLBACK (on_entry_filter_activate), - obj); - - gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (expander), vbox); -} - -static void -gedit_file_browser_widget_init (GeditFileBrowserWidget * obj) -{ - obj->priv = GEDIT_FILE_BROWSER_WIDGET_GET_PRIVATE (obj); - - obj->priv->bookmarks_hash = g_hash_table_new_full (g_file_hash, - (GEqualFunc)g_file_equal, - g_object_unref, - free_name_icon); - - gtk_box_set_spacing (GTK_BOX (obj), 3); - - obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); -} - -/* Private */ - -static void -update_sensitivity (GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - GtkAction *action; - gint mode; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) { - gtk_action_group_set_sensitive (obj->priv->action_group, - TRUE); - gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, - FALSE); - - mode = - gedit_file_browser_store_get_filter_mode - (GEDIT_FILE_BROWSER_STORE (model)); - - action = - gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - !(mode & - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)); - } else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) { - gtk_action_group_set_sensitive (obj->priv->action_group, - FALSE); - gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, - TRUE); - - /* Set the filter toggle to normal up state, just for visual pleasure */ - action = - gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - FALSE); - } - - on_selection_changed (gtk_tree_view_get_selection - (GTK_TREE_VIEW (obj->priv->treeview)), obj); -} - -static gboolean -gedit_file_browser_widget_get_first_selected (GeditFileBrowserWidget *obj, - GtkTreeIter *iter) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - GtkTreeModel *model; - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - gboolean result; - - if (!rows) - return FALSE; - - result = gtk_tree_model_get_iter(model, iter, (GtkTreePath *)(rows->data)); - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result; -} - -static gboolean -popup_menu (GeditFileBrowserWidget * obj, GdkEventButton * event, GtkTreeModel * model) -{ - GtkWidget *menu; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - menu = gtk_ui_manager_get_widget (obj->priv->manager, "/FilePopup"); - else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) - menu = gtk_ui_manager_get_widget (obj->priv->manager, "/BookmarkPopup"); - else - return FALSE; - - g_return_val_if_fail (menu != NULL, FALSE); - - if (event != NULL) { - GtkTreeSelection *selection; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (gtk_tree_selection_count_selected_rows (selection) <= 1) { - GtkTreePath *path; - - if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (obj->priv->treeview), - (gint)event->x, (gint)event->y, - &path, NULL, NULL, NULL)) - { - gtk_tree_selection_unselect_all (selection); - gtk_tree_selection_select_path (selection, path); - gtk_tree_path_free (path); - } - } - - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, - event->button, event->time); - } else { - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, - gedit_utils_menu_position_under_tree_view, - obj->priv->treeview, 0, - gtk_get_current_event_time ()); - gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE); - } - - return TRUE; -} - -static gboolean -filter_glob (GeditFileBrowserWidget * obj, GeditFileBrowserStore * store, - GtkTreeIter * iter, gpointer user_data) -{ - gchar *name; - gboolean result; - guint flags; - - if (obj->priv->filter_pattern == NULL) - return TRUE; - - gtk_tree_model_get (GTK_TREE_MODEL (store), iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_NAME, &name, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (FILE_IS_DIR (flags) || FILE_IS_DUMMY (flags)) - result = TRUE; - else - result = - g_pattern_match_string (obj->priv->filter_pattern, - name); - - g_free (name); - - return result; -} - -static void -rename_selected_file (GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - if (gedit_file_browser_widget_get_first_selected (obj, &iter)) - gedit_file_browser_view_start_rename (obj->priv->treeview, - &iter); -} - -static GList * -get_deletable_files (GeditFileBrowserWidget *obj) { - GtkTreeSelection *selection; - GtkTreeModel *model; - GList *rows; - GList *row; - GList *paths = NULL; - guint flags; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - /* Get all selected files */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (!gtk_tree_model_get_iter (model, &iter, path)) - continue; - - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, - &flags, -1); - - if (FILE_IS_DUMMY (flags)) - continue; - - paths = g_list_append (paths, gtk_tree_path_copy (path)); - } - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return paths; -} - -static gboolean -delete_selected_files (GeditFileBrowserWidget * obj, gboolean trash) -{ - GtkTreeModel *model; - gboolean confirm; - GeditFileBrowserStoreResult result; - GList *rows; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return FALSE; - - rows = get_deletable_files (obj); - - if (!rows) - return FALSE; - - if (!trash) { - g_signal_emit (obj, signals[CONFIRM_DELETE], 0, model, rows, &confirm); - - if (!confirm) - return FALSE; - } - - result = gedit_file_browser_store_delete_all (GEDIT_FILE_BROWSER_STORE (model), - rows, trash); - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result == GEDIT_FILE_BROWSER_STORE_RESULT_OK; -} - -static gboolean -on_file_store_no_trash (GeditFileBrowserStore * store, - GList * files, - GeditFileBrowserWidget * obj) -{ - gboolean confirm = FALSE; - - g_signal_emit (obj, signals[CONFIRM_NO_TRASH], 0, files, &confirm); - - return confirm; -} - -static GFile * -get_topmost_file (GFile * file) -{ - GFile * tmp; - GFile * current; - - current = g_object_ref (file); - - while ((tmp = g_file_get_parent (current)) != NULL) { - g_object_unref (current); - current = tmp; - } - - return current; -} - -static GtkWidget * -create_goto_menu_item (GeditFileBrowserWidget * obj, GList * item, - GdkPixbuf * icon) -{ - GtkWidget *result; - GtkWidget *image; - gchar *unescape; - GdkPixbuf *pixbuf = NULL; - Location *loc; - - loc = (Location *) (item->data); - - if (!get_from_bookmark_file (obj, loc->virtual_root, &unescape, &pixbuf)) { - unescape = gedit_file_browser_utils_file_basename (loc->virtual_root); - - if (icon) - pixbuf = g_object_ref (icon); - } - - if (pixbuf) { - image = gtk_image_new_from_pixbuf (pixbuf); - g_object_unref (pixbuf); - - gtk_widget_show (image); - - result = gtk_image_menu_item_new_with_label (unescape); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (result), - image); - } else { - result = gtk_menu_item_new_with_label (unescape); - } - - g_object_set_data (G_OBJECT (result), LOCATION_DATA_KEY, item); - g_signal_connect (result, "activate", - G_CALLBACK (on_location_jump_activate), obj); - - gtk_widget_show (result); - - g_free (unescape); - - return result; -} - -static GList * -list_next_iterator (GList * list) -{ - if (!list) - return NULL; - - return list->next; -} - -static GList * -list_prev_iterator (GList * list) -{ - if (!list) - return NULL; - - return list->prev; -} - -static void -jump_to_location (GeditFileBrowserWidget * obj, GList * item, - gboolean previous) -{ - Location *loc; - GtkWidget *widget; - GList *children; - GList *child; - GList *(*iter_func) (GList *); - GtkWidget *menu_from; - GtkWidget *menu_to; - gchar *root; - gchar *virtual_root; - - if (!obj->priv->locations) - return; - - if (previous) { - iter_func = list_next_iterator; - menu_from = obj->priv->location_previous_menu; - menu_to = obj->priv->location_next_menu; - } else { - iter_func = list_prev_iterator; - menu_from = obj->priv->location_next_menu; - menu_to = obj->priv->location_previous_menu; - } - - children = gtk_container_get_children (GTK_CONTAINER (menu_from)); - child = children; - - /* This is the menuitem for the current location, which is the first - to be added to the menu */ - widget = obj->priv->current_location_menu_item; - - while (obj->priv->current_location != item) { - if (widget) { - /* Prepend the menu item to the menu */ - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_to), - widget); - - g_object_unref (widget); - } - - widget = GTK_WIDGET (child->data); - - /* Make sure the widget isn't destroyed when removed */ - g_object_ref (widget); - gtk_container_remove (GTK_CONTAINER (menu_from), widget); - - obj->priv->current_location_menu_item = widget; - - if (obj->priv->current_location == NULL) { - obj->priv->current_location = obj->priv->locations; - - if (obj->priv->current_location == item) - break; - } else { - obj->priv->current_location = - iter_func (obj->priv->current_location); - } - - child = child->next; - } - - g_list_free (children); - - obj->priv->changing_location = TRUE; - - loc = (Location *) (obj->priv->current_location->data); - - /* Set the new root + virtual root */ - root = g_file_get_uri (loc->root); - virtual_root = g_file_get_uri (loc->virtual_root); - - gedit_file_browser_widget_set_root_and_virtual_root (obj, - root, - virtual_root); - - g_free (root); - g_free (virtual_root); - - obj->priv->changing_location = FALSE; -} - -static void -clear_next_locations (GeditFileBrowserWidget * obj) -{ - GList *children; - GList *item; - - if (obj->priv->current_location == NULL) - return; - - while (obj->priv->current_location->prev) { - location_free ((Location *) (obj->priv->current_location-> - prev->data)); - obj->priv->locations = - g_list_remove_link (obj->priv->locations, - obj->priv->current_location->prev); - } - - children = - gtk_container_get_children (GTK_CONTAINER - (obj->priv->location_next_menu)); - - for (item = children; item; item = item->next) { - gtk_container_remove (GTK_CONTAINER - (obj->priv->location_next_menu), - GTK_WIDGET (item->data)); - } - - g_list_free (children); - - gtk_action_set_sensitive (gtk_action_group_get_action - (obj->priv->action_group_sensitive, - "DirectoryNext"), FALSE); -} - -static void -update_filter_mode (GeditFileBrowserWidget * obj, - GtkAction * action, - GeditFileBrowserStoreFilterMode mode) -{ - gboolean active = - gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - gint now; - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) { - now = - gedit_file_browser_store_get_filter_mode - (GEDIT_FILE_BROWSER_STORE (model)); - - if (active) - now &= ~mode; - else - now |= mode; - - gedit_file_browser_store_set_filter_mode - (GEDIT_FILE_BROWSER_STORE (model), now); - } -} - -static void -set_filter_pattern_real (GeditFileBrowserWidget * obj, - gchar const * pattern, - gboolean update_entry) -{ - GtkTreeModel *model; - - model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (pattern != NULL && *pattern == '\0') - pattern = NULL; - - if (pattern == NULL && obj->priv->filter_pattern_str == NULL) - return; - - if (pattern != NULL && obj->priv->filter_pattern_str != NULL && - strcmp (pattern, obj->priv->filter_pattern_str) == 0) - return; - - /* Free the old pattern */ - g_free (obj->priv->filter_pattern_str); - obj->priv->filter_pattern_str = g_strdup (pattern); - - if (obj->priv->filter_pattern) { - g_pattern_spec_free (obj->priv->filter_pattern); - obj->priv->filter_pattern = NULL; - } - - if (pattern == NULL) { - if (obj->priv->glob_filter_id != 0) { - gedit_file_browser_widget_remove_filter (obj, - obj-> - priv-> - glob_filter_id); - obj->priv->glob_filter_id = 0; - } - } else { - obj->priv->filter_pattern = g_pattern_spec_new (pattern); - - if (obj->priv->glob_filter_id == 0) - obj->priv->glob_filter_id = - gedit_file_browser_widget_add_filter (obj, - filter_glob, - NULL, - NULL); - } - - if (update_entry) { - if (obj->priv->filter_pattern_str == NULL) - gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), - ""); - else { - gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), - obj->priv->filter_pattern_str); - - gtk_expander_set_expanded (GTK_EXPANDER (obj->priv->filter_expander), - TRUE); - } - } - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - gedit_file_browser_store_refilter (GEDIT_FILE_BROWSER_STORE - (model)); - - g_object_notify (G_OBJECT (obj), "filter-pattern"); -} - - -/* Public */ - -GtkWidget * -gedit_file_browser_widget_new (const gchar *data_dir) -{ - GeditFileBrowserWidget *obj = - g_object_new (GEDIT_TYPE_FILE_BROWSER_WIDGET, NULL); - - create_toolbar (obj, data_dir); - create_combo (obj); - create_tree (obj); - create_filter (obj); - - gedit_file_browser_widget_show_bookmarks (obj); - - return GTK_WIDGET (obj); -} - -void -gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget * obj) -{ - /* Select bookmarks in the combo box */ - g_signal_handlers_block_by_func (obj->priv->combo, - on_combo_changed, obj); - combo_set_active_by_id (obj, BOOKMARKS_ID); - g_signal_handlers_unblock_by_func (obj->priv->combo, - on_combo_changed, obj); - - check_current_item (obj, FALSE); - - gedit_file_browser_view_set_model (obj->priv->treeview, - GTK_TREE_MODEL (obj->priv-> - bookmarks_store)); -} - -static void -show_files_real (GeditFileBrowserWidget *obj, - gboolean do_root_changed) -{ - gedit_file_browser_view_set_model (obj->priv->treeview, - GTK_TREE_MODEL (obj->priv-> - file_store)); - - if (do_root_changed) - on_virtual_root_changed (obj->priv->file_store, NULL, obj); -} - -void -gedit_file_browser_widget_show_files (GeditFileBrowserWidget * obj) -{ - show_files_real (obj, TRUE); -} - -void -gedit_file_browser_widget_set_root_and_virtual_root (GeditFileBrowserWidget *obj, - gchar const *root, - gchar const *virtual_root) -{ - GeditFileBrowserStoreResult result; - - if (!virtual_root) - result = - gedit_file_browser_store_set_root_and_virtual_root - (obj->priv->file_store, root, root); - else - result = - gedit_file_browser_store_set_root_and_virtual_root - (obj->priv->file_store, root, virtual_root); - - if (result == GEDIT_FILE_BROWSER_STORE_RESULT_NO_CHANGE) - show_files_real (obj, TRUE); -} - -void -gedit_file_browser_widget_set_root (GeditFileBrowserWidget * obj, - gchar const *root, - gboolean virtual_root) -{ - GFile *file; - GFile *parent; - gchar *str; - - if (!virtual_root) { - gedit_file_browser_widget_set_root_and_virtual_root (obj, - root, - NULL); - return; - } - - if (!root) - return; - - file = g_file_new_for_uri (root); - parent = get_topmost_file (file); - str = g_file_get_uri (parent); - - gedit_file_browser_widget_set_root_and_virtual_root - (obj, str, root); - - g_free (str); - - g_object_unref (file); - g_object_unref (parent); -} - -GeditFileBrowserStore * -gedit_file_browser_widget_get_browser_store (GeditFileBrowserWidget * obj) -{ - return obj->priv->file_store; -} - -GeditFileBookmarksStore * -gedit_file_browser_widget_get_bookmarks_store (GeditFileBrowserWidget * obj) -{ - return obj->priv->bookmarks_store; -} - -GeditFileBrowserView * -gedit_file_browser_widget_get_browser_view (GeditFileBrowserWidget * obj) -{ - return obj->priv->treeview; -} - -GtkUIManager * -gedit_file_browser_widget_get_ui_manager (GeditFileBrowserWidget * obj) -{ - return obj->priv->manager; -} - -GtkWidget * -gedit_file_browser_widget_get_filter_entry (GeditFileBrowserWidget * obj) -{ - return obj->priv->filter_entry; -} - -gulong -gedit_file_browser_widget_add_filter (GeditFileBrowserWidget * obj, - GeditFileBrowserWidgetFilterFunc func, - gpointer user_data, - GDestroyNotify notify) -{ - FilterFunc *f; - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - f = filter_func_new (obj, func, user_data, notify); - obj->priv->filter_funcs = - g_slist_append (obj->priv->filter_funcs, f); - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - gedit_file_browser_store_refilter (GEDIT_FILE_BROWSER_STORE - (model)); - - return f->id; -} - -void -gedit_file_browser_widget_remove_filter (GeditFileBrowserWidget * obj, - gulong id) -{ - GSList *item; - FilterFunc *func; - - for (item = obj->priv->filter_funcs; item; item = item->next) - { - func = (FilterFunc *) (item->data); - - if (func->id == id) - { - if (func->destroy_notify) - func->destroy_notify (func->user_data); - - obj->priv->filter_funcs = - g_slist_remove_link (obj->priv->filter_funcs, - item); - g_free (func); - break; - } - } -} - -void -gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget * obj, - gchar const *pattern) -{ - set_filter_pattern_real (obj, pattern, TRUE); -} - -gboolean -gedit_file_browser_widget_get_selected_directory (GeditFileBrowserWidget * obj, - GtkTreeIter * iter) -{ - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - GtkTreeIter parent; - guint flags; - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return FALSE; - - if (!gedit_file_browser_widget_get_first_selected (obj, iter)) { - if (!gedit_file_browser_store_get_iter_virtual_root - (GEDIT_FILE_BROWSER_STORE (model), iter)) - return FALSE; - } - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!FILE_IS_DIR (flags)) { - /* Get the parent, because the selection is a file */ - gtk_tree_model_iter_parent (model, &parent, iter); - *iter = parent; - } - - return TRUE; -} - -static guint -gedit_file_browser_widget_get_num_selected_files_or_directories (GeditFileBrowserWidget *obj, - guint *files, - guint *dirs) -{ - GList *rows, *row; - GtkTreePath *path; - GtkTreeIter iter; - GeditFileBrowserStoreFlag flags; - guint result = 0; - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) - return 0; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - /* Get iter from path */ - if (!gtk_tree_model_get_iter (model, &iter, path)) - continue; - - gtk_tree_model_get (model, &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - -1); - - if (!FILE_IS_DUMMY (flags)) { - if (!FILE_IS_DIR (flags)) - ++(*files); - else - ++(*dirs); - - ++result; - } - } - - g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); - g_list_free (rows); - - return result; -} - -typedef struct -{ - GeditFileBrowserWidget *widget; - GCancellable *cancellable; -} AsyncData; - -static AsyncData * -async_data_new (GeditFileBrowserWidget *widget) -{ - AsyncData *ret; - - ret = g_new (AsyncData, 1); - ret->widget = widget; - - cancel_async_operation (widget); - widget->priv->cancellable = g_cancellable_new (); - - ret->cancellable = g_object_ref (widget->priv->cancellable); - - return ret; -} - -static void -async_free (AsyncData *async) -{ - g_object_unref (async->cancellable); - g_free (async); -} - -static void -set_busy (GeditFileBrowserWidget *obj, gboolean busy) -{ - GdkCursor *cursor; - GdkWindow *window; - - window = gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)); - - if (!GDK_IS_WINDOW (window)) - return; - - if (busy) - { - cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (window, cursor); - gdk_cursor_unref (cursor); - } - else - { - gdk_window_set_cursor (window, NULL); - } -} - -static void try_mount_volume (GeditFileBrowserWidget *widget, GVolume *volume); - -static void -activate_mount (GeditFileBrowserWidget *widget, - GVolume *volume, - GMount *mount) -{ - GFile *root; - gchar *uri; - - if (!mount) - { - gchar *message; - gchar *name; - - name = g_volume_get_name (volume); - message = g_strdup_printf (_("No mount object for mounted volume: %s"), name); - - g_signal_emit (widget, - signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_SET_ROOT, - message); - - g_free (name); - g_free (message); - return; - } - - root = g_mount_get_root (mount); - uri = g_file_get_uri (root); - - gedit_file_browser_widget_set_root (widget, uri, FALSE); - - g_free (uri); - g_object_unref (root); -} - -static void -try_activate_drive (GeditFileBrowserWidget *widget, - GDrive *drive) -{ - GList *volumes; - GVolume *volume; - GMount *mount; - - volumes = g_drive_get_volumes (drive); - - volume = G_VOLUME (volumes->data); - mount = g_volume_get_mount (volume); - - if (mount) - { - /* try set the root of the mount */ - activate_mount (widget, volume, mount); - g_object_unref (mount); - } - else - { - /* try to mount it then? */ - try_mount_volume (widget, volume); - } - - g_list_foreach (volumes, (GFunc)g_object_unref, NULL); - g_list_free (volumes); -} - -static void -poll_for_media_cb (GDrive *drive, - GAsyncResult *res, - AsyncData *async) -{ - GError *error = NULL; - - /* check for cancelled state */ - if (g_cancellable_is_cancelled (async->cancellable)) - { - async_free (async); - return; - } - - /* finish poll operation */ - set_busy (async->widget, FALSE); - - if (g_drive_poll_for_media_finish (drive, res, &error) && - g_drive_has_media (drive) && - g_drive_has_volumes (drive)) - { - try_activate_drive (async->widget, drive); - } - else - { - gchar *message; - gchar *name; - - name = g_drive_get_name (drive); - message = g_strdup_printf (_("Could not open media: %s"), name); - - g_signal_emit (async->widget, - signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_SET_ROOT, - message); - - g_free (name); - g_free (message); - - g_error_free (error); - } - - async_free (async); -} - -static void -mount_volume_cb (GVolume *volume, - GAsyncResult *res, - AsyncData *async) -{ - GError *error = NULL; - - /* check for cancelled state */ - if (g_cancellable_is_cancelled (async->cancellable)) - { - async_free (async); - return; - } - - if (g_volume_mount_finish (volume, res, &error)) - { - GMount *mount; - - mount = g_volume_get_mount (volume); - activate_mount (async->widget, volume, mount); - - if (mount) - g_object_unref (mount); - } - else - { - gchar *message; - gchar *name; - - name = g_volume_get_name (volume); - message = g_strdup_printf (_("Could not mount volume: %s"), name); - - g_signal_emit (async->widget, - signals[ERROR], - 0, - GEDIT_FILE_BROWSER_ERROR_SET_ROOT, - message); - - g_free (name); - g_free (message); - - g_error_free (error); - } - - set_busy (async->widget, FALSE); - async_free (async); -} - -static void -activate_drive (GeditFileBrowserWidget *obj, - GtkTreeIter *iter) -{ - GDrive *drive; - AsyncData *async; - - gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, - &drive, -1); - - /* most common use case is a floppy drive, we'll poll for media and - go from there */ - async = async_data_new (obj); - g_drive_poll_for_media (drive, - async->cancellable, - (GAsyncReadyCallback)poll_for_media_cb, - async); - - g_object_unref (drive); - set_busy (obj, TRUE); -} - -static void -try_mount_volume (GeditFileBrowserWidget *widget, - GVolume *volume) -{ - GMountOperation *operation; - AsyncData *async; - - operation = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); - async = async_data_new (widget); - - g_volume_mount (volume, - G_MOUNT_MOUNT_NONE, - operation, - async->cancellable, - (GAsyncReadyCallback)mount_volume_cb, - async); - - g_object_unref (operation); - set_busy (widget, TRUE); -} - -static void -activate_volume (GeditFileBrowserWidget *obj, - GtkTreeIter *iter) -{ - GVolume *volume; - - gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, - &volume, -1); - - /* see if we can mount the volume */ - try_mount_volume (obj, volume); - g_object_unref (volume); -} - -void -gedit_file_browser_widget_refresh (GeditFileBrowserWidget *obj) -{ - GtkTreeModel *model = - gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - gedit_file_browser_store_refresh (GEDIT_FILE_BROWSER_STORE - (model)); - else if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) { - g_hash_table_ref (obj->priv->bookmarks_hash); - g_hash_table_destroy (obj->priv->bookmarks_hash); - - gedit_file_bookmarks_store_refresh - (GEDIT_FILE_BOOKMARKS_STORE (model)); - } -} - -void -gedit_file_browser_widget_history_back (GeditFileBrowserWidget *obj) -{ - if (obj->priv->locations) { - if (obj->priv->current_location) - jump_to_location (obj, - obj->priv->current_location-> - next, TRUE); - else { - jump_to_location (obj, obj->priv->locations, TRUE); - } - } -} - -void -gedit_file_browser_widget_history_forward (GeditFileBrowserWidget *obj) -{ - if (obj->priv->locations) - jump_to_location (obj, obj->priv->current_location->prev, - FALSE); -} - -static void -bookmark_open (GeditFileBrowserWidget *obj, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - gchar *uri; - gint flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, - &flags, -1); - - if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_DRIVE) - { - /* handle a drive node */ - gedit_file_browser_store_cancel_mount_operation (obj->priv->file_store); - activate_drive (obj, iter); - return; - } - else if (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_VOLUME) - { - /* handle a volume node */ - gedit_file_browser_store_cancel_mount_operation (obj->priv->file_store); - activate_volume (obj, iter); - return; - } - - uri = - gedit_file_bookmarks_store_get_uri - (GEDIT_FILE_BOOKMARKS_STORE (model), iter); - - if (uri) { - /* here we check if the bookmark is a mount point, or if it - is a remote bookmark. If that's the case, we will set the - root to the uri of the bookmark and not try to set the - topmost parent as root (since that may as well not be the - mount point anymore) */ - if ((flags & GEDIT_FILE_BOOKMARKS_STORE_IS_MOUNT) || - (flags & GEDIT_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK)) { - gedit_file_browser_widget_set_root (obj, - uri, - FALSE); - } else { - gedit_file_browser_widget_set_root (obj, - uri, - TRUE); - } - } else { - g_warning ("No uri!"); - } - - g_free (uri); -} - -static void -file_open (GeditFileBrowserWidget *obj, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - gchar *uri; - gint flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - if (!FILE_IS_DIR (flags) && !FILE_IS_DUMMY (flags)) { - g_signal_emit (obj, signals[URI_ACTIVATED], 0, uri); - } - - g_free (uri); -} - -static gboolean -directory_open (GeditFileBrowserWidget *obj, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - gboolean result = FALSE; - GError *error = NULL; - gchar *uri = NULL; - GeditFileBrowserStoreFlag flags; - - gtk_tree_model_get (model, iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, &uri, - -1); - - if (FILE_IS_DIR (flags)) { - result = TRUE; - - if (!gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (obj)), uri, GDK_CURRENT_TIME, &error)) { - g_signal_emit (obj, signals[ERROR], 0, - GEDIT_FILE_BROWSER_ERROR_OPEN_DIRECTORY, - error->message); - - g_error_free (error); - error = NULL; - } - } - - g_free (uri); - - return result; -} - -static void -on_bookmark_activated (GeditFileBrowserView *tree_view, - GtkTreeIter *iter, - GeditFileBrowserWidget *obj) -{ - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); - - bookmark_open (obj, model, iter); -} - -static void -on_file_activated (GeditFileBrowserView *tree_view, - GtkTreeIter *iter, - GeditFileBrowserWidget *obj) -{ - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); - - file_open (obj, model, iter); -} - -static gboolean -virtual_root_is_root (GeditFileBrowserWidget * obj, - GeditFileBrowserStore * model) -{ - GtkTreeIter root; - GtkTreeIter virtual_root; - - if (!gedit_file_browser_store_get_iter_root (model, &root)) - return TRUE; - - if (!gedit_file_browser_store_get_iter_virtual_root (model, &virtual_root)) - return TRUE; - - return gedit_file_browser_store_iter_equal (model, &root, &virtual_root); -} - -static void -on_virtual_root_changed (GeditFileBrowserStore * model, - GParamSpec * param, - GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - gchar *uri; - gchar *root_uri; - GtkTreeIter root; - GtkAction *action; - Location *loc; - GdkPixbuf *pixbuf; - - if (gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)) != - GTK_TREE_MODEL (obj->priv->file_store)) - { - show_files_real (obj, FALSE); - } - - if (gedit_file_browser_store_get_iter_virtual_root (model, &iter)) { - gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_URI, - &uri, -1); - - if (gedit_file_browser_store_get_iter_root (model, &root)) { - if (!obj->priv->changing_location) { - /* Remove all items from obj->priv->current_location on */ - if (obj->priv->current_location) - clear_next_locations (obj); - - root_uri = - gedit_file_browser_store_get_root - (model); - - loc = g_new (Location, 1); - loc->root = g_file_new_for_uri (root_uri); - loc->virtual_root = g_file_new_for_uri (uri); - g_free (root_uri); - - if (obj->priv->current_location) { - /* Add current location to the menu so we can go back - to it later */ - gtk_menu_shell_prepend - (GTK_MENU_SHELL - (obj->priv-> - location_previous_menu), - obj->priv-> - current_location_menu_item); - } - - obj->priv->locations = - g_list_prepend (obj->priv->locations, - loc); - - gtk_tree_model_get (GTK_TREE_MODEL (model), - &iter, - GEDIT_FILE_BROWSER_STORE_COLUMN_ICON, - &pixbuf, -1); - - obj->priv->current_location = - obj->priv->locations; - obj->priv->current_location_menu_item = - create_goto_menu_item (obj, - obj->priv-> - current_location, - pixbuf); - - g_object_ref_sink (obj->priv-> - current_location_menu_item); - - if (pixbuf) - g_object_unref (pixbuf); - - } - - action = - gtk_action_group_get_action (obj->priv-> - action_group, - "DirectoryUp"); - gtk_action_set_sensitive (action, - !virtual_root_is_root (obj, model)); - - action = - gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, - obj->priv-> - current_location != NULL - && obj->priv-> - current_location->next != - NULL); - - action = - gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryNext"); - gtk_action_set_sensitive (action, - obj->priv-> - current_location != NULL - && obj->priv-> - current_location->prev != - NULL); - } - - check_current_item (obj, TRUE); - g_free (uri); - } else { - g_message ("NO!"); - } -} - -static void -on_model_set (GObject * gobject, GParamSpec * arg1, - GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (gobject)); - - clear_signals (obj); - - if (GEDIT_IS_FILE_BOOKMARKS_STORE (model)) { - clear_next_locations (obj); - - /* Add the current location to the back menu */ - if (obj->priv->current_location) { - GtkAction *action; - - gtk_menu_shell_prepend (GTK_MENU_SHELL (obj->priv->location_previous_menu), - obj->priv->current_location_menu_item); - - g_object_unref (obj->priv->current_location_menu_item); - obj->priv->current_location = NULL; - obj->priv->current_location_menu_item = NULL; - - action = gtk_action_group_get_action (obj->priv->action_group_sensitive, - "DirectoryPrevious"); - gtk_action_set_sensitive (action, TRUE); - } - - gtk_widget_set_sensitive (obj->priv->filter_expander, FALSE); - - add_signal (obj, gobject, - g_signal_connect (gobject, "bookmark-activated", - G_CALLBACK - (on_bookmark_activated), obj)); - } else if (GEDIT_IS_FILE_BROWSER_STORE (model)) { - /* make sure any async operation is cancelled */ - cancel_async_operation (obj); - - add_signal (obj, gobject, - g_signal_connect (gobject, "file-activated", - G_CALLBACK - (on_file_activated), obj)); - - add_signal (obj, model, - g_signal_connect (model, "no-trash", - G_CALLBACK - (on_file_store_no_trash), obj)); - - gtk_widget_set_sensitive (obj->priv->filter_expander, TRUE); - } - - update_sensitivity (obj); -} - -static void -on_file_store_error (GeditFileBrowserStore * store, guint code, - gchar * message, GeditFileBrowserWidget * obj) -{ - g_signal_emit (obj, signals[ERROR], 0, code, message); -} - -static void -on_treeview_error (GeditFileBrowserView * tree_view, guint code, - gchar * message, GeditFileBrowserWidget * obj) -{ - g_signal_emit (obj, signals[ERROR], 0, code, message); -} - -static void -on_combo_changed (GtkComboBox * combo, GeditFileBrowserWidget * obj) -{ - GtkTreeIter iter; - guint id; - gchar * uri; - GFile * file; - - if (!gtk_combo_box_get_active_iter (combo, &iter)) - return; - - gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->combo_model), &iter, - COLUMN_ID, &id, -1); - - switch (id) { - case BOOKMARKS_ID: - gedit_file_browser_widget_show_bookmarks (obj); - break; - - case PATH_ID: - gtk_tree_model_get (GTK_TREE_MODEL - (obj->priv->combo_model), &iter, - COLUMN_FILE, &file, -1); - - uri = g_file_get_uri (file); - gedit_file_browser_store_set_virtual_root_from_string - (obj->priv->file_store, uri); - - g_free (uri); - g_object_unref (file); - break; - } -} - -static gboolean -on_treeview_popup_menu (GeditFileBrowserView * treeview, - GeditFileBrowserWidget * obj) -{ - return popup_menu (obj, NULL, gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); -} - -static gboolean -on_treeview_button_press_event (GeditFileBrowserView * treeview, - GdkEventButton * event, - GeditFileBrowserWidget * obj) -{ - if (event->type == GDK_BUTTON_PRESS && event->button == 3) { - return popup_menu (obj, event, - gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); - } - - return FALSE; -} - -static gboolean -do_change_directory (GeditFileBrowserWidget * obj, - GdkEventKey * event) -{ - GtkAction * action = NULL; - - if ((event->state & - (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK & ~GDK_MOD1_MASK)) == - event->state && event->keyval == GDK_BackSpace) - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - else if (!((event->state & GDK_MOD1_MASK) && - (event->state & (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK)) == event->state)) - return FALSE; - - switch (event->keyval) { - case GDK_Left: - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryPrevious"); - break; - case GDK_Right: - action = gtk_action_group_get_action (obj->priv-> - action_group_sensitive, - "DirectoryNext"); - break; - case GDK_Up: - action = gtk_action_group_get_action (obj->priv-> - action_group, - "DirectoryUp"); - break; - default: - break; - } - - if (action != NULL) { - gtk_action_activate (action); - return TRUE; - } - - return FALSE; -} - -static gboolean -on_treeview_key_press_event (GeditFileBrowserView * treeview, - GdkEventKey * event, - GeditFileBrowserWidget * obj) -{ - guint modifiers; - - if (do_change_directory (obj, event)) - return TRUE; - - if (!GEDIT_IS_FILE_BROWSER_STORE - (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)))) - return FALSE; - - modifiers = gtk_accelerator_get_default_mod_mask (); - - if (event->keyval == GDK_Delete - || event->keyval == GDK_KP_Delete) { - - if ((event->state & modifiers) == GDK_SHIFT_MASK) { - if (obj->priv->enable_delete) { - delete_selected_files (obj, FALSE); - return TRUE; - } - } else if ((event->state & modifiers) == 0) { - delete_selected_files (obj, TRUE); - return TRUE; - } - } - - if ((event->keyval == GDK_F2) - && (event->state & modifiers) == 0) { - rename_selected_file (obj); - - return TRUE; - } - - return FALSE; -} - -static void -on_selection_changed (GtkTreeSelection * selection, - GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - guint selected = 0; - guint files = 0; - guint dirs = 0; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (GEDIT_IS_FILE_BROWSER_STORE (model)) - { - selected = gedit_file_browser_widget_get_num_selected_files_or_directories (obj, - &files, - &dirs); - } - - gtk_action_group_set_sensitive (obj->priv->action_group_selection, - selected > 0); - gtk_action_group_set_sensitive (obj->priv->action_group_file_selection, - (selected > 0) && (selected == files)); - gtk_action_group_set_sensitive (obj->priv->action_group_single_selection, - selected == 1); - gtk_action_group_set_sensitive (obj->priv->action_group_single_most_selection, - selected <= 1); -} - -static gboolean -on_entry_filter_activate (GeditFileBrowserWidget * obj) -{ - gchar const *text; - - text = gtk_entry_get_text (GTK_ENTRY (obj->priv->filter_entry)); - set_filter_pattern_real (obj, text, FALSE); - - return FALSE; -} - -static void -on_location_jump_activate (GtkMenuItem * item, - GeditFileBrowserWidget * obj) -{ - GList *location; - - location = g_object_get_data (G_OBJECT (item), LOCATION_DATA_KEY); - - if (obj->priv->current_location) { - jump_to_location (obj, location, - g_list_position (obj->priv->locations, - location) > - g_list_position (obj->priv->locations, - obj->priv-> - current_location)); - } else { - jump_to_location (obj, location, TRUE); - } - -} - -static void -on_bookmarks_row_changed (GtkTreeModel * model, - GtkTreePath * path, - GtkTreeIter * iter, - GeditFileBrowserWidget *obj) -{ - add_bookmark_hash (obj, iter); -} - -static void -on_bookmarks_row_deleted (GtkTreeModel * model, - GtkTreePath * path, - GeditFileBrowserWidget *obj) -{ - GtkTreeIter iter; - gchar * uri; - GFile * file; - - if (!gtk_tree_model_get_iter (model, &iter, path)) - return; - - uri = gedit_file_bookmarks_store_get_uri (obj->priv->bookmarks_store, &iter); - - if (!uri) - return; - - file = g_file_new_for_uri (uri); - g_hash_table_remove (obj->priv->bookmarks_hash, file); - - g_object_unref (file); - g_free (uri); -} - -static void -on_filter_mode_changed (GeditFileBrowserStore * model, - GParamSpec * param, - GeditFileBrowserWidget * obj) -{ - gint mode; - GtkToggleAction * action; - gboolean active; - - mode = gedit_file_browser_store_get_filter_mode (model); - - action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, - "FilterHidden")); - active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); - - if (active != gtk_toggle_action_get_active (action)) - gtk_toggle_action_set_active (action, active); - - action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, - "FilterBinary")); - active = !(mode & GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); - - if (active != gtk_toggle_action_get_active (action)) - gtk_toggle_action_set_active (action, active); -} - -static void -on_action_directory_next (GtkAction * action, GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_history_forward (obj); -} - -static void -on_action_directory_previous (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_history_back (obj); -} - -static void -on_action_directory_up (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - gedit_file_browser_store_set_virtual_root_up (GEDIT_FILE_BROWSER_STORE (model)); -} - -static void -on_action_directory_new (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter parent; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - if (!gedit_file_browser_widget_get_selected_directory (obj, &parent)) - return; - - if (gedit_file_browser_store_new_directory - (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter)) { - gedit_file_browser_view_start_rename (obj->priv->treeview, - &iter); - } -} - -static void -on_action_file_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GList *rows; - GList *row; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (gtk_tree_model_get_iter (model, &iter, path)) - file_open (obj, model, &iter); - - gtk_tree_path_free (path); - } - - g_list_free (rows); -} - -static void -on_action_file_new (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeIter parent; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - if (!gedit_file_browser_widget_get_selected_directory (obj, &parent)) - return; - - if (gedit_file_browser_store_new_file - (GEDIT_FILE_BROWSER_STORE (model), &parent, &iter)) { - gedit_file_browser_view_start_rename (obj->priv->treeview, - &iter); - } -} - -static void -on_action_file_rename (GtkAction * action, GeditFileBrowserWidget * obj) -{ - rename_selected_file (obj); -} - -static void -on_action_file_delete (GtkAction * action, GeditFileBrowserWidget * obj) -{ - delete_selected_files (obj, FALSE); -} - -static void -on_action_file_move_to_trash (GtkAction * action, GeditFileBrowserWidget * obj) -{ - delete_selected_files (obj, TRUE); -} - -static void -on_action_directory_refresh (GtkAction * action, - GeditFileBrowserWidget * obj) -{ - gedit_file_browser_widget_refresh (obj); -} - -static void -on_action_directory_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GList *rows; - GList *row; - gboolean directory_opened = FALSE; - GtkTreeIter iter; - GtkTreePath *path; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BROWSER_STORE (model)) - return; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - for (row = rows; row; row = row->next) { - path = (GtkTreePath *)(row->data); - - if (gtk_tree_model_get_iter (model, &iter, path)) - directory_opened |= directory_open (obj, model, &iter); - - gtk_tree_path_free (path); - } - - if (!directory_opened) { - if (gedit_file_browser_widget_get_selected_directory (obj, &iter)) - directory_open (obj, model, &iter); - } - - g_list_free (rows); -} - -static void -on_action_filter_hidden (GtkAction * action, GeditFileBrowserWidget * obj) -{ - update_filter_mode (obj, - action, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); -} - -static void -on_action_filter_binary (GtkAction * action, GeditFileBrowserWidget * obj) -{ - update_filter_mode (obj, - action, - GEDIT_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); -} - -static void -on_action_bookmark_open (GtkAction * action, GeditFileBrowserWidget * obj) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); - - if (!GEDIT_IS_FILE_BOOKMARKS_STORE (model)) - return; - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - bookmark_open (obj, model, &iter); -} - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser-widget.h b/plugins/filebrowser/gedit-file-browser-widget.h deleted file mode 100755 index e9cc2a0e..00000000 --- a/plugins/filebrowser/gedit-file-browser-widget.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * gedit-file-browser-widget.h - Gedit plugin providing easy file access - * from the sidepanel - * - * Copyright (C) 2006 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_FILE_BROWSER_WIDGET_H__ -#define __GEDIT_FILE_BROWSER_WIDGET_H__ - -#include -#include "gedit-file-browser-store.h" -#include "gedit-file-bookmarks-store.h" -#include "gedit-file-browser-view.h" - -G_BEGIN_DECLS -#define GEDIT_TYPE_FILE_BROWSER_WIDGET (gedit_file_browser_widget_get_type ()) -#define GEDIT_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidget)) -#define GEDIT_FILE_BROWSER_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidget const)) -#define GEDIT_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidgetClass)) -#define GEDIT_IS_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET)) -#define GEDIT_IS_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FILE_BROWSER_WIDGET)) -#define GEDIT_FILE_BROWSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FILE_BROWSER_WIDGET, GeditFileBrowserWidgetClass)) - -typedef struct _GeditFileBrowserWidget GeditFileBrowserWidget; -typedef struct _GeditFileBrowserWidgetClass GeditFileBrowserWidgetClass; -typedef struct _GeditFileBrowserWidgetPrivate GeditFileBrowserWidgetPrivate; - -typedef -gboolean (*GeditFileBrowserWidgetFilterFunc) (GeditFileBrowserWidget * obj, - GeditFileBrowserStore * - model, GtkTreeIter * iter, - gpointer user_data); - -struct _GeditFileBrowserWidget -{ - GtkVBox parent; - - GeditFileBrowserWidgetPrivate *priv; -}; - -struct _GeditFileBrowserWidgetClass -{ - GtkVBoxClass parent_class; - - /* Signals */ - void (*uri_activated) (GeditFileBrowserWidget * widget, - gchar const *uri); - void (*error) (GeditFileBrowserWidget * widget, - guint code, - gchar const *message); - gboolean (*confirm_delete) (GeditFileBrowserWidget * widget, - GeditFileBrowserStore * model, - GList *list); - gboolean (*confirm_no_trash) (GeditFileBrowserWidget * widget, - GList *list); -}; - -GType gedit_file_browser_widget_get_type (void) G_GNUC_CONST; -GType gedit_file_browser_widget_register_type (GTypeModule * module); - -GtkWidget *gedit_file_browser_widget_new (const gchar *data_dir); - -void gedit_file_browser_widget_show_bookmarks (GeditFileBrowserWidget * obj); -void gedit_file_browser_widget_show_files (GeditFileBrowserWidget * obj); - -void gedit_file_browser_widget_set_root (GeditFileBrowserWidget * obj, - gchar const *root, - gboolean virtual_root); -void -gedit_file_browser_widget_set_root_and_virtual_root (GeditFileBrowserWidget * obj, - gchar const *root, - gchar const *virtual_root); - -gboolean -gedit_file_browser_widget_get_selected_directory (GeditFileBrowserWidget * obj, - GtkTreeIter * iter); - -GeditFileBrowserStore * -gedit_file_browser_widget_get_browser_store (GeditFileBrowserWidget * obj); -GeditFileBookmarksStore * -gedit_file_browser_widget_get_bookmarks_store (GeditFileBrowserWidget * obj); -GeditFileBrowserView * -gedit_file_browser_widget_get_browser_view (GeditFileBrowserWidget * obj); -GtkWidget * -gedit_file_browser_widget_get_filter_entry (GeditFileBrowserWidget * obj); - -GtkUIManager * -gedit_file_browser_widget_get_ui_manager (GeditFileBrowserWidget * obj); - -gulong gedit_file_browser_widget_add_filter (GeditFileBrowserWidget * obj, - GeditFileBrowserWidgetFilterFunc func, - gpointer user_data, - GDestroyNotify notify); -void gedit_file_browser_widget_remove_filter (GeditFileBrowserWidget * obj, - gulong id); -void gedit_file_browser_widget_set_filter_pattern (GeditFileBrowserWidget * obj, - gchar const *pattern); - -void gedit_file_browser_widget_refresh (GeditFileBrowserWidget * obj); -void gedit_file_browser_widget_history_back (GeditFileBrowserWidget * obj); -void gedit_file_browser_widget_history_forward (GeditFileBrowserWidget * obj); - -G_END_DECLS -#endif /* __GEDIT_FILE_BROWSER_WIDGET_H__ */ - -// ex:ts=8:noet: diff --git a/plugins/filebrowser/gedit-file-browser.schemas.in b/plugins/filebrowser/gedit-file-browser.schemas.in deleted file mode 100755 index c80c8eec..00000000 --- a/plugins/filebrowser/gedit-file-browser.schemas.in +++ /dev/null @@ -1,97 +0,0 @@ - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/tree_view - /apps/gedit-2/plugins/filebrowser/on_load/tree_view - gedit - bool - TRUE - - Open With Tree View - Open the tree view when the file browser plugin gets loaded instead of the bookmarks view - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/root - /apps/gedit-2/plugins/filebrowser/on_load/root - gedit - string - - - File Browser Root Directory - The file browser root directory to use when loading the file - browser plugin and onload/tree_view is TRUE. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/virtual_root - /apps/gedit-2/plugins/filebrowser/on_load/virtual_root - gedit - string - - - File Browser Virtual Root Directory - The file browser virtual root directory to use when loading the - file browser plugin when onload/tree_view is TRUE. The virtual root - must always be below the actual root. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/on_load/enable_remote - /apps/gedit-2/plugins/filebrowser/on_load/enable_remote - gedit - bool - FALSE - - Enable Restore of Remote Locations - Sets whether to enable restoring of remote locations. - - - - - /schemas/apps/gedit-2/plugins/filebrowser/open_at_first_doc - /apps/gedit-2/plugins/filebrowser/open_at_first_doc - gedit - bool - TRUE - - Set Location to First Document - If TRUE the file browser plugin will view the directory of - the first opened document given that the file browser hasn't been - used yet. (Thus this generally applies to opening a document from - the command line or opening it with Caja, etc.) - - - - - /schemas/apps/gedit-2/plugins/filebrowser/filter_mode - /apps/gedit-2/plugins/filebrowser/filter_mode - gedit - string - hidden_and_binary - - File Browser Filter Mode - This value determines what files get filtered from the file - browser. Valid values are: none (filter nothing), - hidden (filter hidden files), binary (filter binary files) and - hidden_and_binary (filter both hidden and binary files). - - - - - /schemas/apps/gedit-2/plugins/filebrowser/filter_pattern - /apps/gedit-2/plugins/filebrowser/filter_pattern - gedit - string - - - File Browser Filter Pattern - The filter pattern to filter the file browser with. This filter - works on top of the filter_mode. - - - - diff --git a/plugins/filebrowser/pluma-file-bookmarks-store.c b/plugins/filebrowser/pluma-file-bookmarks-store.c new file mode 100755 index 00000000..19def257 --- /dev/null +++ b/plugins/filebrowser/pluma-file-bookmarks-store.c @@ -0,0 +1,879 @@ +/* + * pluma-file-bookmarks-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-utils.h" + +#define PLUMA_FILE_BOOKMARKS_STORE_GET_PRIVATE(object)( \ + G_TYPE_INSTANCE_GET_PRIVATE((object), PLUMA_TYPE_FILE_BOOKMARKS_STORE, \ + PlumaFileBookmarksStorePrivate)) + +struct _PlumaFileBookmarksStorePrivate +{ + GVolumeMonitor * volume_monitor; + GFileMonitor * bookmarks_monitor; +}; + +static void remove_node (GtkTreeModel * model, + GtkTreeIter * iter); + +static void on_fs_changed (GVolumeMonitor *monitor, + GObject *object, + PlumaFileBookmarksStore *model); + +static void on_bookmarks_file_changed (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + PlumaFileBookmarksStore * model); +static gboolean find_with_flags (GtkTreeModel * model, + GtkTreeIter * iter, + gpointer obj, + guint flags, + guint notflags); + +PLUMA_PLUGIN_DEFINE_TYPE(PlumaFileBookmarksStore, pluma_file_bookmarks_store, GTK_TYPE_TREE_STORE) + +static void +pluma_file_bookmarks_store_dispose (GObject * object) +{ + PlumaFileBookmarksStore *obj = PLUMA_FILE_BOOKMARKS_STORE (object); + + if (obj->priv->volume_monitor != NULL) { + g_signal_handlers_disconnect_by_func (obj->priv->volume_monitor, + on_fs_changed, + obj); + + g_object_unref (obj->priv->volume_monitor); + obj->priv->volume_monitor = NULL; + } + + if (obj->priv->bookmarks_monitor != NULL) { + g_object_unref (obj->priv->bookmarks_monitor); + obj->priv->bookmarks_monitor = NULL; + } + + G_OBJECT_CLASS (pluma_file_bookmarks_store_parent_class)->dispose (object); +} + +static void +pluma_file_bookmarks_store_finalize (GObject * object) +{ + G_OBJECT_CLASS (pluma_file_bookmarks_store_parent_class)->finalize (object); +} + +static void +pluma_file_bookmarks_store_class_init (PlumaFileBookmarksStoreClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = pluma_file_bookmarks_store_dispose; + object_class->finalize = pluma_file_bookmarks_store_finalize; + + g_type_class_add_private (object_class, sizeof (PlumaFileBookmarksStorePrivate)); +} + +static void +pluma_file_bookmarks_store_init (PlumaFileBookmarksStore * obj) +{ + obj->priv = PLUMA_FILE_BOOKMARKS_STORE_GET_PRIVATE (obj); +} + +/* Private */ +static void +add_node (PlumaFileBookmarksStore *model, + GdkPixbuf *pixbuf, + const gchar *name, + GObject *obj, + guint flags, + GtkTreeIter *iter) +{ + GtkTreeIter newiter; + + gtk_tree_store_append (GTK_TREE_STORE (model), &newiter, NULL); + + gtk_tree_store_set (GTK_TREE_STORE (model), &newiter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON, pixbuf, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, name, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, obj, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, flags, + -1); + + if (iter != NULL) + *iter = newiter; +} + +static gboolean +add_file (PlumaFileBookmarksStore *model, + GFile *file, + const gchar *name, + guint flags, + GtkTreeIter *iter) +{ + GdkPixbuf *pixbuf = NULL; + gboolean native; + gchar *newname; + + native = g_file_is_native (file); + + if (native && !g_file_query_exists (file, NULL)) { + return FALSE; + } + + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_HOME) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("user-home", GTK_ICON_SIZE_MENU); + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("user-desktop", GTK_ICON_SIZE_MENU); + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT) + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("drive-harddisk", GTK_ICON_SIZE_MENU); + + if (pixbuf == NULL) { + /* getting the icon is a sync get_info call, so we just do it for local files */ + if (native) { + pixbuf = pluma_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); + } else { + pixbuf = pluma_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); + } + } + + if (name == NULL) { + newname = pluma_file_browser_utils_file_basename (file); + } else { + newname = g_strdup (name); + } + + add_node (model, pixbuf, newname, G_OBJECT (file), flags, iter); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (newname); + + return TRUE; +} + +static void +check_mount_separator (PlumaFileBookmarksStore * model, guint flags, + gboolean added) +{ + GtkTreeIter iter; + gboolean found; + + found = + find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, + flags | + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, 0); + + if (added && !found) { + /* Add the separator */ + add_node (model, NULL, NULL, NULL, + flags | PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, + NULL); + } else if (!added && found) { + remove_node (GTK_TREE_MODEL (model), &iter); + } +} + +static void +init_special_directories (PlumaFileBookmarksStore * model) +{ + gchar const *path; + GFile * file; + + path = g_get_home_dir (); + if (path != NULL) + { + file = g_file_new_for_path (path); + add_file (model, file, NULL, PLUMA_FILE_BOOKMARKS_STORE_IS_HOME | + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); + g_object_unref (file); + } + + path = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); + if (path != NULL) + { + file = g_file_new_for_path (path); + add_file (model, file, NULL, PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP | + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); + g_object_unref (file); + } + + path = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS); + if (path != NULL) + { + file = g_file_new_for_path (path); + add_file (model, file, NULL, PLUMA_FILE_BOOKMARKS_STORE_IS_DOCUMENTS | + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, NULL); + g_object_unref (file); + } + + file = g_file_new_for_uri ("file:///"); + add_file (model, file, _("File System"), PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, NULL); + g_object_unref (file); + + check_mount_separator (model, PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, TRUE); +} + +static void +get_fs_properties (gpointer fs, + gchar **name, + GdkPixbuf **pixbuf, + guint *flags) +{ + GIcon *icon = NULL; + + *flags = PLUMA_FILE_BOOKMARKS_STORE_IS_FS; + *name = NULL; + *pixbuf = NULL; + + if (G_IS_DRIVE (fs)) + { + icon = g_drive_get_icon (G_DRIVE (fs)); + *name = g_drive_get_name (G_DRIVE (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE; + } + else if (G_IS_VOLUME (fs)) + { + icon = g_volume_get_icon (G_VOLUME (fs)); + *name = g_volume_get_name (G_VOLUME (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME; + } + else if (G_IS_MOUNT (fs)) + { + icon = g_mount_get_icon (G_MOUNT (fs)); + *name = g_mount_get_name (G_MOUNT (fs)); + + *flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT; + } + + if (icon) + { + *pixbuf = pluma_file_browser_utils_pixbuf_from_icon (icon, GTK_ICON_SIZE_MENU); + g_object_unref (icon); + } +} + + +static void +add_fs (PlumaFileBookmarksStore *model, + gpointer fs, + guint flags, + GtkTreeIter *iter) +{ + gchar *name; + GdkPixbuf *pixbuf; + guint fsflags; + + get_fs_properties (fs, &name, &pixbuf, &fsflags); + add_node (model, pixbuf, name, fs, flags | fsflags, iter); + + if (pixbuf) + g_object_unref (pixbuf); + + g_free (name); + check_mount_separator (model, PLUMA_FILE_BOOKMARKS_STORE_IS_FS, TRUE); +} + +static void +process_volume_cb (GVolume *volume, + PlumaFileBookmarksStore *model) +{ + GMount *mount; + guint flags = PLUMA_FILE_BOOKMARKS_STORE_NONE; + mount = g_volume_get_mount (volume); + + /* CHECK: should we use the LOCAL/REMOTE thing still? */ + if (mount) + { + /* Show mounted volume */ + add_fs (model, mount, flags, NULL); + g_object_unref (mount); + } + else if (g_volume_can_mount (volume)) + { + /* We also show the unmounted volume here so users can + mount it if they want to access it */ + add_fs (model, volume, flags, NULL); + } +} + +static void +process_drive_novolumes (PlumaFileBookmarksStore *model, + GDrive *drive) +{ + if (g_drive_is_media_removable (drive) && + !g_drive_is_media_check_automatic (drive) && + g_drive_can_poll_for_media (drive)) + { + /* This can be the case for floppy drives or other + drives where media detection fails. We show the + drive and poll for media when the user activates + it */ + add_fs (model, drive, PLUMA_FILE_BOOKMARKS_STORE_NONE, NULL); + } +} + +static void +process_drive_cb (GDrive *drive, + PlumaFileBookmarksStore *model) +{ + GList *volumes; + + volumes = g_drive_get_volumes (drive); + + if (volumes) + { + /* Add all volumes for the drive */ + g_list_foreach (volumes, (GFunc)process_volume_cb, model); + g_list_free (volumes); + } + else + { + process_drive_novolumes (model, drive); + } +} + +static void +init_drives (PlumaFileBookmarksStore *model) +{ + GList *drives; + + drives = g_volume_monitor_get_connected_drives (model->priv->volume_monitor); + + g_list_foreach (drives, (GFunc)process_drive_cb, model); + g_list_foreach (drives, (GFunc)g_object_unref, NULL); + g_list_free (drives); +} + +static void +process_volume_nodrive_cb (GVolume *volume, + PlumaFileBookmarksStore *model) +{ + GDrive *drive; + + drive = g_volume_get_drive (volume); + + if (drive) + { + g_object_unref (drive); + return; + } + + process_volume_cb (volume, model); +} + +static void +init_volumes (PlumaFileBookmarksStore *model) +{ + GList *volumes; + + volumes = g_volume_monitor_get_volumes (model->priv->volume_monitor); + + g_list_foreach (volumes, (GFunc)process_volume_nodrive_cb, model); + g_list_foreach (volumes, (GFunc)g_object_unref, NULL); + g_list_free (volumes); +} + +static void +process_mount_novolume_cb (GMount *mount, + PlumaFileBookmarksStore *model) +{ + GVolume *volume; + + volume = g_mount_get_volume (mount); + + if (volume) + { + g_object_unref (volume); + } + else if (!g_mount_is_shadowed (mount)) + { + /* Add the mount */ + add_fs (model, mount, PLUMA_FILE_BOOKMARKS_STORE_NONE, NULL); + } +} + +static void +init_mounts (PlumaFileBookmarksStore *model) +{ + GList *mounts; + + mounts = g_volume_monitor_get_mounts (model->priv->volume_monitor); + + g_list_foreach (mounts, (GFunc)process_mount_novolume_cb, model); + g_list_foreach (mounts, (GFunc)g_object_unref, NULL); + g_list_free (mounts); +} + +static void +init_fs (PlumaFileBookmarksStore * model) +{ + if (model->priv->volume_monitor == NULL) { + const gchar **ptr; + const gchar *signals[] = { + "drive-connected", "drive-changed", "drive-disconnected", + "volume-added", "volume-removed", "volume-changed", + "mount-added", "mount-removed", "mount-changed", + NULL + }; + + model->priv->volume_monitor = g_volume_monitor_get (); + + /* Connect signals */ + for (ptr = signals; *ptr; ptr++) + { + g_signal_connect (model->priv->volume_monitor, + *ptr, + G_CALLBACK (on_fs_changed), model); + } + } + + /* First go through all the connected drives */ + init_drives (model); + + /* Then add all volumes, not associated with a drive */ + init_volumes (model); + + /* Then finally add all mounts that have no volume */ + init_mounts (model); +} + +static gboolean +add_bookmark (PlumaFileBookmarksStore * model, + gchar const * name, + gchar const * uri) +{ + GFile * file; + gboolean ret; + guint flags = PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK; + GtkTreeIter iter; + + file = g_file_new_for_uri (uri); + + if (g_file_is_native (file)) { + flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK; + } else { + flags |= PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK; + } + + ret = add_file (model, file, name, flags, &iter); + + g_object_unref (file); + + return ret; +} + +static void +init_bookmarks (PlumaFileBookmarksStore * model) +{ + gchar *bookmarks; + GError *error = NULL; + gchar *contents; + gchar **lines; + gchar **line; + gboolean added = FALSE; + + /* Read the bookmarks file */ + bookmarks = g_build_filename (g_get_home_dir (), + ".gtk-bookmarks", + NULL); + + if (g_file_get_contents (bookmarks, &contents, NULL, &error)) { + lines = g_strsplit (contents, "\n", 0); + + for (line = lines; *line; ++line) { + if (**line) { + gchar *pos; + gchar *name; + + /* CHECK: is this really utf8? */ + pos = g_utf8_strchr (*line, -1, ' '); + + if (pos != NULL) { + *pos = '\0'; + name = pos + 1; + } else { + name = NULL; + } + + /* the bookmarks file should contain valid + * URIs, but paranoia is good */ + if (pluma_utils_is_valid_uri (*line)) { + added |= add_bookmark (model, name, *line); + } + } + } + + g_strfreev (lines); + g_free (contents); + + /* Add a watch */ + if (model->priv->bookmarks_monitor == NULL) { + GFile * file; + + file = g_file_new_for_path (bookmarks); + model->priv->bookmarks_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + + g_signal_connect (model->priv->bookmarks_monitor, + "changed", + (GCallback)on_bookmarks_file_changed, + model); + } + } else { + /* The bookmarks file doesn't exist (which is perfectly fine) */ + g_error_free (error); + } + + if (added) { + /* Bookmarks separator */ + add_node (model, NULL, NULL, NULL, + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK | + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR, NULL); + } + + g_free (bookmarks); +} + +static gint flags_order[] = { + PLUMA_FILE_BOOKMARKS_STORE_IS_HOME, + PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP, + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR, + PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT, + PLUMA_FILE_BOOKMARKS_STORE_IS_FS, + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK, + -1 +}; + +static gint +utf8_casecmp (gchar const *s1, const gchar * s2) +{ + gchar *n1; + gchar *n2; + gint result; + + n1 = g_utf8_casefold (s1, -1); + n2 = g_utf8_casefold (s2, -1); + + result = g_utf8_collate (n1, n2); + + g_free (n1); + g_free (n2); + + return result; +} + +static gint +bookmarks_compare_names (GtkTreeModel * model, GtkTreeIter * a, + GtkTreeIter * b) +{ + gchar *n1; + gchar *n2; + gint result; + guint f1; + guint f2; + + gtk_tree_model_get (model, a, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n1, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, + -1); + gtk_tree_model_get (model, b, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, &n2, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2, + -1); + + /* do not sort actual bookmarks to keep same order as in caja */ + if ((f1 & PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK) && + (f2 & PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK)) + result = 0; + else if (n1 == NULL && n2 == NULL) + result = 0; + else if (n1 == NULL) + result = -1; + else if (n2 == NULL) + result = 1; + else + result = utf8_casecmp (n1, n2); + + g_free (n1); + g_free (n2); + + return result; +} + +static gint +bookmarks_compare_flags (GtkTreeModel * model, GtkTreeIter * a, + GtkTreeIter * b) +{ + guint f1; + guint f2; + gint *flags; + guint sep; + + sep = PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR; + + gtk_tree_model_get (model, a, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f1, + -1); + gtk_tree_model_get (model, b, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &f2, + -1); + + for (flags = flags_order; *flags != -1; ++flags) { + if ((f1 & *flags) != (f2 & *flags)) { + if (f1 & *flags) { + return -1; + } else { + return 1; + } + } else if ((f1 & *flags) && (f1 & sep) != (f2 & sep)) { + if (f1 & sep) + return -1; + else + return 1; + } + } + + return 0; +} + +static gint +bookmarks_compare_func (GtkTreeModel * model, GtkTreeIter * a, + GtkTreeIter * b, gpointer user_data) +{ + gint result; + + result = bookmarks_compare_flags (model, a, b); + + if (result == 0) + result = bookmarks_compare_names (model, a, b); + + return result; +} + +static gboolean +find_with_flags (GtkTreeModel * model, GtkTreeIter * iter, gpointer obj, + guint flags, guint notflags) +{ + GtkTreeIter child; + guint childflags = 0; + GObject * childobj; + gboolean fequal; + + if (!gtk_tree_model_get_iter_first (model, &child)) + return FALSE; + + do { + gtk_tree_model_get (model, &child, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &childobj, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &childflags, -1); + + fequal = (obj == childobj); + + if (childobj) + g_object_unref (childobj); + + if ((obj == NULL || fequal) && + (childflags & flags) == flags + && !(childflags & notflags)) { + *iter = child; + return TRUE; + } + } while (gtk_tree_model_iter_next (model, &child)); + + return FALSE; +} + +static void +remove_node (GtkTreeModel * model, GtkTreeIter * iter) +{ + guint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!(flags & PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR)) { + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS) { + check_mount_separator (PLUMA_FILE_BOOKMARKS_STORE (model), + flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS, + FALSE); + } + } + + gtk_tree_store_remove (GTK_TREE_STORE (model), iter); +} + +static void +remove_bookmarks (PlumaFileBookmarksStore * model) +{ + GtkTreeIter iter; + + while (find_with_flags (GTK_TREE_MODEL (model), &iter, NULL, + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK, + 0)) { + remove_node (GTK_TREE_MODEL (model), &iter); + } +} + +static void +initialize_fill (PlumaFileBookmarksStore * model) +{ + init_special_directories (model); + init_fs (model); + init_bookmarks (model); +} + +/* Public */ +PlumaFileBookmarksStore * +pluma_file_bookmarks_store_new (void) +{ + PlumaFileBookmarksStore *model; + GType column_types[] = { + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_OBJECT, + G_TYPE_UINT + }; + + model = g_object_new (PLUMA_TYPE_FILE_BOOKMARKS_STORE, NULL); + gtk_tree_store_set_column_types (GTK_TREE_STORE (model), + PLUMA_FILE_BOOKMARKS_STORE_N_COLUMNS, + column_types); + + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), + bookmarks_compare_func, + NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); + + initialize_fill (model); + + return model; +} + +gchar * +pluma_file_bookmarks_store_get_uri (PlumaFileBookmarksStore * model, + GtkTreeIter * iter) +{ + GObject * obj; + GFile * file = NULL; + guint flags; + gchar * ret = NULL; + gboolean isfs; + + g_return_val_if_fail (PLUMA_IS_FILE_BOOKMARKS_STORE (model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + + gtk_tree_model_get (GTK_TREE_MODEL (model), iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &obj, + -1); + + if (obj == NULL) + return NULL; + + isfs = (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_FS); + + if (isfs && (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT)) + { + file = g_mount_get_root (G_MOUNT (obj)); + } + else if (!isfs) + { + file = g_object_ref (obj); + } + + g_object_unref (obj); + + if (file) + { + ret = g_file_get_uri (file); + g_object_unref (file); + } + + return ret; +} + +void +pluma_file_bookmarks_store_refresh (PlumaFileBookmarksStore * model) +{ + gtk_tree_store_clear (GTK_TREE_STORE (model)); + initialize_fill (model); +} + +static void +on_fs_changed (GVolumeMonitor *monitor, + GObject *object, + PlumaFileBookmarksStore *model) +{ + GtkTreeModel *tree_model = GTK_TREE_MODEL (model); + guint flags = PLUMA_FILE_BOOKMARKS_STORE_IS_FS; + guint noflags = PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR; + GtkTreeIter iter; + + /* clear all fs items */ + while (find_with_flags (tree_model, &iter, NULL, flags, noflags)) + remove_node (tree_model, &iter); + + /* then reinitialize */ + init_fs (model); +} + +static void +on_bookmarks_file_changed (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + PlumaFileBookmarksStore * model) +{ + switch (event_type) { + case G_FILE_MONITOR_EVENT_CHANGED: + case G_FILE_MONITOR_EVENT_CREATED: + /* Re-initialize bookmarks */ + remove_bookmarks (model); + init_bookmarks (model); + break; + case G_FILE_MONITOR_EVENT_DELETED: // FIXME: shouldn't we also monitor the directory? + /* Remove bookmarks */ + remove_bookmarks (model); + g_object_unref (monitor); + model->priv->bookmarks_monitor = NULL; + break; + default: + break; + } +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-bookmarks-store.h b/plugins/filebrowser/pluma-file-bookmarks-store.h new file mode 100755 index 00000000..c811f588 --- /dev/null +++ b/plugins/filebrowser/pluma-file-bookmarks-store.h @@ -0,0 +1,90 @@ +/* + * pluma-file-bookmarks-store.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BOOKMARKS_STORE_H__ +#define __PLUMA_FILE_BOOKMARKS_STORE_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BOOKMARKS_STORE (pluma_file_bookmarks_store_get_type ()) +#define PLUMA_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStore)) +#define PLUMA_FILE_BOOKMARKS_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStore const)) +#define PLUMA_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStoreClass)) +#define PLUMA_IS_FILE_BOOKMARKS_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE)) +#define PLUMA_IS_FILE_BOOKMARKS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BOOKMARKS_STORE)) +#define PLUMA_FILE_BOOKMARKS_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BOOKMARKS_STORE, PlumaFileBookmarksStoreClass)) + +typedef struct _PlumaFileBookmarksStore PlumaFileBookmarksStore; +typedef struct _PlumaFileBookmarksStoreClass PlumaFileBookmarksStoreClass; +typedef struct _PlumaFileBookmarksStorePrivate PlumaFileBookmarksStorePrivate; + +enum +{ + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON = 0, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + PLUMA_FILE_BOOKMARKS_STORE_N_COLUMNS +}; + +enum +{ + PLUMA_FILE_BOOKMARKS_STORE_NONE = 0, + PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR = 1 << 0, /* Separator item */ + PLUMA_FILE_BOOKMARKS_STORE_IS_SPECIAL_DIR = 1 << 1, /* Special user dir */ + PLUMA_FILE_BOOKMARKS_STORE_IS_HOME = 1 << 2, /* The special Home user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DESKTOP = 1 << 3, /* The special Desktop user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DOCUMENTS = 1 << 4, /* The special Documents user directory */ + PLUMA_FILE_BOOKMARKS_STORE_IS_FS = 1 << 5, /* A mount object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT = 1 << 6, /* A mount object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME = 1 << 7, /* A volume object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE = 1 << 8, /* A drive object */ + PLUMA_FILE_BOOKMARKS_STORE_IS_ROOT = 1 << 9, /* The root file system (file:///) */ + PLUMA_FILE_BOOKMARKS_STORE_IS_BOOKMARK = 1 << 10, /* A gtk bookmark */ + PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK = 1 << 11, /* A remote gtk bookmark */ + PLUMA_FILE_BOOKMARKS_STORE_IS_LOCAL_BOOKMARK = 1 << 12 /* A local gtk bookmark */ +}; + +struct _PlumaFileBookmarksStore +{ + GtkTreeStore parent; + + PlumaFileBookmarksStorePrivate *priv; +}; + +struct _PlumaFileBookmarksStoreClass +{ + GtkTreeStoreClass parent_class; +}; + +GType pluma_file_bookmarks_store_get_type (void) G_GNUC_CONST; +GType pluma_file_bookmarks_store_register_type (GTypeModule * module); + +PlumaFileBookmarksStore *pluma_file_bookmarks_store_new (void); +gchar *pluma_file_bookmarks_store_get_uri (PlumaFileBookmarksStore * model, + GtkTreeIter * iter); +void pluma_file_bookmarks_store_refresh (PlumaFileBookmarksStore * model); + +G_END_DECLS +#endif /* __PLUMA_FILE_BOOKMARKS_STORE_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-enum-register.c.template b/plugins/filebrowser/pluma-file-browser-enum-register.c.template new file mode 100755 index 00000000..0bbd1018 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-register.c.template @@ -0,0 +1,20 @@ +/*** BEGIN file-header ***/ +void +pluma_file_browser_enum_and_flag_register_type (GTypeModule * module) +{ +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + /* Enumerations from "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN enumeration-production ***/ + register_@enum_name@ (module); + +/*** END enumeration-production ***/ + +/*** BEGIN file-tail ***/ +} + +/*** END file-tail ***/ diff --git a/plugins/filebrowser/pluma-file-browser-enum-types.c.template b/plugins/filebrowser/pluma-file-browser-enum-types.c.template new file mode 100755 index 00000000..dc1ac9ea --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-types.c.template @@ -0,0 +1,45 @@ +/*** BEGIN file-header ***/ +#include "pluma-file-browser-enum-types.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +#include "@filename@" + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +static GType @enum_name@_type = 0; + +static GType +register_@enum_name@ (GTypeModule *module) +{ + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, + "@VALUENAME@", + "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + @enum_name@_type = + g_type_module_register_@type@ (module, + "@EnumName@", + values); + + return @enum_name@_type; +} + +GType +@enum_name@_get_type (void) +{ + return @enum_name@_type; +} + +/*** END value-tail ***/ diff --git a/plugins/filebrowser/pluma-file-browser-enum-types.h.template b/plugins/filebrowser/pluma-file-browser-enum-types.h.template new file mode 100755 index 00000000..4f09901e --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-enum-types.h.template @@ -0,0 +1,29 @@ +/*** BEGIN file-header ***/ +#ifndef __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ +#define __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ + +#include + +G_BEGIN_DECLS + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* Enumerations from "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN enumeration-production ***/ +#define PLUMA_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) +GType @enum_name@_get_type (void) G_GNUC_CONST; + +/*** END enumeration-production ***/ + +/*** BEGIN file-tail ***/ +void pluma_file_browser_enum_and_flag_register_type (GTypeModule * module); + +G_END_DECLS + +#endif /* __PLUMA_FILE_BROWSER_ENUM_TYPES_H__ */ +/*** END file-tail ***/ + diff --git a/plugins/filebrowser/pluma-file-browser-error.h b/plugins/filebrowser/pluma-file-browser-error.h new file mode 100755 index 00000000..59f01e2a --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-error.h @@ -0,0 +1,41 @@ +/* + * pluma-file-browser-error.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_ERROR_H__ +#define __PLUMA_FILE_BROWSER_ERROR_H__ + +G_BEGIN_DECLS + +typedef enum { + PLUMA_FILE_BROWSER_ERROR_NONE, + PLUMA_FILE_BROWSER_ERROR_RENAME, + PLUMA_FILE_BROWSER_ERROR_DELETE, + PLUMA_FILE_BROWSER_ERROR_NEW_FILE, + PLUMA_FILE_BROWSER_ERROR_NEW_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY, + PLUMA_FILE_BROWSER_ERROR_NUM +} PlumaFileBrowserError; + +G_END_DECLS + +#endif /* __PLUMA_FILE_BROWSER_ERROR_H__ */ diff --git a/plugins/filebrowser/pluma-file-browser-marshal.list b/plugins/filebrowser/pluma-file-browser-marshal.list new file mode 100755 index 00000000..5fa72c8b --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-marshal.list @@ -0,0 +1,5 @@ +VOID:UINT,STRING +VOID:STRING,STRING +BOOL:OBJECT,POINTER +BOOL:POINTER +BOOL:VOID diff --git a/plugins/filebrowser/pluma-file-browser-messages.c b/plugins/filebrowser/pluma-file-browser-messages.c new file mode 100755 index 00000000..f4b20d05 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-messages.c @@ -0,0 +1,1033 @@ +#include "pluma-file-browser-messages.h" +#include "pluma-file-browser-store.h" +#include + +#define MESSAGE_OBJECT_PATH "/plugins/filebrowser" +#define WINDOW_DATA_KEY "PlumaFileBrowserMessagesWindowData" + +#define BUS_CONNECT(bus, name, data) pluma_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (PlumaMessageCallback) message_##name##_cb, data, NULL) + +typedef struct +{ + PlumaWindow *window; + PlumaMessage *message; +} MessageCacheData; + +typedef struct +{ + guint row_inserted_id; + guint row_deleted_id; + guint root_changed_id; + guint begin_loading_id; + guint end_loading_id; + + GList *merge_ids; + GtkActionGroup *merged_actions; + + PlumaMessageBus *bus; + PlumaFileBrowserWidget *widget; + GHashTable *row_tracking; + + GHashTable *filters; +} WindowData; + +typedef struct +{ + gulong id; + + PlumaWindow *window; + PlumaMessage *message; +} FilterData; + +static WindowData * +window_data_new (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + WindowData *data = g_slice_new (WindowData); + GtkUIManager *manager; + GList *groups; + + data->bus = pluma_window_get_message_bus (window); + data->widget = widget; + data->row_tracking = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)gtk_tree_row_reference_free); + + data->filters = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + NULL); + + manager = pluma_file_browser_widget_get_ui_manager (widget); + + data->merge_ids = NULL; + data->merged_actions = gtk_action_group_new ("MessageMergedActions"); + + groups = gtk_ui_manager_get_action_groups (manager); + gtk_ui_manager_insert_action_group (manager, data->merged_actions, g_list_length (groups)); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); + + return data; +} + +static WindowData * +get_window_data (PlumaWindow * window) +{ + return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); +} + +static void +window_data_free (PlumaWindow *window) +{ + WindowData *data = get_window_data (window); + GtkUIManager *manager; + GList *item; + + g_hash_table_destroy (data->row_tracking); + g_hash_table_destroy (data->filters); + + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + gtk_ui_manager_remove_action_group (manager, data->merged_actions); + + for (item = data->merge_ids; item; item = item->next) + gtk_ui_manager_remove_ui (manager, GPOINTER_TO_INT (item->data)); + + g_list_free (data->merge_ids); + g_object_unref (data->merged_actions); + + g_slice_free (WindowData, data); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static FilterData * +filter_data_new (PlumaWindow *window, + PlumaMessage *message) +{ + FilterData *data = g_slice_new (FilterData); + WindowData *wdata; + + data->window = window; + data->id = 0; + data->message = message; + + wdata = get_window_data (window); + + g_hash_table_insert (wdata->filters, + pluma_message_type_identifier (pluma_message_get_object_path (message), + pluma_message_get_method (message)), + data); + + return data; +} + +static void +filter_data_free (FilterData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *identifier; + + identifier = pluma_message_type_identifier (pluma_message_get_object_path (data->message), + pluma_message_get_method (data->message)); + + g_hash_table_remove (wdata->filters, identifier); + g_free (identifier); + + g_object_unref (data->message); + g_slice_free (FilterData, data); +} + +static GtkTreePath * +track_row_lookup (WindowData *data, + const gchar *id) +{ + GtkTreeRowReference *ref; + + ref = (GtkTreeRowReference *)g_hash_table_lookup (data->row_tracking, id); + + if (!ref) + return NULL; + + return gtk_tree_row_reference_get_path (ref); +} + +static void +message_cache_data_free (MessageCacheData *data) +{ + g_object_unref (data->message); + g_slice_free (MessageCacheData, data); +} + +static MessageCacheData * +message_cache_data_new (PlumaWindow *window, + PlumaMessage *message) +{ + MessageCacheData *data = g_slice_new (MessageCacheData); + + data->window = window; + data->message = message; + + return data; +} + +static void +message_get_root_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserStore *store; + gchar *uri; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + uri = pluma_file_browser_store_get_virtual_root (store); + + pluma_message_set (message, "uri", uri, NULL); + g_free (uri); +} + +static void +message_set_root_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gchar *root = NULL; + gchar *virtual = NULL; + + pluma_message_get (message, "uri", &root, NULL); + + if (!root) + return; + + if (pluma_message_has_key (message, "virtual")) + pluma_message_get (message, "virtual", &virtual, NULL); + + if (virtual) + pluma_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual); + else + pluma_file_browser_widget_set_root (data->widget, root, TRUE); + + g_free (root); + g_free (virtual); +} + +static void +message_set_emblem_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gchar *id = NULL; + gchar *emblem = NULL; + GtkTreePath *path; + PlumaFileBrowserStore *store; + + pluma_message_get (message, "id", &id, "emblem", &emblem, NULL); + + if (!id || !emblem) + { + g_free (id); + g_free (emblem); + + return; + } + + path = track_row_lookup (data, id); + + if (path != NULL) + { + GError *error = NULL; + GdkPixbuf *pixbuf; + + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + emblem, + 10, + 0, + &error); + + if (pixbuf) + { + GValue value = { 0, }; + GtkTreeIter iter; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) + { + g_value_init (&value, GDK_TYPE_PIXBUF); + g_value_set_object (&value, pixbuf); + + pluma_file_browser_store_set_value (store, + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM, + &value); + + g_value_unset (&value); + } + + g_object_unref (pixbuf); + } + + if (error) + g_error_free (error); + } + + g_free (id); + g_free (emblem); +} + +static gchar * +item_id (const gchar *path, + const gchar *uri) +{ + return g_strconcat (path, "::", uri, NULL); +} + +static gchar * +track_row (WindowData *data, + PlumaFileBrowserStore *store, + GtkTreePath *path, + const gchar *uri) +{ + GtkTreeRowReference *ref; + gchar *id; + gchar *pathstr; + + pathstr = gtk_tree_path_to_string (path); + id = item_id (pathstr, uri); + + ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path); + g_hash_table_insert (data->row_tracking, g_strdup (id), ref); + + g_free (pathstr); + + return id; +} + +static void +set_item_message (WindowData *data, + GtkTreeIter *iter, + GtkTreePath *path, + PlumaMessage *message) +{ + PlumaFileBrowserStore *store; + gchar *uri = NULL; + guint flags = 0; + gchar *track_id; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!uri) + return; + + if (path && gtk_tree_path_get_depth (path) != 0) + track_id = track_row (data, store, path, uri); + else + track_id = NULL; + + pluma_message_set (message, + "id", track_id, + "uri", uri, + NULL); + + if (pluma_message_has_key (message, "is_directory")) + { + pluma_message_set (message, + "is_directory", FILE_IS_DIR (flags), + NULL); + } + + g_free (uri); + g_free (track_id); +} + +static gboolean +custom_message_filter_func (PlumaFileBrowserWidget *widget, + PlumaFileBrowserStore *store, + GtkTreeIter *iter, + FilterData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *uri = NULL; + guint flags = 0; + gboolean filter = FALSE; + GtkTreePath *path; + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!uri || FILE_IS_DUMMY (flags)) + { + g_free (uri); + return FALSE; + } + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); + set_item_message (wdata, iter, path, data->message); + gtk_tree_path_free (path); + + pluma_message_set (data->message, "filter", filter, NULL); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + pluma_message_get (data->message, "filter", &filter, NULL); + + return !filter; +} + +static void +message_add_filter_cb (PlumaMessageBus *bus, + PlumaMessage *message, + PlumaWindow *window) +{ + gchar *object_path = NULL; + gchar *method = NULL; + gulong id; + PlumaMessageType *message_type; + PlumaMessage *cbmessage; + FilterData *filter_data; + WindowData *data = get_window_data (window); + + pluma_message_get (message, + "object_path", &object_path, + "method", &method, + NULL); + + // Check if there exists such a 'callback' message + if (!object_path || !method) + { + g_free (object_path); + g_free (method); + + return; + } + + message_type = pluma_message_bus_lookup (bus, object_path, method); + + if (!message_type) + { + g_free (object_path); + g_free (method); + + return; + } + + // Check if the message type has the correct arguments + if (pluma_message_type_lookup (message_type, "id") != G_TYPE_STRING || + pluma_message_type_lookup (message_type, "uri") != G_TYPE_STRING || + pluma_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN || + pluma_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN) + { + return; + } + + cbmessage = pluma_message_type_instantiate (message_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + "filter", FALSE, + NULL); + + // Register the custom filter on the widget + filter_data = filter_data_new (window, cbmessage); + id = pluma_file_browser_widget_add_filter (data->widget, + (PlumaFileBrowserWidgetFilterFunc)custom_message_filter_func, + filter_data, + (GDestroyNotify)filter_data_free); + + filter_data->id = id; +} + +static void +message_remove_filter_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gulong id = 0; + + pluma_message_get (message, "id", &id, NULL); + + if (!id) + return; + + pluma_file_browser_widget_remove_filter (data->widget, id); +} + +static void +message_up_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserStore *store = pluma_file_browser_widget_get_browser_store (data->widget); + + pluma_file_browser_store_set_virtual_root_up (store); +} + +static void +message_history_back_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_history_back (data->widget); +} + +static void +message_history_forward_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_history_forward (data->widget); +} + +static void +message_refresh_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_refresh (data->widget); +} + +static void +message_set_show_hidden_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gboolean active = FALSE; + PlumaFileBrowserStore *store; + PlumaFileBrowserStoreFilterMode mode; + + pluma_message_get (message, "active", &active, NULL); + + store = pluma_file_browser_widget_get_browser_store (data->widget); + mode = pluma_file_browser_store_get_filter_mode (store); + + if (active) + mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + else + mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + + pluma_file_browser_store_set_filter_mode (store, mode); +} + +static void +message_set_show_binary_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + gboolean active = FALSE; + PlumaFileBrowserStore *store; + PlumaFileBrowserStoreFilterMode mode; + + pluma_message_get (message, "active", &active, NULL); + + store = pluma_file_browser_widget_get_browser_store (data->widget); + mode = pluma_file_browser_store_get_filter_mode (store); + + if (active) + mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + else + mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + + pluma_file_browser_store_set_filter_mode (store, mode); +} + +static void +message_show_bookmarks_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_show_bookmarks (data->widget); +} + +static void +message_show_files_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + pluma_file_browser_widget_show_files (data->widget); +} + +static void +message_add_context_item_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + GtkAction *action = NULL; + gchar *path = NULL; + gchar *name; + GtkUIManager *manager; + guint merge_id; + + pluma_message_get (message, + "action", &action, + "path", &path, + NULL); + + if (!action || !path) + { + if (action) + g_object_unref (action); + + g_free (path); + return; + } + + gtk_action_group_add_action (data->merged_actions, action); + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + name = g_strconcat (gtk_action_get_name (action), "MenuItem", NULL); + merge_id = gtk_ui_manager_new_merge_id (manager); + + gtk_ui_manager_add_ui (manager, + merge_id, + path, + name, + gtk_action_get_name (action), + GTK_UI_MANAGER_AUTO, + FALSE); + + if (gtk_ui_manager_get_widget (manager, path)) + { + data->merge_ids = g_list_prepend (data->merge_ids, GINT_TO_POINTER (merge_id)); + pluma_message_set (message, "id", merge_id, NULL); + } + else + { + pluma_message_set (message, "id", 0, NULL); + } + + g_object_unref (action); + g_free (path); + g_free (name); +} + +static void +message_remove_context_item_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + guint merge_id = 0; + GtkUIManager *manager; + + pluma_message_get (message, "id", &merge_id, NULL); + + if (merge_id == 0) + return; + + manager = pluma_file_browser_widget_get_ui_manager (data->widget); + + data->merge_ids = g_list_remove (data->merge_ids, GINT_TO_POINTER (merge_id)); + gtk_ui_manager_remove_ui (manager, merge_id); +} + +static void +message_get_view_cb (PlumaMessageBus *bus, + PlumaMessage *message, + WindowData *data) +{ + PlumaFileBrowserView *view; + view = pluma_file_browser_widget_get_browser_view (data->widget); + + pluma_message_set (message, "view", view, NULL); +} + +static void +register_methods (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + WindowData *data = get_window_data (window); + + /* Register method calls */ + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "get_root", + 1, + "uri", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_root", + 1, + "uri", G_TYPE_STRING, + "virtual", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_emblem", + 0, + "id", G_TYPE_STRING, + "emblem", G_TYPE_STRING, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "add_filter", + 1, + "object_path", G_TYPE_STRING, + "method", G_TYPE_STRING, + "id", G_TYPE_ULONG, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "remove_filter", + 0, + "id", G_TYPE_ULONG, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "add_context_item", + 1, + "action", GTK_TYPE_ACTION, + "path", G_TYPE_STRING, + "id", G_TYPE_UINT, + NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "remove_context_item", + 0, + "id", G_TYPE_UINT, + NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL); + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_show_hidden", + 0, + "active", G_TYPE_BOOLEAN, + NULL); + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "set_show_binary", + 0, + "active", G_TYPE_BOOLEAN, + NULL); + + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL); + pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL); + + pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "get_view", + 1, + "view", PLUMA_TYPE_FILE_BROWSER_VIEW, + NULL); + + BUS_CONNECT (bus, get_root, data); + BUS_CONNECT (bus, set_root, data); + BUS_CONNECT (bus, set_emblem, data); + BUS_CONNECT (bus, add_filter, window); + BUS_CONNECT (bus, remove_filter, data); + + BUS_CONNECT (bus, add_context_item, data); + BUS_CONNECT (bus, remove_context_item, data); + + BUS_CONNECT (bus, up, data); + BUS_CONNECT (bus, history_back, data); + BUS_CONNECT (bus, history_forward, data); + + BUS_CONNECT (bus, refresh, data); + + BUS_CONNECT (bus, set_show_hidden, data); + BUS_CONNECT (bus, set_show_binary, data); + + BUS_CONNECT (bus, show_bookmarks, data); + BUS_CONNECT (bus, show_files, data); + + BUS_CONNECT (bus, get_view, data); +} + +static void +store_row_inserted (PlumaFileBrowserStore *store, + GtkTreePath *path, + GtkTreeIter *iter, + MessageCacheData *data) +{ + gchar *uri = NULL; + guint flags = 0; + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags)) + { + WindowData *wdata = get_window_data (data->window); + + set_item_message (wdata, iter, path, data->message); + pluma_message_bus_send_message_sync (wdata->bus, data->message); + } + + g_free (uri); +} + +static void +store_row_deleted (PlumaFileBrowserStore *store, + GtkTreePath *path, + MessageCacheData *data) +{ + GtkTreeIter iter; + gchar *uri = NULL; + guint flags = 0; + + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags)) + { + WindowData *wdata = get_window_data (data->window); + + set_item_message (wdata, &iter, path, data->message); + pluma_message_bus_send_message_sync (wdata->bus, data->message); + } + + g_free (uri); +} + +static void +store_virtual_root_changed (PlumaFileBrowserStore *store, + GParamSpec *spec, + MessageCacheData *data) +{ + WindowData *wdata = get_window_data (data->window); + gchar *uri; + + uri = pluma_file_browser_store_get_virtual_root (store); + + if (!uri) + return; + + pluma_message_set (data->message, + "uri", uri, + NULL); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + + g_free (uri); +} + +static void +store_begin_loading (PlumaFileBrowserStore *store, + GtkTreeIter *iter, + MessageCacheData *data) +{ + GtkTreePath *path; + WindowData *wdata = get_window_data (data->window); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); + + set_item_message (wdata, iter, path, data->message); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + gtk_tree_path_free (path); +} + +static void +store_end_loading (PlumaFileBrowserStore *store, + GtkTreeIter *iter, + MessageCacheData *data) +{ + GtkTreePath *path; + WindowData *wdata = get_window_data (data->window); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); + + set_item_message (wdata, iter, path, data->message); + + pluma_message_bus_send_message_sync (wdata->bus, data->message); + gtk_tree_path_free (path); +} + +static void +register_signals (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + PlumaFileBrowserStore *store; + PlumaMessageType *inserted_type; + PlumaMessageType *deleted_type; + PlumaMessageType *begin_loading_type; + PlumaMessageType *end_loading_type; + PlumaMessageType *root_changed_type; + + PlumaMessage *message; + WindowData *data; + + /* Register signals */ + root_changed_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "root_changed", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + begin_loading_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "begin_loading", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + end_loading_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "end_loading", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + NULL); + + inserted_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "inserted", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + "is_directory", G_TYPE_BOOLEAN, + NULL); + + deleted_type = pluma_message_bus_register (bus, + MESSAGE_OBJECT_PATH, "deleted", + 0, + "id", G_TYPE_STRING, + "uri", G_TYPE_STRING, + "is_directory", G_TYPE_BOOLEAN, + NULL); + + store = pluma_file_browser_widget_get_browser_store (widget); + + message = pluma_message_type_instantiate (inserted_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + NULL); + + data = get_window_data (window); + + data->row_inserted_id = + g_signal_connect_data (store, + "row-inserted", + G_CALLBACK (store_row_inserted), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); + + message = pluma_message_type_instantiate (deleted_type, + "id", NULL, + "uri", NULL, + "is_directory", FALSE, + NULL); + data->row_deleted_id = + g_signal_connect_data (store, + "row-deleted", + G_CALLBACK (store_row_deleted), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); + + message = pluma_message_type_instantiate (root_changed_type, + "id", NULL, + "uri", NULL, + NULL); + data->root_changed_id = + g_signal_connect_data (store, + "notify::virtual-root", + G_CALLBACK (store_virtual_root_changed), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); + + message = pluma_message_type_instantiate (begin_loading_type, + "id", NULL, + "uri", NULL, + NULL); + data->begin_loading_id = + g_signal_connect_data (store, + "begin_loading", + G_CALLBACK (store_begin_loading), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); + + message = pluma_message_type_instantiate (end_loading_type, + "id", NULL, + "uri", NULL, + NULL); + data->end_loading_id = + g_signal_connect_data (store, + "end_loading", + G_CALLBACK (store_end_loading), + message_cache_data_new (window, message), + (GClosureNotify)message_cache_data_free, + 0); +} + +static void +message_unregistered (PlumaMessageBus *bus, + PlumaMessageType *message_type, + PlumaWindow *window) +{ + gchar *identifier = pluma_message_type_identifier (pluma_message_type_get_object_path (message_type), + pluma_message_type_get_method (message_type)); + FilterData *data; + WindowData *wdata = get_window_data (window); + + data = g_hash_table_lookup (wdata->filters, identifier); + + if (data) + pluma_file_browser_widget_remove_filter (wdata->widget, data->id); + + g_free (identifier); +} + +void +pluma_file_browser_messages_register (PlumaWindow *window, + PlumaFileBrowserWidget *widget) +{ + window_data_new (window, widget); + + register_methods (window, widget); + register_signals (window, widget); + + g_signal_connect (pluma_window_get_message_bus (window), + "unregistered", + G_CALLBACK (message_unregistered), + window); +} + +static void +cleanup_signals (PlumaWindow *window) +{ + WindowData *data = get_window_data (window); + PlumaFileBrowserStore *store; + + store = pluma_file_browser_widget_get_browser_store (data->widget); + + g_signal_handler_disconnect (store, data->row_inserted_id); + g_signal_handler_disconnect (store, data->row_deleted_id); + g_signal_handler_disconnect (store, data->root_changed_id); + g_signal_handler_disconnect (store, data->begin_loading_id); + g_signal_handler_disconnect (store, data->end_loading_id); + + g_signal_handlers_disconnect_by_func (data->bus, message_unregistered, window); +} + +void +pluma_file_browser_messages_unregister (PlumaWindow *window) +{ + PlumaMessageBus *bus = pluma_window_get_message_bus (window); + + cleanup_signals (window); + pluma_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH); + + window_data_free (window); +} diff --git a/plugins/filebrowser/pluma-file-browser-messages.h b/plugins/filebrowser/pluma-file-browser-messages.h new file mode 100755 index 00000000..8f5c2ba4 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-messages.h @@ -0,0 +1,35 @@ +/* + * pluma-file-browser-messages.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2008 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_MESSAGES_H__ +#define __PLUMA_FILE_BROWSER_MESSAGES_H__ + +#include +#include +#include "pluma-file-browser-widget.h" + +void pluma_file_browser_messages_register (PlumaWindow *window, + PlumaFileBrowserWidget *widget); +void pluma_file_browser_messages_unregister (PlumaWindow *window); + +#endif /* __PLUMA_FILE_BROWSER_MESSAGES_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-plugin.c b/plugins/filebrowser/pluma-file-browser-plugin.c new file mode 100755 index 00000000..b9ac96d3 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-plugin.c @@ -0,0 +1,1254 @@ +/* + * pluma-file-browser-plugin.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "pluma-file-browser-enum-types.h" +#include "pluma-file-browser-plugin.h" +#include "pluma-file-browser-utils.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-widget.h" +#include "pluma-file-browser-messages.h" + +#define WINDOW_DATA_KEY "PlumaFileBrowserPluginWindowData" +#define FILE_BROWSER_BASE_KEY "/apps/pluma-2/plugins/filebrowser" +#define CAJA_CLICK_POLICY_BASE_KEY "/apps/caja/preferences" +#define CAJA_CLICK_POLICY_KEY "click_policy" +#define CAJA_ENABLE_DELETE_KEY "enable_delete" +#define CAJA_CONFIRM_TRASH_KEY "confirm_trash" +#define TERMINAL_EXEC_KEY "/desktop/mate/applications/terminal/exec" + +#define PLUMA_FILE_BROWSER_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginPrivate)) + +struct _PlumaFileBrowserPluginPrivate +{ + gpointer dummy; +}; + +typedef struct _PlumaFileBrowserPluginData +{ + PlumaFileBrowserWidget * tree_widget; + gulong merge_id; + GtkActionGroup * action_group; + GtkActionGroup * single_selection_action_group; + gboolean auto_root; + gulong end_loading_handle; + gboolean confirm_trash; + + guint click_policy_handle; + guint enable_delete_handle; + guint confirm_trash_handle; +} PlumaFileBrowserPluginData; + +static void on_uri_activated_cb (PlumaFileBrowserWidget * widget, + gchar const *uri, + PlumaWindow * window); +static void on_error_cb (PlumaFileBrowserWidget * widget, + guint code, + gchar const *message, + PlumaWindow * window); +static void on_model_set_cb (PlumaFileBrowserView * widget, + GParamSpec *arg1, + PlumaWindow * window); +static void on_virtual_root_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window); +static void on_filter_mode_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window); +static void on_rename_cb (PlumaFileBrowserStore * model, + const gchar * olduri, + const gchar * newuri, + PlumaWindow * window); +static void on_filter_pattern_changed_cb (PlumaFileBrowserWidget * widget, + GParamSpec * param, + PlumaWindow * window); +static void on_tab_added_cb (PlumaWindow * window, + PlumaTab * tab, + PlumaFileBrowserPluginData * data); +static gboolean on_confirm_delete_cb (PlumaFileBrowserWidget * widget, + PlumaFileBrowserStore * store, + GList * rows, + PlumaWindow * window); +static gboolean on_confirm_no_trash_cb (PlumaFileBrowserWidget * widget, + GList * files, + PlumaWindow * window); + +PLUMA_PLUGIN_REGISTER_TYPE_WITH_CODE (PlumaFileBrowserPlugin, filetree_plugin, \ + pluma_file_browser_enum_and_flag_register_type (type_module); \ + pluma_file_browser_store_register_type (type_module); \ + pluma_file_bookmarks_store_register_type (type_module); \ + pluma_file_browser_view_register_type (type_module); \ + pluma_file_browser_widget_register_type (type_module); \ +) + + +static void +filetree_plugin_init (PlumaFileBrowserPlugin * plugin) +{ + plugin->priv = PLUMA_FILE_BROWSER_PLUGIN_GET_PRIVATE (plugin); +} + +static void +filetree_plugin_finalize (GObject * object) +{ + //PlumaFileBrowserPlugin * plugin = PLUMA_FILE_BROWSER_PLUGIN (object); + + G_OBJECT_CLASS (filetree_plugin_parent_class)->finalize (object); +} + +static PlumaFileBrowserPluginData * +get_plugin_data (PlumaWindow * window) +{ + return (PlumaFileBrowserPluginData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY)); +} + +static void +on_end_loading_cb (PlumaFileBrowserStore * store, + GtkTreeIter * iter, + PlumaFileBrowserPluginData * data) +{ + /* Disconnect the signal */ + g_signal_handler_disconnect (store, data->end_loading_handle); + data->end_loading_handle = 0; + data->auto_root = FALSE; +} + +static void +prepare_auto_root (PlumaFileBrowserPluginData *data) +{ + PlumaFileBrowserStore *store; + + data->auto_root = TRUE; + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + + if (data->end_loading_handle != 0) { + g_signal_handler_disconnect (store, data->end_loading_handle); + data->end_loading_handle = 0; + } + + data->end_loading_handle = g_signal_connect (store, + "end-loading", + G_CALLBACK (on_end_loading_cb), + data); +} + +static void +restore_default_location (PlumaFileBrowserPluginData *data) +{ + gchar * root; + gchar * virtual_root; + gboolean bookmarks; + gboolean remote; + MateConfClient * client; + + client = mateconf_client_get_default (); + if (!client) + return; + + bookmarks = !mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/tree_view", + NULL); + + if (bookmarks) { + g_object_unref (client); + pluma_file_browser_widget_show_bookmarks (data->tree_widget); + return; + } + + root = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/on_load/root", + NULL); + virtual_root = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + NULL); + + remote = mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/enable_remote", + NULL); + + if (root != NULL && *root != '\0') { + GFile *file; + + file = g_file_new_for_uri (root); + + if (remote || g_file_is_native (file)) { + if (virtual_root != NULL && *virtual_root != '\0') { + prepare_auto_root (data); + pluma_file_browser_widget_set_root_and_virtual_root (data->tree_widget, + root, + virtual_root); + } else { + prepare_auto_root (data); + pluma_file_browser_widget_set_root (data->tree_widget, + root, + TRUE); + } + } + + g_object_unref (file); + } + + g_object_unref (client); + g_free (root); + g_free (virtual_root); +} + +static void +restore_filter (PlumaFileBrowserPluginData * data) +{ + MateConfClient * client; + gchar *filter_mode; + PlumaFileBrowserStoreFilterMode mode; + gchar *pattern; + + client = mateconf_client_get_default (); + if (!client) + return; + + /* Get filter_mode */ + filter_mode = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + NULL); + + /* Filter mode */ + mode = pluma_file_browser_store_filter_mode_get_default (); + + if (filter_mode != NULL) { + if (strcmp (filter_mode, "hidden") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + } else if (strcmp (filter_mode, "binary") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + } else if (strcmp (filter_mode, "hidden_and_binary") == 0 || + strcmp (filter_mode, "binary_and_hidden") == 0) { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN | + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY; + } else if (strcmp (filter_mode, "none") == 0 || + *filter_mode == '\0') { + mode = PLUMA_FILE_BROWSER_STORE_FILTER_MODE_NONE; + } + } + + /* Set the filter mode */ + pluma_file_browser_store_set_filter_mode ( + pluma_file_browser_widget_get_browser_store (data->tree_widget), + mode); + + pattern = mateconf_client_get_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + NULL); + + pluma_file_browser_widget_set_filter_pattern (data->tree_widget, + pattern); + + g_object_unref (client); + g_free (filter_mode); + g_free (pattern); +} + +static PlumaFileBrowserViewClickPolicy +click_policy_from_string (gchar const *click_policy) +{ + if (click_policy && strcmp (click_policy, "single") == 0) + return PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; + else + return PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; +} + +static void +on_click_policy_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData * data; + gchar const *click_policy; + PlumaFileBrowserViewClickPolicy policy = PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE; + PlumaFileBrowserView *view; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_STRING) { + click_policy = mateconf_value_get_string (value); + + policy = click_policy_from_string (click_policy); + } + + view = pluma_file_browser_widget_get_browser_view (data->tree_widget); + pluma_file_browser_view_set_click_policy (view, policy); +} + +static void +on_enable_delete_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData *data; + gboolean enable = FALSE; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_BOOL) + enable = mateconf_value_get_bool (value); + + g_object_set (G_OBJECT (data->tree_widget), "enable-delete", enable, NULL); +} + +static void +on_confirm_trash_changed (MateConfClient *client, + guint cnxn_id, + MateConfEntry *entry, + gpointer user_data) +{ + MateConfValue *value; + PlumaFileBrowserPluginData *data; + gboolean enable = FALSE; + + data = (PlumaFileBrowserPluginData *)(user_data); + value = mateconf_entry_get_value (entry); + + if (value && value->type == MATECONF_VALUE_BOOL) + enable = mateconf_value_get_bool (value); + + data->confirm_trash = enable; +} + +static void +install_caja_prefs (PlumaFileBrowserPluginData *data) +{ + MateConfClient *client; + gchar *pref; + gboolean prefb; + PlumaFileBrowserViewClickPolicy policy; + PlumaFileBrowserView *view; + + client = mateconf_client_get_default (); + if (!client) + return; + + mateconf_client_add_dir (client, + CAJA_CLICK_POLICY_BASE_KEY, + MATECONF_CLIENT_PRELOAD_NONE, + NULL); + + /* Get click_policy */ + pref = mateconf_client_get_string (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, + NULL); + + policy = click_policy_from_string (pref); + + view = pluma_file_browser_widget_get_browser_view (data->tree_widget); + pluma_file_browser_view_set_click_policy (view, policy); + + if (pref) { + data->click_policy_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CLICK_POLICY_KEY, + on_click_policy_changed, + data, + NULL, + NULL); + g_free (pref); + } + + /* Get enable_delete */ + prefb = mateconf_client_get_bool (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, + NULL); + + g_object_set (G_OBJECT (data->tree_widget), "enable-delete", prefb, NULL); + + data->enable_delete_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_ENABLE_DELETE_KEY, + on_enable_delete_changed, + data, + NULL, + NULL); + + /* Get confirm_trash */ + prefb = mateconf_client_get_bool (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, + NULL); + + data->confirm_trash = prefb; + + data->confirm_trash_handle = + mateconf_client_notify_add (client, + CAJA_CLICK_POLICY_BASE_KEY "/" CAJA_CONFIRM_TRASH_KEY, + on_confirm_trash_changed, + data, + NULL, + NULL); + g_object_unref (client); +} + +static void +set_root_from_doc (PlumaFileBrowserPluginData * data, + PlumaDocument * doc) +{ + GFile *file; + GFile *parent; + + if (doc == NULL) + return; + + file = pluma_document_get_location (doc); + if (file == NULL) + return; + + parent = g_file_get_parent (file); + + if (parent != NULL) { + gchar * root; + + root = g_file_get_uri (parent); + + pluma_file_browser_widget_set_root (data->tree_widget, + root, + TRUE); + + g_object_unref (parent); + g_free (root); + } + + g_object_unref (file); +} + +static void +on_action_set_active_root (GtkAction * action, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData *data; + + data = get_plugin_data (window); + set_root_from_doc (data, + pluma_window_get_active_document (window)); +} + +static gchar * +get_terminal (void) +{ + MateConfClient * client; + gchar * terminal; + + client = mateconf_client_get_default (); + terminal = mateconf_client_get_string (client, + TERMINAL_EXEC_KEY, + NULL); + g_object_unref (client); + + if (terminal == NULL) { + const gchar *term = g_getenv ("TERM"); + + if (term != NULL) + terminal = g_strdup (term); + else + terminal = g_strdup ("xterm"); + } + + return terminal; +} + +static void +on_action_open_terminal (GtkAction * action, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + gchar * terminal; + gchar * wd = NULL; + gchar * local; + gchar * argv[2]; + GFile * file; + + GtkTreeIter iter; + PlumaFileBrowserStore * store; + + data = get_plugin_data (window); + + /* Get the current directory */ + if (!pluma_file_browser_widget_get_selected_directory (data->tree_widget, &iter)) + return; + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + gtk_tree_model_get (GTK_TREE_MODEL (store), + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &wd, + -1); + + if (wd == NULL) + return; + + terminal = get_terminal (); + + file = g_file_new_for_uri (wd); + local = g_file_get_path (file); + g_object_unref (file); + + argv[0] = terminal; + argv[1] = NULL; + + g_spawn_async (local, + argv, + NULL, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + NULL, + NULL); + + g_free (terminal); + g_free (wd); + g_free (local); +} + +static void +on_selection_changed_cb (GtkTreeSelection *selection, + PlumaWindow *window) +{ + PlumaFileBrowserPluginData * data; + GtkTreeView * tree_view; + GtkTreeModel * model; + GtkTreeIter iter; + gboolean sensitive; + gchar * uri; + + data = get_plugin_data (window); + + tree_view = GTK_TREE_VIEW (pluma_file_browser_widget_get_browser_view (data->tree_widget)); + model = gtk_tree_view_get_model (tree_view); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + sensitive = pluma_file_browser_widget_get_selected_directory (data->tree_widget, &iter); + + if (sensitive) { + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, -1); + + sensitive = pluma_utils_uri_has_file_scheme (uri); + g_free (uri); + } + + gtk_action_set_sensitive ( + gtk_action_group_get_action (data->single_selection_action_group, + "OpenTerminal"), + sensitive); +} + +#define POPUP_UI "" \ +"" \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +" " \ +"" + +static GtkActionEntry extra_actions[] = +{ + {"SetActiveRoot", GTK_STOCK_JUMP_TO, N_("_Set root to active document"), + NULL, + N_("Set the root to the active document location"), + G_CALLBACK (on_action_set_active_root)} +}; + +static GtkActionEntry extra_single_selection_actions[] = { + {"OpenTerminal", "utilities-terminal", N_("_Open terminal here"), + NULL, + N_("Open a terminal at the currently opened directory"), + G_CALLBACK (on_action_open_terminal)} +}; + +static void +add_popup_ui (PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + GtkUIManager * manager; + GtkActionGroup * action_group; + GError * error = NULL; + + data = get_plugin_data (window); + manager = pluma_file_browser_widget_get_ui_manager (data->tree_widget); + + action_group = gtk_action_group_new ("FileBrowserPluginExtra"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + extra_actions, + G_N_ELEMENTS (extra_actions), + window); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + data->action_group = action_group; + + action_group = gtk_action_group_new ("FileBrowserPluginSingleSelectionExtra"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + extra_single_selection_actions, + G_N_ELEMENTS (extra_single_selection_actions), + window); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + data->single_selection_action_group = action_group; + + data->merge_id = gtk_ui_manager_add_ui_from_string (manager, + POPUP_UI, + -1, + &error); + + if (data->merge_id == 0) { + g_warning("Unable to merge UI: %s", error->message); + g_error_free(error); + } +} + +static void +remove_popup_ui (PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + GtkUIManager * manager; + + data = get_plugin_data (window); + manager = pluma_file_browser_widget_get_ui_manager (data->tree_widget); + gtk_ui_manager_remove_ui (manager, data->merge_id); + + gtk_ui_manager_remove_action_group (manager, data->action_group); + g_object_unref (data->action_group); + + gtk_ui_manager_remove_action_group (manager, data->single_selection_action_group); + g_object_unref (data->single_selection_action_group); +} + +static void +impl_updateui (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + PlumaDocument * doc; + + data = get_plugin_data (window); + + doc = pluma_window_get_active_document (window); + + gtk_action_set_sensitive (gtk_action_group_get_action (data->action_group, + "SetActiveRoot"), + doc != NULL && + !pluma_document_is_untitled (doc)); +} + +static void +impl_activate (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaPanel * panel; + PlumaFileBrowserPluginData * data; + GtkWidget * image; + GdkPixbuf * pixbuf; + PlumaFileBrowserStore * store; + gchar *data_dir; + + data = g_new0 (PlumaFileBrowserPluginData, 1); + + data_dir = pluma_plugin_get_data_dir (plugin); + data->tree_widget = PLUMA_FILE_BROWSER_WIDGET (pluma_file_browser_widget_new (data_dir)); + g_free (data_dir); + + g_signal_connect (data->tree_widget, + "uri-activated", + G_CALLBACK (on_uri_activated_cb), window); + + g_signal_connect (data->tree_widget, + "error", G_CALLBACK (on_error_cb), window); + + g_signal_connect (data->tree_widget, + "notify::filter-pattern", + G_CALLBACK (on_filter_pattern_changed_cb), + window); + + g_signal_connect (data->tree_widget, + "confirm-delete", + G_CALLBACK (on_confirm_delete_cb), + window); + + g_signal_connect (data->tree_widget, + "confirm-no-trash", + G_CALLBACK (on_confirm_no_trash_cb), + window); + + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW + (pluma_file_browser_widget_get_browser_view + (data->tree_widget))), + "changed", + G_CALLBACK (on_selection_changed_cb), + window); + + panel = pluma_window_get_side_panel (window); + pixbuf = pluma_file_browser_utils_pixbuf_from_theme("system-file-manager", + GTK_ICON_SIZE_MENU); + + if (pixbuf) { + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + } else { + image = gtk_image_new_from_stock(GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU); + } + + gtk_widget_show(image); + pluma_panel_add_item (panel, + GTK_WIDGET (data->tree_widget), + _("File Browser"), + image); + gtk_widget_show (GTK_WIDGET (data->tree_widget)); + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data); + + add_popup_ui (window); + + /* Restore filter options */ + restore_filter (data); + + /* Install caja preferences */ + install_caja_prefs (data); + + /* Connect signals to store the last visited location */ + g_signal_connect (pluma_file_browser_widget_get_browser_view (data->tree_widget), + "notify::model", + G_CALLBACK (on_model_set_cb), + window); + + store = pluma_file_browser_widget_get_browser_store (data->tree_widget); + g_signal_connect (store, + "notify::virtual-root", + G_CALLBACK (on_virtual_root_changed_cb), + window); + + g_signal_connect (store, + "notify::filter-mode", + G_CALLBACK (on_filter_mode_changed_cb), + window); + + g_signal_connect (store, + "rename", + G_CALLBACK (on_rename_cb), + window); + + g_signal_connect (window, + "tab-added", + G_CALLBACK (on_tab_added_cb), + data); + + /* Register messages on the bus */ + pluma_file_browser_messages_register (window, data->tree_widget); + + impl_updateui (plugin, window); +} + +static void +impl_deactivate (PlumaPlugin * plugin, PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data; + PlumaPanel * panel; + MateConfClient *client; + + data = get_plugin_data (window); + + /* Unregister messages from the bus */ + pluma_file_browser_messages_unregister (window); + + /* Disconnect signals */ + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); + + client = mateconf_client_get_default (); + mateconf_client_remove_dir (client, CAJA_CLICK_POLICY_BASE_KEY, NULL); + + if (data->click_policy_handle) + mateconf_client_notify_remove (client, data->click_policy_handle); + + if (data->enable_delete_handle) + mateconf_client_notify_remove (client, data->enable_delete_handle); + + if (data->confirm_trash_handle) + mateconf_client_notify_remove (client, data->confirm_trash_handle); + + g_object_unref (client); + remove_popup_ui (window); + + panel = pluma_window_get_side_panel (window); + pluma_panel_remove_item (panel, GTK_WIDGET (data->tree_widget)); + + g_free (data); + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +filetree_plugin_class_init (PlumaFileBrowserPluginClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass * plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = filetree_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_updateui; + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserPluginPrivate)); +} + +/* Callbacks */ +static void +on_uri_activated_cb (PlumaFileBrowserWidget * tree_widget, + gchar const *uri, PlumaWindow * window) +{ + pluma_commands_load_uri (window, uri, NULL, 0); +} + +static void +on_error_cb (PlumaFileBrowserWidget * tree_widget, + guint code, gchar const *message, PlumaWindow * window) +{ + gchar * title; + GtkWidget * dlg; + PlumaFileBrowserPluginData * data; + + data = get_plugin_data (window); + + /* Do not show the error when the root has been set automatically */ + if (data->auto_root && (code == PLUMA_FILE_BROWSER_ERROR_SET_ROOT || + code == PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY)) + { + /* Show bookmarks */ + pluma_file_browser_widget_show_bookmarks (data->tree_widget); + return; + } + + switch (code) { + case PLUMA_FILE_BROWSER_ERROR_NEW_DIRECTORY: + title = + _("An error occurred while creating a new directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_NEW_FILE: + title = _("An error occurred while creating a new file"); + break; + case PLUMA_FILE_BROWSER_ERROR_RENAME: + title = + _ + ("An error occurred while renaming a file or directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_DELETE: + title = + _ + ("An error occurred while deleting a file or directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY: + title = + _ + ("An error occurred while opening a directory in the file manager"); + break; + case PLUMA_FILE_BROWSER_ERROR_SET_ROOT: + title = + _("An error occurred while setting a root directory"); + break; + case PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY: + title = + _("An error occurred while loading a directory"); + break; + default: + title = _("An error occurred"); + break; + } + + dlg = gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "%s", title); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), + "%s", message); + + gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); +} + +static void +on_model_set_cb (PlumaFileBrowserView * widget, + GParamSpec *arg1, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data = get_plugin_data (window); + GtkTreeModel * model; + MateConfClient * client; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (pluma_file_browser_widget_get_browser_view (data->tree_widget))); + + if (model == NULL) + return; + + client = mateconf_client_get_default (); + mateconf_client_set_bool (client, + FILE_BROWSER_BASE_KEY "/on_load/tree_view", + PLUMA_IS_FILE_BROWSER_STORE (model), + NULL); + g_object_unref (client); +} + +static void +on_filter_mode_changed_cb (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaWindow * window) +{ + MateConfClient * client; + PlumaFileBrowserStoreFilterMode mode; + + client = mateconf_client_get_default (); + + if (!client) + return; + + mode = pluma_file_browser_store_get_filter_mode (model); + + if ((mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) && + (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY)) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "hidden_and_binary", + NULL); + } else if (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "hidden", + NULL); + } else if (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "binary", + NULL); + } else { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_mode", + "none", + NULL); + } + + g_object_unref (client); + +} + +static void +on_rename_cb (PlumaFileBrowserStore * store, + const gchar * olduri, + const gchar * newuri, + PlumaWindow * window) +{ + PlumaApp * app; + GList * documents; + GList * item; + PlumaDocument * doc; + GFile * docfile; + GFile * oldfile; + GFile * newfile; + gchar * uri; + + /* Find all documents and set its uri to newuri where it matches olduri */ + app = pluma_app_get_default (); + documents = pluma_app_get_documents (app); + + oldfile = g_file_new_for_uri (olduri); + newfile = g_file_new_for_uri (newuri); + + for (item = documents; item; item = item->next) { + doc = PLUMA_DOCUMENT (item->data); + uri = pluma_document_get_uri (doc); + + if (!uri) + continue; + + docfile = g_file_new_for_uri (uri); + + if (g_file_equal (docfile, oldfile)) { + pluma_document_set_uri (doc, newuri); + } else { + gchar *relative; + + relative = g_file_get_relative_path (oldfile, docfile); + + if (relative) { + /* relative now contains the part in docfile without + the prefix oldfile */ + + g_object_unref (docfile); + g_free (uri); + + docfile = g_file_get_child (newfile, relative); + uri = g_file_get_uri (docfile); + + pluma_document_set_uri (doc, uri); + } + + g_free (relative); + } + + g_free (uri); + g_object_unref (docfile); + } + + g_object_unref (oldfile); + g_object_unref (newfile); + + g_list_free (documents); +} + +static void +on_filter_pattern_changed_cb (PlumaFileBrowserWidget * widget, + GParamSpec * param, + PlumaWindow * window) +{ + MateConfClient * client; + gchar * pattern; + + client = mateconf_client_get_default (); + + if (!client) + return; + + g_object_get (G_OBJECT (widget), "filter-pattern", &pattern, NULL); + + if (pattern == NULL) + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + "", + NULL); + else + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/filter_pattern", + pattern, + NULL); + + g_free (pattern); +} + +static void +on_virtual_root_changed_cb (PlumaFileBrowserStore * store, + GParamSpec * param, + PlumaWindow * window) +{ + PlumaFileBrowserPluginData * data = get_plugin_data (window); + gchar * root; + gchar * virtual_root; + MateConfClient * client; + + root = pluma_file_browser_store_get_root (store); + + if (!root) + return; + + client = mateconf_client_get_default (); + + if (!client) + return; + + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/root", + root, + NULL); + + virtual_root = pluma_file_browser_store_get_virtual_root (store); + + if (!virtual_root) { + /* Set virtual to same as root then */ + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + root, + NULL); + } else { + mateconf_client_set_string (client, + FILE_BROWSER_BASE_KEY "/on_load/virtual_root", + virtual_root, + NULL); + } + + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); + + g_object_unref (client); + g_free (root); + g_free (virtual_root); +} + +static void +on_tab_added_cb (PlumaWindow * window, + PlumaTab * tab, + PlumaFileBrowserPluginData * data) +{ + MateConfClient *client; + gboolean open; + gboolean load_default = TRUE; + + client = mateconf_client_get_default (); + + if (!client) + return; + + open = mateconf_client_get_bool (client, + FILE_BROWSER_BASE_KEY "/open_at_first_doc", + NULL); + + if (open) { + PlumaDocument *doc; + gchar *uri; + + doc = pluma_tab_get_document (tab); + + uri = pluma_document_get_uri (doc); + + if (uri != NULL && pluma_utils_uri_has_file_scheme (uri)) { + prepare_auto_root (data); + set_root_from_doc (data, doc); + load_default = FALSE; + } + + g_free (uri); + } + + if (load_default) + restore_default_location (data); + + g_object_unref (client); + + /* Disconnect this signal, it's only called once */ + g_signal_handlers_disconnect_by_func (window, + G_CALLBACK (on_tab_added_cb), + data); +} + +static gchar * +get_filename_from_path (GtkTreeModel *model, GtkTreePath *path) +{ + GtkTreeIter iter; + gchar *uri; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + return pluma_file_browser_utils_uri_basename (uri); +} + +static gboolean +on_confirm_no_trash_cb (PlumaFileBrowserWidget * widget, + GList * files, + PlumaWindow * window) +{ + gchar *normal; + gchar *message; + gchar *secondary; + gboolean result; + + message = _("Cannot move file to trash, do you\nwant to delete permanently?"); + + if (files->next == NULL) { + normal = pluma_file_browser_utils_file_basename (G_FILE (files->data)); + secondary = g_strdup_printf (_("The file \"%s\" cannot be moved to the trash."), normal); + g_free (normal); + } else { + secondary = g_strdup (_("The selected files cannot be moved to the trash.")); + } + + result = pluma_file_browser_utils_confirmation_dialog (window, + GTK_MESSAGE_QUESTION, + message, + secondary, + GTK_STOCK_DELETE, + NULL); + g_free (secondary); + + return result; +} + +static gboolean +on_confirm_delete_cb (PlumaFileBrowserWidget *widget, + PlumaFileBrowserStore *store, + GList *paths, + PlumaWindow *window) +{ + gchar *normal; + gchar *message; + gchar *secondary; + gboolean result; + PlumaFileBrowserPluginData *data; + + data = get_plugin_data (window); + + if (!data->confirm_trash) + return TRUE; + + if (paths->next == NULL) { + normal = get_filename_from_path (GTK_TREE_MODEL (store), (GtkTreePath *)(paths->data)); + message = g_strdup_printf (_("Are you sure you want to permanently delete \"%s\"?"), normal); + g_free (normal); + } else { + message = g_strdup (_("Are you sure you want to permanently delete the selected files?")); + } + + secondary = _("If you delete an item, it is permanently lost."); + + result = pluma_file_browser_utils_confirmation_dialog (window, + GTK_MESSAGE_QUESTION, + message, + secondary, + GTK_STOCK_DELETE, + NULL); + + g_free (message); + + return result; +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-plugin.h b/plugins/filebrowser/pluma-file-browser-plugin.h new file mode 100755 index 00000000..634c56af --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-plugin.h @@ -0,0 +1,71 @@ +/* + * pluma-file-browser-plugin.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_PLUGIN_H__ +#define __PLUMA_FILE_BROWSER_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_FILE_BROWSER_PLUGIN (filetree_plugin_get_type ()) +#define PLUMA_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPlugin)) +#define PLUMA_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginClass)) +#define PLUMA_IS_FILE_BROWSER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN)) +#define PLUMA_IS_FILE_BROWSER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_FILE_BROWSER_PLUGIN)) +#define PLUMA_FILE_BROWSER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_FILE_BROWSER_PLUGIN, PlumaFileBrowserPluginClass)) + +/* Private structure type */ +typedef struct _PlumaFileBrowserPluginPrivate PlumaFileBrowserPluginPrivate; +typedef struct _PlumaFileBrowserPlugin PlumaFileBrowserPlugin; +typedef struct _PlumaFileBrowserPluginClass PlumaFileBrowserPluginClass; + +struct _PlumaFileBrowserPlugin +{ + PlumaPlugin parent_instance; + + /*< private > */ + PlumaFileBrowserPluginPrivate *priv; +}; + + + +struct _PlumaFileBrowserPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType filetree_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule * module); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_PLUGIN_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-store.c b/plugins/filebrowser/pluma-file-browser-store.c new file mode 100755 index 00000000..a046fe42 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-store.c @@ -0,0 +1,3625 @@ +/* + * pluma-file-browser-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "pluma-file-browser-store.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-utils.h" + +#define PLUMA_FILE_BROWSER_STORE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_STORE, \ + PlumaFileBrowserStorePrivate)) + +#define NODE_IS_DIR(node) (FILE_IS_DIR((node)->flags)) +#define NODE_IS_HIDDEN(node) (FILE_IS_HIDDEN((node)->flags)) +#define NODE_IS_TEXT(node) (FILE_IS_TEXT((node)->flags)) +#define NODE_LOADED(node) (FILE_LOADED((node)->flags)) +#define NODE_IS_FILTERED(node) (FILE_IS_FILTERED((node)->flags)) +#define NODE_IS_DUMMY(node) (FILE_IS_DUMMY((node)->flags)) + +#define FILE_BROWSER_NODE_DIR(node) ((FileBrowserNodeDir *)(node)) + +#define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100 +#define STANDARD_ATTRIBUTE_TYPES G_FILE_ATTRIBUTE_STANDARD_TYPE "," \ + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," \ + G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP "," \ + G_FILE_ATTRIBUTE_STANDARD_NAME "," \ + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \ + G_FILE_ATTRIBUTE_STANDARD_ICON + +typedef struct _FileBrowserNode FileBrowserNode; +typedef struct _FileBrowserNodeDir FileBrowserNodeDir; +typedef struct _AsyncData AsyncData; +typedef struct _AsyncNode AsyncNode; + +typedef gint (*SortFunc) (FileBrowserNode * node1, + FileBrowserNode * node2); + +struct _AsyncData +{ + PlumaFileBrowserStore * model; + GCancellable * cancellable; + gboolean trash; + GList * files; + GList * iter; + gboolean removed; +}; + +struct _AsyncNode +{ + FileBrowserNodeDir *dir; + GCancellable *cancellable; + GSList *original_children; +}; + +typedef struct { + PlumaFileBrowserStore * model; + gchar * virtual_root; + GMountOperation * operation; + GCancellable * cancellable; +} MountInfo; + +struct _FileBrowserNode +{ + GFile *file; + guint flags; + gchar *name; + + GdkPixbuf *icon; + GdkPixbuf *emblem; + + FileBrowserNode *parent; + gint pos; + gboolean inserted; +}; + +struct _FileBrowserNodeDir +{ + FileBrowserNode node; + GSList *children; + GHashTable *hidden_file_hash; + + GCancellable *cancellable; + GFileMonitor *monitor; + PlumaFileBrowserStore *model; +}; + +struct _PlumaFileBrowserStorePrivate +{ + FileBrowserNode *root; + FileBrowserNode *virtual_root; + GType column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_NUM]; + + PlumaFileBrowserStoreFilterMode filter_mode; + PlumaFileBrowserStoreFilterFunc filter_func; + gpointer filter_user_data; + + SortFunc sort_func; + + GSList *async_handles; + MountInfo *mount_info; +}; + +static FileBrowserNode *model_find_node (PlumaFileBrowserStore *model, + FileBrowserNode *node, + GFile *uri); +static void model_remove_node (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes); + +static void set_virtual_root_from_node (PlumaFileBrowserStore * model, + FileBrowserNode * node); + +static void pluma_file_browser_store_iface_init (GtkTreeModelIface * iface); +static GtkTreeModelFlags pluma_file_browser_store_get_flags (GtkTreeModel * tree_model); +static gint pluma_file_browser_store_get_n_columns (GtkTreeModel * tree_model); +static GType pluma_file_browser_store_get_column_type (GtkTreeModel * tree_model, + gint index); +static gboolean pluma_file_browser_store_get_iter (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreePath * path); +static GtkTreePath *pluma_file_browser_store_get_path (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static void pluma_file_browser_store_get_value (GtkTreeModel * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value); +static gboolean pluma_file_browser_store_iter_next (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gboolean pluma_file_browser_store_iter_children (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent); +static gboolean pluma_file_browser_store_iter_has_child (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gint pluma_file_browser_store_iter_n_children (GtkTreeModel * tree_model, + GtkTreeIter * iter); +static gboolean pluma_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent, + gint n); +static gboolean pluma_file_browser_store_iter_parent (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * child); +static void pluma_file_browser_store_row_inserted (GtkTreeModel * tree_model, + GtkTreePath * path, + GtkTreeIter * iter); + +static void pluma_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface); +static gboolean pluma_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, + GtkTreePath * path); +static gboolean pluma_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, + GtkTreePath * path); +static gboolean pluma_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, + GtkTreePath * path, + GtkSelectionData * selection_data); + +static void file_browser_node_free (PlumaFileBrowserStore * model, + FileBrowserNode * node); +static void model_add_node (PlumaFileBrowserStore * model, + FileBrowserNode * child, + FileBrowserNode * parent); +static void model_clear (PlumaFileBrowserStore * model, + gboolean free_nodes); +static gint model_sort_default (FileBrowserNode * node1, + FileBrowserNode * node2); +static void model_check_dummy (PlumaFileBrowserStore * model, + FileBrowserNode * node); +static void next_files_async (GFileEnumerator * enumerator, + AsyncNode * async); + +PLUMA_PLUGIN_DEFINE_TYPE_WITH_CODE (PlumaFileBrowserStore, pluma_file_browser_store, + G_TYPE_OBJECT, + PLUMA_PLUGIN_IMPLEMENT_INTERFACE (pluma_file_browser_store_tree_model, + GTK_TYPE_TREE_MODEL, + pluma_file_browser_store_iface_init) + PLUMA_PLUGIN_IMPLEMENT_INTERFACE (pluma_file_browser_store_drag_source, + GTK_TYPE_TREE_DRAG_SOURCE, + pluma_file_browser_store_drag_source_init)) + +/* Properties */ +enum { + PROP_0, + + PROP_ROOT, + PROP_VIRTUAL_ROOT, + PROP_FILTER_MODE +}; + +/* Signals */ +enum +{ + BEGIN_LOADING, + END_LOADING, + ERROR, + NO_TRASH, + RENAME, + BEGIN_REFRESH, + END_REFRESH, + UNLOAD, + NUM_SIGNALS +}; + +static guint model_signals[NUM_SIGNALS] = { 0 }; + +static void +cancel_mount_operation (PlumaFileBrowserStore *obj) +{ + if (obj->priv->mount_info != NULL) + { + obj->priv->mount_info->model = NULL; + g_cancellable_cancel (obj->priv->mount_info->cancellable); + obj->priv->mount_info = NULL; + } +} + +static void +pluma_file_browser_store_finalize (GObject * object) +{ + PlumaFileBrowserStore *obj = PLUMA_FILE_BROWSER_STORE (object); + GSList *item; + + /* Free all the nodes */ + file_browser_node_free (obj, obj->priv->root); + + /* Cancel any asynchronous operations */ + for (item = obj->priv->async_handles; item; item = item->next) + { + AsyncData *data = (AsyncData *) (item->data); + g_cancellable_cancel (data->cancellable); + + data->removed = TRUE; + } + + cancel_mount_operation (obj); + + g_slist_free (obj->priv->async_handles); + G_OBJECT_CLASS (pluma_file_browser_store_parent_class)->finalize (object); +} + +static void +set_gvalue_from_node (GValue *value, + FileBrowserNode *node) +{ + gchar * uri; + + if (node == NULL || !node->file) { + g_value_set_string (value, NULL); + } else { + uri = g_file_get_uri (node->file); + g_value_take_string (value, uri); + } +} + +static void +pluma_file_browser_store_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserStore *obj = PLUMA_FILE_BROWSER_STORE (object); + + switch (prop_id) + { + case PROP_ROOT: + set_gvalue_from_node (value, obj->priv->root); + break; + case PROP_VIRTUAL_ROOT: + set_gvalue_from_node (value, obj->priv->virtual_root); + break; + case PROP_FILTER_MODE: + g_value_set_flags (value, obj->priv->filter_mode); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_store_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserStore *obj = PLUMA_FILE_BROWSER_STORE (object); + + switch (prop_id) + { + case PROP_FILTER_MODE: + pluma_file_browser_store_set_filter_mode (obj, + g_value_get_flags (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_store_class_init (PlumaFileBrowserStoreClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = pluma_file_browser_store_finalize; + + object_class->get_property = pluma_file_browser_store_get_property; + object_class->set_property = pluma_file_browser_store_set_property; + + g_object_class_install_property (object_class, PROP_ROOT, + g_param_spec_string ("root", + "Root", + "The root uri", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_VIRTUAL_ROOT, + g_param_spec_string ("virtual-root", + "Virtual Root", + "The virtual root uri", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_FILTER_MODE, + g_param_spec_flags ("filter-mode", + "Filter Mode", + "The filter mode", + PLUMA_TYPE_FILE_BROWSER_STORE_FILTER_MODE, + pluma_file_browser_store_filter_mode_get_default (), + G_PARAM_READWRITE)); + + model_signals[BEGIN_LOADING] = + g_signal_new ("begin-loading", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + begin_loading), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, + GTK_TYPE_TREE_ITER); + model_signals[END_LOADING] = + g_signal_new ("end-loading", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + end_loading), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, + GTK_TYPE_TREE_ITER); + model_signals[ERROR] = + g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); + model_signals[NO_TRASH] = + g_signal_new ("no-trash", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + no_trash), g_signal_accumulator_true_handled, NULL, + pluma_file_browser_marshal_BOOL__POINTER, + G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); + model_signals[RENAME] = + g_signal_new ("rename", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + rename), NULL, NULL, + pluma_file_browser_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_STRING); + model_signals[BEGIN_REFRESH] = + g_signal_new ("begin-refresh", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + begin_refresh), NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + model_signals[END_REFRESH] = + g_signal_new ("end-refresh", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + end_refresh), NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + model_signals[UNLOAD] = + g_signal_new ("unload", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserStoreClass, + unload), NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserStorePrivate)); +} + +static void +pluma_file_browser_store_iface_init (GtkTreeModelIface * iface) +{ + iface->get_flags = pluma_file_browser_store_get_flags; + iface->get_n_columns = pluma_file_browser_store_get_n_columns; + iface->get_column_type = pluma_file_browser_store_get_column_type; + iface->get_iter = pluma_file_browser_store_get_iter; + iface->get_path = pluma_file_browser_store_get_path; + iface->get_value = pluma_file_browser_store_get_value; + iface->iter_next = pluma_file_browser_store_iter_next; + iface->iter_children = pluma_file_browser_store_iter_children; + iface->iter_has_child = pluma_file_browser_store_iter_has_child; + iface->iter_n_children = pluma_file_browser_store_iter_n_children; + iface->iter_nth_child = pluma_file_browser_store_iter_nth_child; + iface->iter_parent = pluma_file_browser_store_iter_parent; + iface->row_inserted = pluma_file_browser_store_row_inserted; +} + +static void +pluma_file_browser_store_drag_source_init (GtkTreeDragSourceIface * iface) +{ + iface->row_draggable = pluma_file_browser_store_row_draggable; + iface->drag_data_delete = pluma_file_browser_store_drag_data_delete; + iface->drag_data_get = pluma_file_browser_store_drag_data_get; +} + +static void +pluma_file_browser_store_init (PlumaFileBrowserStore * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_STORE_GET_PRIVATE (obj); + + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_URI] = + G_TYPE_STRING; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_NAME] = + G_TYPE_STRING; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS] = + G_TYPE_UINT; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_ICON] = + GDK_TYPE_PIXBUF; + obj->priv->column_types[PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM] = + GDK_TYPE_PIXBUF; + + // Default filter mode is hiding the hidden files + obj->priv->filter_mode = pluma_file_browser_store_filter_mode_get_default (); + obj->priv->sort_func = model_sort_default; +} + +static gboolean +node_has_parent (FileBrowserNode * node, FileBrowserNode * parent) +{ + if (node->parent == NULL) + return FALSE; + + if (node->parent == parent) + return TRUE; + + return node_has_parent (node->parent, parent); +} + +static gboolean +node_in_tree (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + return node_has_parent (node, model->priv->virtual_root); +} + +static gboolean +model_node_visibility (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + if (node == NULL) + return FALSE; + + if (NODE_IS_DUMMY (node)) + return !NODE_IS_HIDDEN (node); + + if (node == model->priv->virtual_root) + return TRUE; + + if (!node_has_parent (node, model->priv->virtual_root)) + return FALSE; + + return !NODE_IS_FILTERED (node); +} + +static gboolean +model_node_inserted (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + return node == model->priv->virtual_root || (model_node_visibility (model, node) && node->inserted); +} + +/* Interface implementation */ + +static GtkTreeModelFlags +pluma_file_browser_store_get_flags (GtkTreeModel * tree_model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + (GtkTreeModelFlags) 0); + + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint +pluma_file_browser_store_get_n_columns (GtkTreeModel * tree_model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), 0); + + return PLUMA_FILE_BROWSER_STORE_COLUMN_NUM; +} + +static GType +pluma_file_browser_store_get_column_type (GtkTreeModel * tree_model, gint idx) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + G_TYPE_INVALID); + g_return_val_if_fail (idx < PLUMA_FILE_BROWSER_STORE_COLUMN_NUM && + idx >= 0, G_TYPE_INVALID); + + return PLUMA_FILE_BROWSER_STORE (tree_model)->priv->column_types[idx]; +} + +static gboolean +pluma_file_browser_store_get_iter (GtkTreeModel * tree_model, + GtkTreeIter * iter, GtkTreePath * path) +{ + gint * indices, depth, i; + FileBrowserNode * node; + PlumaFileBrowserStore * model; + gint num; + + g_assert (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_assert (path != NULL); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + indices = gtk_tree_path_get_indices (path); + depth = gtk_tree_path_get_depth (path); + node = model->priv->virtual_root; + + for (i = 0; i < depth; ++i) { + GSList * item; + + if (node == NULL) + return FALSE; + + num = 0; + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { + FileBrowserNode * child; + + child = (FileBrowserNode *) (item->data); + + if (model_node_inserted (model, child)) { + if (num == indices[i]) { + node = child; + break; + } + + num++; + } + } + + if (item == NULL) + return FALSE; + + node = (FileBrowserNode *) (item->data); + } + + iter->user_data = node; + iter->user_data2 = NULL; + iter->user_data3 = NULL; + + return node != NULL; +} + +static GtkTreePath * +pluma_file_browser_store_get_path_real (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GtkTreePath *path; + gint num = 0; + + path = gtk_tree_path_new (); + + while (node != model->priv->virtual_root) { + GSList *item; + + if (node->parent == NULL) { + gtk_tree_path_free (path); + return NULL; + } + + num = 0; + + for (item = FILE_BROWSER_NODE_DIR (node->parent)->children; item; item = item->next) { + FileBrowserNode *check; + + check = (FileBrowserNode *) (item->data); + + if (model_node_visibility (model, check) && (check == node || check->inserted)) { + if (check == node) { + gtk_tree_path_prepend_index (path, + num); + break; + } + + ++num; + } else if (check == node) { + if (NODE_IS_DUMMY (node)) + g_warning ("Dummy not visible???"); + + gtk_tree_path_free (path); + return NULL; + } + } + + node = node->parent; + } + + return path; +} + +static GtkTreePath * +pluma_file_browser_store_get_path (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), NULL); + g_return_val_if_fail (iter != NULL, NULL); + g_return_val_if_fail (iter->user_data != NULL, NULL); + + return pluma_file_browser_store_get_path_real (PLUMA_FILE_BROWSER_STORE (tree_model), + (FileBrowserNode *) (iter->user_data)); +} + +static void +pluma_file_browser_store_get_value (GtkTreeModel * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value) +{ + FileBrowserNode *node; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + node = (FileBrowserNode *) (iter->user_data); + + g_value_init (value, PLUMA_FILE_BROWSER_STORE (tree_model)->priv->column_types[column]); + + switch (column) { + case PLUMA_FILE_BROWSER_STORE_COLUMN_URI: + set_gvalue_from_node (value, node); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_NAME: + g_value_set_string (value, node->name); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS: + g_value_set_uint (value, node->flags); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_ICON: + g_value_set_object (value, node->icon); + break; + case PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM: + g_value_set_object (value, node->emblem); + break; + default: + g_return_if_reached (); + } +} + +static gboolean +pluma_file_browser_store_iter_next (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + PlumaFileBrowserStore * model; + FileBrowserNode * node; + GSList * item; + GSList * first; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (iter->user_data != NULL, FALSE); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + node = (FileBrowserNode *) (iter->user_data); + + if (node->parent == NULL) + return FALSE; + + first = g_slist_next (g_slist_find (FILE_BROWSER_NODE_DIR (node->parent)->children, node)); + + for (item = first; item; item = item->next) { + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { + iter->user_data = item->data; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +pluma_file_browser_store_iter_children (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent) +{ + FileBrowserNode * node; + PlumaFileBrowserStore * model; + GSList * item; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (parent == NULL + || parent->user_data != NULL, FALSE); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + + if (parent == NULL) + node = model->priv->virtual_root; + else + node = (FileBrowserNode *) (parent->user_data); + + if (node == NULL) + return FALSE; + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { + iter->user_data = item->data; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +filter_tree_model_iter_has_child_real (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GSList *item; + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) { + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) + return TRUE; + } + + return FALSE; +} + +static gboolean +pluma_file_browser_store_iter_has_child (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (iter == NULL + || iter->user_data != NULL, FALSE); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + + if (iter == NULL) + node = model->priv->virtual_root; + else + node = (FileBrowserNode *) (iter->user_data); + + return filter_tree_model_iter_has_child_real (model, node); +} + +static gint +pluma_file_browser_store_iter_n_children (GtkTreeModel * tree_model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + GSList *item; + gint num = 0; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (iter == NULL + || iter->user_data != NULL, FALSE); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + + if (iter == NULL) + node = model->priv->virtual_root; + else + node = (FileBrowserNode *) (iter->user_data); + + if (!NODE_IS_DIR (node)) + return 0; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; item = item->next) + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) + ++num; + + return num; +} + +static gboolean +pluma_file_browser_store_iter_nth_child (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * parent, gint n) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + GSList *item; + gint num = 0; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), + FALSE); + g_return_val_if_fail (parent == NULL + || parent->user_data != NULL, FALSE); + + model = PLUMA_FILE_BROWSER_STORE (tree_model); + + if (parent == NULL) + node = model->priv->virtual_root; + else + node = (FileBrowserNode *) (parent->user_data); + + if (!NODE_IS_DIR (node)) + return FALSE; + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; + item = item->next) { + if (model_node_inserted (model, (FileBrowserNode *) (item->data))) { + if (num == n) { + iter->user_data = item->data; + return TRUE; + } + + ++num; + } + } + + return FALSE; +} + +static gboolean +pluma_file_browser_store_iter_parent (GtkTreeModel * tree_model, + GtkTreeIter * iter, + GtkTreeIter * child) +{ + FileBrowserNode *node; + PlumaFileBrowserStore *model; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model), FALSE); + g_return_val_if_fail (child != NULL, FALSE); + g_return_val_if_fail (child->user_data != NULL, FALSE); + + node = (FileBrowserNode *) (child->user_data); + model = PLUMA_FILE_BROWSER_STORE (tree_model); + + if (!node_in_tree (model, node)) + return FALSE; + + if (node->parent == NULL) + return FALSE; + + iter->user_data = node->parent; + return TRUE; +} + +static void +pluma_file_browser_store_row_inserted (GtkTreeModel * tree_model, + GtkTreePath * path, + GtkTreeIter * iter) +{ + FileBrowserNode * node = (FileBrowserNode *)(iter->user_data); + + node->inserted = TRUE; +} + +static gboolean +pluma_file_browser_store_row_draggable (GtkTreeDragSource * drag_source, + GtkTreePath * path) +{ + GtkTreeIter iter; + PlumaFileBrowserStoreFlag flags; + + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), + &iter, path)) + { + return FALSE; + } + + gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + return !FILE_IS_DUMMY(flags); +} + +static gboolean +pluma_file_browser_store_drag_data_delete (GtkTreeDragSource * drag_source, + GtkTreePath * path) +{ + return FALSE; +} + +static gboolean +pluma_file_browser_store_drag_data_get (GtkTreeDragSource * drag_source, + GtkTreePath * path, + GtkSelectionData * selection_data) +{ + GtkTreeIter iter; + gchar *uri; + gchar *uris[2] = {0, }; + gboolean ret; + + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), + &iter, path)) + { + return FALSE; + } + + gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + g_assert (uri); + + uris[0] = uri; + ret = gtk_selection_data_set_uris (selection_data, uris); + + g_free (uri); + + return ret; +} + +#define FILTER_HIDDEN(mode) (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN) +#define FILTER_BINARY(mode) (mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY) + +/* Private */ +static void +model_begin_loading (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + GtkTreeIter iter; + + iter.user_data = node; + g_signal_emit (model, model_signals[BEGIN_LOADING], 0, &iter); +} + +static void +model_end_loading (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + GtkTreeIter iter; + + iter.user_data = node; + g_signal_emit (model, model_signals[END_LOADING], 0, &iter); +} + +static void +model_node_update_visibility (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GtkTreeIter iter; + + node->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + + if (FILTER_HIDDEN (model->priv->filter_mode) && + NODE_IS_HIDDEN (node)) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + else if (FILTER_BINARY (model->priv->filter_mode) && + (!NODE_IS_TEXT (node) && !NODE_IS_DIR (node))) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + else if (model->priv->filter_func) { + iter.user_data = node; + + if (!model->priv-> + filter_func (model, &iter, + model->priv->filter_user_data)) + node->flags |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED; + } +} + +static gint +collate_nodes (FileBrowserNode * node1, FileBrowserNode * node2) +{ + if (node1->name == NULL) + return -1; + else if (node2->name == NULL) + return 1; + else { + gchar *k1, *k2; + gint result; + + k1 = g_utf8_collate_key_for_filename (node1->name, -1); + k2 = g_utf8_collate_key_for_filename (node2->name, -1); + + result = strcmp (k1, k2); + + g_free (k1); + g_free (k2); + + return result; + } +} + +static gint +model_sort_default (FileBrowserNode * node1, FileBrowserNode * node2) +{ + gint f1; + gint f2; + + f1 = NODE_IS_DUMMY (node1); + f2 = NODE_IS_DUMMY (node2); + + if (f1 && f2) + { + return 0; + } + else if (f1 || f2) + { + return f1 ? -1 : 1; + } + + f1 = NODE_IS_DIR (node1); + f2 = NODE_IS_DIR (node2); + + if (f1 != f2) + { + return f1 ? -1 : 1; + } + + f1 = NODE_IS_HIDDEN (node1); + f2 = NODE_IS_HIDDEN (node2); + + if (f1 != f2) + { + return f2 ? -1 : 1; + } + + return collate_nodes (node1, node2); +} + +static void +model_resort_node (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + FileBrowserNodeDir *dir; + GSList *item; + FileBrowserNode *child; + gint pos = 0; + GtkTreeIter iter; + GtkTreePath *path; + gint *neworder; + + dir = FILE_BROWSER_NODE_DIR (node->parent); + + if (!model_node_visibility (model, node->parent)) { + /* Just sort the children of the parent */ + dir->children = g_slist_sort (dir->children, + (GCompareFunc) (model->priv-> + sort_func)); + } else { + /* Store current positions */ + for (item = dir->children; item; item = item->next) { + child = (FileBrowserNode *) (item->data); + + if (model_node_visibility (model, child)) + child->pos = pos++; + } + + dir->children = g_slist_sort (dir->children, + (GCompareFunc) (model->priv-> + sort_func)); + neworder = g_new (gint, pos); + pos = 0; + + /* Store the new positions */ + for (item = dir->children; item; item = item->next) { + child = (FileBrowserNode *) (item->data); + + if (model_node_visibility (model, child)) + neworder[pos++] = child->pos; + } + + iter.user_data = node->parent; + path = + pluma_file_browser_store_get_path_real (model, + node->parent); + + gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), + path, &iter, neworder); + + g_free (neworder); + gtk_tree_path_free (path); + } +} + +static void +row_changed (PlumaFileBrowserStore * model, + GtkTreePath ** path, + GtkTreeIter * iter) +{ + GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path); + + /* Insert a copy of the actual path here because the row-inserted + signal may alter the path */ + gtk_tree_model_row_changed (GTK_TREE_MODEL(model), *path, iter); + gtk_tree_path_free (*path); + + *path = gtk_tree_row_reference_get_path (ref); + gtk_tree_row_reference_free (ref); +} + +static void +row_inserted (PlumaFileBrowserStore * model, + GtkTreePath ** path, + GtkTreeIter * iter) +{ + /* This function creates a row reference for the path because it's + uncertain what might change the actual model/view when we insert + a node, maybe another directory load is triggered for example. + Because functions that use this function rely on the notion that + the path remains pointed towards the inserted node, we use the + reference to keep track. */ + GtkTreeRowReference *ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), *path); + GtkTreePath * copy = gtk_tree_path_copy (*path); + + gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), copy, iter); + gtk_tree_path_free (copy); + + if (ref) + { + gtk_tree_path_free (*path); + + /* To restore the path, we get the path from the reference. But, since + we inserted a row, the path will be one index further than the + actual path of our node. We therefore call gtk_tree_path_prev */ + *path = gtk_tree_row_reference_get_path (ref); + gtk_tree_path_prev (*path); + } + + gtk_tree_row_reference_free (ref); +} + +static void +row_deleted (PlumaFileBrowserStore * model, + const GtkTreePath * path) +{ + GtkTreePath *copy = gtk_tree_path_copy (path); + + /* Delete a copy of the actual path here because the row-deleted + signal may alter the path */ + gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), copy); + gtk_tree_path_free (copy); +} + +static void +model_refilter_node (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath ** path) +{ + gboolean old_visible; + gboolean new_visible; + FileBrowserNodeDir *dir; + GSList *item; + GtkTreeIter iter; + GtkTreePath *tmppath = NULL; + gboolean in_tree; + + if (node == NULL) + return; + + old_visible = model_node_visibility (model, node); + model_node_update_visibility (model, node); + + in_tree = node_in_tree (model, node); + + if (path == NULL) + { + if (in_tree) + tmppath = pluma_file_browser_store_get_path_real (model, + node); + else + tmppath = gtk_tree_path_new_first (); + + path = &tmppath; + } + + if (NODE_IS_DIR (node)) { + if (in_tree) + gtk_tree_path_down (*path); + + dir = FILE_BROWSER_NODE_DIR (node); + + for (item = dir->children; item; item = item->next) { + model_refilter_node (model, + (FileBrowserNode *) (item->data), + path); + } + + if (in_tree) + gtk_tree_path_up (*path); + } + + if (in_tree) { + new_visible = model_node_visibility (model, node); + + if (old_visible != new_visible) { + if (old_visible) { + node->inserted = FALSE; + row_deleted (model, *path); + } else { + iter.user_data = node; + row_inserted (model, path, &iter); + gtk_tree_path_next (*path); + } + } else if (old_visible) { + gtk_tree_path_next (*path); + } + } + + model_check_dummy (model, node); + + if (tmppath) + gtk_tree_path_free (tmppath); +} + +static void +model_refilter (PlumaFileBrowserStore * model) +{ + model_refilter_node (model, model->priv->root, NULL); +} + +static void +file_browser_node_set_name (FileBrowserNode * node) +{ + g_free (node->name); + + if (node->file) { + node->name = pluma_file_browser_utils_file_basename (node->file); + } else { + node->name = NULL; + } +} + +static void +file_browser_node_init (FileBrowserNode * node, GFile * file, + FileBrowserNode * parent) +{ + if (file != NULL) { + node->file = g_object_ref (file); + file_browser_node_set_name (node); + } + + node->parent = parent; +} + +static FileBrowserNode * +file_browser_node_new (GFile * file, FileBrowserNode * parent) +{ + FileBrowserNode *node = g_slice_new0 (FileBrowserNode); + + file_browser_node_init (node, file, parent); + return node; +} + +static FileBrowserNode * +file_browser_node_dir_new (PlumaFileBrowserStore * model, + GFile * file, FileBrowserNode * parent) +{ + FileBrowserNode *node = + (FileBrowserNode *) g_slice_new0 (FileBrowserNodeDir); + + file_browser_node_init (node, file, parent); + + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; + + FILE_BROWSER_NODE_DIR (node)->model = model; + + return node; +} + +static void +file_browser_node_free_children (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + GSList *item; + + if (node == NULL) + return; + + if (NODE_IS_DIR (node)) { + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; + item = item->next) + file_browser_node_free (model, + (FileBrowserNode *) (item-> + data)); + + g_slist_free (FILE_BROWSER_NODE_DIR (node)->children); + FILE_BROWSER_NODE_DIR (node)->children = NULL; + + /* This node is no longer loaded */ + node->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; + } +} + +static void +file_browser_node_free (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + gchar *uri; + + if (node == NULL) + return; + + if (NODE_IS_DIR (node)) + { + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (node); + + if (dir->cancellable) { + g_cancellable_cancel (dir->cancellable); + g_object_unref (dir->cancellable); + + model_end_loading (model, node); + } + + file_browser_node_free_children (model, node); + + if (dir->monitor) { + g_file_monitor_cancel (dir->monitor); + g_object_unref (dir->monitor); + } + + if (dir->hidden_file_hash) + g_hash_table_destroy (dir->hidden_file_hash); + } + + if (node->file) + { + uri = g_file_get_uri (node->file); + g_signal_emit (model, model_signals[UNLOAD], 0, uri); + + g_free (uri); + g_object_unref (node->file); + } + + if (node->icon) + g_object_unref (node->icon); + + if (node->emblem) + g_object_unref (node->emblem); + + g_free (node->name); + + if (NODE_IS_DIR (node)) + g_slice_free (FileBrowserNodeDir, (FileBrowserNodeDir *)node); + else + g_slice_free (FileBrowserNode, (FileBrowserNode *)node); +} + +/** + * model_remove_node_children: + * @model: the #PlumaFileBrowserStore + * @node: the FileBrowserNode to remove + * @path: the path of the node, or NULL to let the path be calculated + * @free_nodes: whether to also remove the nodes from memory + * + * Removes all the children of node from the model. This function is used + * to remove the child nodes from the _model_. Don't use it to just free + * a node. + **/ +static void +model_remove_node_children (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes) +{ + FileBrowserNodeDir *dir; + GtkTreePath *path_child; + GSList *list; + GSList *item; + + if (node == NULL || !NODE_IS_DIR (node)) + return; + + dir = FILE_BROWSER_NODE_DIR (node); + + if (dir->children == NULL) + return; + + if (!model_node_visibility (model, node)) { + // Node is invisible and therefore the children can just + // be freed + if (free_nodes) + file_browser_node_free_children (model, node); + + return; + } + + if (path == NULL) + path_child = + pluma_file_browser_store_get_path_real (model, node); + else + path_child = gtk_tree_path_copy (path); + + gtk_tree_path_down (path_child); + + list = g_slist_copy (dir->children); + + for (item = list; item; item = item->next) { + model_remove_node (model, (FileBrowserNode *) (item->data), + path_child, free_nodes); + } + + g_slist_free (list); + gtk_tree_path_free (path_child); +} + +/** + * model_remove_node: + * @model: the #PlumaFileBrowserStore + * @node: the FileBrowserNode to remove + * @path: the path to use to remove this node, or NULL to use the path + * calculated from the node itself + * @free_nodes: whether to also remove the nodes from memory + * + * Removes this node and all its children from the model. This function is used + * to remove the node from the _model_. Don't use it to just free + * a node. + **/ +static void +model_remove_node (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GtkTreePath * path, + gboolean free_nodes) +{ + gboolean free_path = FALSE; + FileBrowserNode *parent; + + if (path == NULL) { + path = + pluma_file_browser_store_get_path_real (model, node); + free_path = TRUE; + } + + model_remove_node_children (model, node, path, free_nodes); + + /* Only delete if the node is visible in the tree (but only when it's + not the virtual root) */ + if (model_node_visibility (model, node) && node != model->priv->virtual_root) + { + node->inserted = FALSE; + row_deleted (model, path); + } + + if (free_path) + gtk_tree_path_free (path); + + parent = node->parent; + + if (free_nodes) { + /* Remove the node from the parents children list */ + if (parent) + FILE_BROWSER_NODE_DIR (node->parent)->children = + g_slist_remove (FILE_BROWSER_NODE_DIR + (node->parent)->children, + node); + } + + /* If this is the virtual root, than set the parent as the virtual root */ + if (node == model->priv->virtual_root) + set_virtual_root_from_node (model, parent); + else if (parent && model_node_visibility (model, parent) && !(free_nodes && NODE_IS_DUMMY(node))) + model_check_dummy (model, parent); + + /* Now free the node if necessary */ + if (free_nodes) + file_browser_node_free (model, node); +} + +/** + * model_clear: + * @model: the #PlumaFileBrowserStore + * @free_nodes: whether to also remove the nodes from memory + * + * Removes all nodes from the model. This function is used + * to remove all the nodes from the _model_. Don't use it to just free the + * nodes in the model. + **/ +static void +model_clear (PlumaFileBrowserStore * model, gboolean free_nodes) +{ + GtkTreePath *path; + FileBrowserNodeDir *dir; + FileBrowserNode *dummy; + + path = gtk_tree_path_new (); + model_remove_node_children (model, model->priv->virtual_root, path, + free_nodes); + gtk_tree_path_free (path); + + /* Remove the dummy if there is one */ + if (model->priv->virtual_root) { + dir = FILE_BROWSER_NODE_DIR (model->priv->virtual_root); + + if (dir->children != NULL) { + dummy = (FileBrowserNode *) (dir->children->data); + + if (NODE_IS_DUMMY (dummy) + && model_node_visibility (model, dummy)) { + path = gtk_tree_path_new_first (); + + dummy->inserted = FALSE; + row_deleted (model, path); + gtk_tree_path_free (path); + } + } + } +} + +static void +file_browser_node_unload (PlumaFileBrowserStore * model, + FileBrowserNode * node, gboolean remove_children) +{ + FileBrowserNodeDir *dir; + + if (node == NULL) + return; + + if (!NODE_IS_DIR (node) || !NODE_LOADED (node)) + return; + + dir = FILE_BROWSER_NODE_DIR (node); + + if (remove_children) + model_remove_node_children (model, node, NULL, TRUE); + + if (dir->cancellable) { + g_cancellable_cancel (dir->cancellable); + g_object_unref (dir->cancellable); + + model_end_loading (model, node); + dir->cancellable = NULL; + } + + if (dir->monitor) { + g_file_monitor_cancel (dir->monitor); + g_object_unref (dir->monitor); + + dir->monitor = NULL; + } + + node->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; +} + +static void +model_recomposite_icon_real (PlumaFileBrowserStore * tree_model, + FileBrowserNode * node, + GFileInfo * info) +{ + GdkPixbuf *icon; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_return_if_fail (node != NULL); + + if (node->file == NULL) + return; + + if (info) { + GIcon *gicon = g_file_info_get_icon (info); + if (gicon != NULL) + icon = pluma_file_browser_utils_pixbuf_from_icon (gicon, GTK_ICON_SIZE_MENU); + else + icon = NULL; + } else { + icon = pluma_file_browser_utils_pixbuf_from_file (node->file, GTK_ICON_SIZE_MENU); + } + + if (node->icon) + g_object_unref (node->icon); + + if (node->emblem) { + gint icon_size; + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size); + + if (icon == NULL) { + node->icon = + gdk_pixbuf_new (gdk_pixbuf_get_colorspace (node->emblem), + gdk_pixbuf_get_has_alpha (node->emblem), + gdk_pixbuf_get_bits_per_sample (node->emblem), + icon_size, + icon_size); + } else { + node->icon = gdk_pixbuf_copy (icon); + g_object_unref (icon); + } + + gdk_pixbuf_composite (node->emblem, node->icon, + icon_size - 10, icon_size - 10, 10, + 10, icon_size - 10, icon_size - 10, + 1, 1, GDK_INTERP_NEAREST, 255); + } else { + node->icon = icon; + } +} + +static void +model_recomposite_icon (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + model_recomposite_icon_real (tree_model, + (FileBrowserNode *) (iter->user_data), + NULL); +} + +static FileBrowserNode * +model_create_dummy_node (PlumaFileBrowserStore * model, + FileBrowserNode * parent) +{ + FileBrowserNode *dummy; + + dummy = file_browser_node_new (NULL, parent); + dummy->name = g_strdup (_("(Empty)")); + + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY; + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + return dummy; +} + +static FileBrowserNode * +model_add_dummy_node (PlumaFileBrowserStore * model, + FileBrowserNode * parent) +{ + FileBrowserNode *dummy; + + dummy = model_create_dummy_node (model, parent); + + if (model_node_visibility (model, parent)) + dummy->flags &= ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + model_add_node (model, dummy, parent); + + return dummy; +} + +static void +model_check_dummy (PlumaFileBrowserStore * model, FileBrowserNode * node) +{ + // Hide the dummy child if needed + if (NODE_IS_DIR (node)) { + FileBrowserNode *dummy; + GtkTreeIter iter; + GtkTreePath *path; + guint flags; + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (node); + + if (dir->children == NULL) { + model_add_dummy_node (model, node); + return; + } + + dummy = (FileBrowserNode *) (dir->children->data); + + if (!NODE_IS_DUMMY (dummy)) { + dummy = model_create_dummy_node (model, node); + dir->children = g_slist_prepend (dir->children, dummy); + } + + if (!model_node_visibility (model, node)) { + dummy->flags |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + return; + } + + /* Temporarily set the node to invisible to check + * for real children */ + flags = dummy->flags; + dummy->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (!filter_tree_model_iter_has_child_real (model, node)) { + dummy->flags &= + ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (FILE_IS_HIDDEN (flags)) { + // Was hidden, needs to be inserted + iter.user_data = dummy; + path = + pluma_file_browser_store_get_path_real + (model, dummy); + + row_inserted (model, &path, &iter); + gtk_tree_path_free (path); + } + } else { + if (!FILE_IS_HIDDEN (flags)) { + // Was shown, needs to be removed + + // To get the path we need to set it to visible temporarily + dummy->flags &= + ~PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + path = + pluma_file_browser_store_get_path_real + (model, dummy); + dummy->flags |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + dummy->inserted = FALSE; + row_deleted (model, path); + gtk_tree_path_free (path); + } + } + } +} + +static void +insert_node_sorted (PlumaFileBrowserStore * model, + FileBrowserNode * child, + FileBrowserNode * parent) +{ + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (parent); + + if (model->priv->sort_func == NULL) { + dir->children = g_slist_append (dir->children, child); + } else { + dir->children = + g_slist_insert_sorted (dir->children, child, + (GCompareFunc) (model->priv-> + sort_func)); + } +} + +static void +model_add_node (PlumaFileBrowserStore * model, FileBrowserNode * child, + FileBrowserNode * parent) +{ + /* Add child to parents children */ + insert_node_sorted (model, child, parent); + + if (model_node_visibility (model, parent) && + model_node_visibility (model, child)) { + GtkTreeIter iter; + GtkTreePath *path; + + iter.user_data = child; + path = pluma_file_browser_store_get_path_real (model, child); + + /* Emit row inserted */ + row_inserted (model, &path, &iter); + gtk_tree_path_free (path); + } + + model_check_dummy (model, parent); + model_check_dummy (model, child); +} + +static void +model_add_nodes_batch (PlumaFileBrowserStore * model, + GSList * children, + FileBrowserNode * parent) +{ + GSList *sorted_children; + GSList *child; + GSList *prev; + GSList *l; + FileBrowserNodeDir *dir; + + dir = FILE_BROWSER_NODE_DIR (parent); + + sorted_children = g_slist_sort (children, (GCompareFunc) model->priv->sort_func); + + child = sorted_children; + l = dir->children; + prev = NULL; + + model_check_dummy (model, parent); + + while (child) { + FileBrowserNode *node = child->data; + GtkTreeIter iter; + GtkTreePath *path; + + /* reached the end of the first list, just append the second */ + if (l == NULL) { + + dir->children = g_slist_concat (dir->children, child); + + for (l = child; l; l = l->next) { + if (model_node_visibility (model, parent) && + model_node_visibility (model, l->data)) { + iter.user_data = l->data; + path = pluma_file_browser_store_get_path_real (model, l->data); + + // Emit row inserted + row_inserted (model, &path, &iter); + gtk_tree_path_free (path); + } + + model_check_dummy (model, l->data); + } + + break; + } + + if (model->priv->sort_func (l->data, node) > 0) { + GSList *next_child; + + if (prev == NULL) { + /* prepend to the list */ + dir->children = g_slist_prepend (dir->children, child); + } else { + prev->next = child; + } + + next_child = child->next; + prev = child; + child->next = l; + child = next_child; + + if (model_node_visibility (model, parent) && + model_node_visibility (model, node)) { + iter.user_data = node; + path = pluma_file_browser_store_get_path_real (model, node); + + // Emit row inserted + row_inserted (model, &path, &iter); + gtk_tree_path_free (path); + } + + model_check_dummy (model, node); + + /* try again at the same l position with the + * next child */ + } else { + + /* Move to the next item in the list */ + prev = l; + l = l->next; + } + } +} + +static gchar const * +backup_content_type (GFileInfo * info) +{ + gchar const * content; + + if (!g_file_info_get_is_backup (info)) + return NULL; + + content = g_file_info_get_content_type (info); + + if (!content || g_content_type_equals (content, "application/x-trash")) + return "text/plain"; + + return content; +} + +static void +file_browser_node_set_from_info (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GFileInfo * info, + gboolean isadded) +{ + FileBrowserNodeDir * dir; + gchar const * content; + gchar const * name; + gboolean free_info = FALSE; + GtkTreePath * path; + gchar * uri; + GError * error = NULL; + + if (info == NULL) { + info = g_file_query_info (node->file, + STANDARD_ATTRIBUTE_TYPES, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + + if (!info) { + if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND)) { + uri = g_file_get_uri (node->file); + g_warning ("Could not get info for %s: %s", uri, error->message); + g_free (uri); + } + g_error_free (error); + + return; + } + + free_info = TRUE; + } + + dir = FILE_BROWSER_NODE_DIR (node->parent); + name = g_file_info_get_name (info); + + if (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + else if (dir != NULL && dir->hidden_file_hash != NULL && + g_hash_table_lookup (dir->hidden_file_hash, name) != NULL) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY; + else { + if (!(content = backup_content_type (info))) + content = g_file_info_get_content_type (info); + + if (!content || + g_content_type_is_unknown (content) || + g_content_type_is_a (content, "text/plain")) + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT; + } + + model_recomposite_icon_real (model, node, info); + + if (free_info) + g_object_unref (info); + + if (isadded) { + path = pluma_file_browser_store_get_path_real (model, node); + model_refilter_node (model, node, &path); + gtk_tree_path_free (path); + + model_check_dummy (model, node->parent); + } else { + model_node_update_visibility (model, node); + } +} + +static FileBrowserNode * +node_list_contains_file (GSList *children, GFile * file) +{ + GSList *item; + + for (item = children; item; item = item->next) { + FileBrowserNode *node; + + node = (FileBrowserNode *) (item->data); + + if (node->file != NULL + && g_file_equal (node->file, file)) + return node; + } + + return NULL; +} + +static FileBrowserNode * +model_add_node_from_file (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GFile * file, + GFileInfo * info) +{ + FileBrowserNode *node; + gboolean free_info = FALSE; + GError * error = NULL; + + if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL) { + if (info == NULL) { + info = g_file_query_info (file, + STANDARD_ATTRIBUTE_TYPES, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + free_info = TRUE; + } + + if (!info) { + g_warning ("Error querying file info: %s", error->message); + g_error_free (error); + + /* FIXME: What to do now then... */ + node = file_browser_node_new (file, parent); + } else if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { + node = file_browser_node_dir_new (model, file, parent); + } else { + node = file_browser_node_new (file, parent); + } + + file_browser_node_set_from_info (model, node, info, FALSE); + model_add_node (model, node, parent); + + if (info && free_info) + g_object_unref (info); + } + + return node; +} + +/* We pass in a copy of the list of parent->children so that we do + * not have to check if a file already exists among the ones we just + * added */ +static void +model_add_nodes_from_files (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GSList * original_children, + GList * files) +{ + GList *item; + GSList *nodes = NULL; + + for (item = files; item; item = item->next) { + GFileInfo *info = G_FILE_INFO (item->data); + GFileType type; + gchar const * name; + GFile * file; + FileBrowserNode *node; + + type = g_file_info_get_file_type (info); + + /* Skip all non regular, non directory files */ + if (type != G_FILE_TYPE_REGULAR && + type != G_FILE_TYPE_DIRECTORY && + type != G_FILE_TYPE_SYMBOLIC_LINK) { + g_object_unref (info); + continue; + } + + name = g_file_info_get_name (info); + + /* Skip '.' and '..' directories */ + if (type == G_FILE_TYPE_DIRECTORY && + (strcmp (name, ".") == 0 || + strcmp (name, "..") == 0)) { + continue; + } + + file = g_file_get_child (parent->file, name); + + if ((node = node_list_contains_file (original_children, file)) == NULL) { + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { + node = file_browser_node_dir_new (model, file, parent); + } else { + node = file_browser_node_new (file, parent); + } + + file_browser_node_set_from_info (model, node, info, FALSE); + + nodes = g_slist_prepend (nodes, node); + } + + g_object_unref (file); + g_object_unref (info); + } + + if (nodes) + model_add_nodes_batch (model, nodes, parent); +} + +static FileBrowserNode * +model_add_node_from_dir (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GFile * file) +{ + FileBrowserNode *node; + + /* Check if it already exists */ + if ((node = node_list_contains_file (FILE_BROWSER_NODE_DIR (parent)->children, file)) == NULL) { + node = file_browser_node_dir_new (model, file, parent); + file_browser_node_set_from_info (model, node, NULL, FALSE); + + if (node->name == NULL) { + file_browser_node_set_name (node); + } + + if (node->icon == NULL) { + node->icon = pluma_file_browser_utils_pixbuf_from_theme ("folder", GTK_ICON_SIZE_MENU); + } + + model_add_node (model, node, parent); + } + + return node; +} + +/* Read is sync, but we only do it for local files */ +static void +parse_dot_hidden_file (FileBrowserNode *directory) +{ + gsize file_size; + char *file_contents; + GFile *child; + GFileInfo *info; + GFileType type; + int i; + FileBrowserNodeDir * dir = FILE_BROWSER_NODE_DIR (directory); + + /* FIXME: We only support .hidden on file: uri's for the moment. + * Need to figure out if we should do this async or sync to extend + * it to all types of uris. + */ + if (directory->file == NULL || !g_file_is_native (directory->file)) { + return; + } + + child = g_file_get_child (directory->file, ".hidden"); + info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); + + type = info ? g_file_info_get_file_type (info) : G_FILE_TYPE_UNKNOWN; + + if (info) + g_object_unref (info); + + if (type != G_FILE_TYPE_REGULAR) { + g_object_unref (child); + + return; + } + + if (!g_file_load_contents (child, NULL, &file_contents, &file_size, NULL, NULL)) { + g_object_unref (child); + return; + } + + g_object_unref (child); + + if (dir->hidden_file_hash == NULL) { + dir->hidden_file_hash = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + } + + /* Now parse the data */ + i = 0; + while (i < file_size) { + int start; + + start = i; + while (i < file_size && file_contents[i] != '\n') { + i++; + } + + if (i > start) { + char *hidden_filename; + + hidden_filename = g_strndup (file_contents + start, i - start); + g_hash_table_insert (dir->hidden_file_hash, + hidden_filename, hidden_filename); + } + + i++; + + } + + g_free (file_contents); +} + +static void +on_directory_monitor_event (GFileMonitor * monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + FileBrowserNode * parent) +{ + FileBrowserNode *node; + FileBrowserNodeDir *dir = FILE_BROWSER_NODE_DIR (parent); + + switch (event_type) { + case G_FILE_MONITOR_EVENT_DELETED: + node = node_list_contains_file (dir->children, file); + + if (node != NULL) { + model_remove_node (dir->model, node, NULL, TRUE); + } + break; + case G_FILE_MONITOR_EVENT_CREATED: + if (g_file_query_exists (file, NULL)) { + model_add_node_from_file (dir->model, parent, file, NULL); + } + + break; + default: + break; + } +} + +static void +async_node_free (AsyncNode *async) +{ + g_object_unref (async->cancellable); + g_slist_free (async->original_children); + g_free (async); +} + +static void +model_iterate_next_files_cb (GFileEnumerator * enumerator, + GAsyncResult * result, + AsyncNode * async) +{ + GList * files; + GError * error = NULL; + FileBrowserNodeDir * dir = async->dir; + FileBrowserNode * parent = (FileBrowserNode *)dir; + + files = g_file_enumerator_next_files_finish (enumerator, result, &error); + + if (files == NULL) { + g_file_enumerator_close (enumerator, NULL, NULL); + async_node_free (async); + + if (!error) + { + /* We're done loading */ + g_object_unref (dir->cancellable); + dir->cancellable = NULL; + +/* + * FIXME: This is temporarly, it is a bug in gio: + * http://bugzilla.gnome.org/show_bug.cgi?id=565924 + */ +#ifndef G_OS_WIN32 + if (g_file_is_native (parent->file) && dir->monitor == NULL) { + dir->monitor = g_file_monitor_directory (parent->file, + G_FILE_MONITOR_NONE, + NULL, + NULL); + if (dir->monitor != NULL) + { + g_signal_connect (dir->monitor, + "changed", + G_CALLBACK (on_directory_monitor_event), + parent); + } + } +#endif + + model_check_dummy (dir->model, parent); + model_end_loading (dir->model, parent); + } else { + /* Simply return if we were cancelled */ + if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED) + return; + + /* Otherwise handle the error appropriately */ + g_signal_emit (dir->model, + model_signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY, + error->message); + + file_browser_node_unload (dir->model, (FileBrowserNode *)parent, TRUE); + g_error_free (error); + } + } else if (g_cancellable_is_cancelled (async->cancellable)) { + /* Check cancel state manually */ + g_file_enumerator_close (enumerator, NULL, NULL); + async_node_free (async); + } else { + model_add_nodes_from_files (dir->model, parent, async->original_children, files); + + g_list_free (files); + next_files_async (enumerator, async); + } +} + +static void +next_files_async (GFileEnumerator * enumerator, + AsyncNode * async) +{ + g_file_enumerator_next_files_async (enumerator, + DIRECTORY_LOAD_ITEMS_PER_CALLBACK, + G_PRIORITY_DEFAULT, + async->cancellable, + (GAsyncReadyCallback)model_iterate_next_files_cb, + async); +} + +static void +model_iterate_children_cb (GFile * file, + GAsyncResult * result, + AsyncNode * async) +{ + GError * error = NULL; + GFileEnumerator * enumerator; + + if (g_cancellable_is_cancelled (async->cancellable)) + { + async_node_free (async); + return; + } + + enumerator = g_file_enumerate_children_finish (file, result, &error); + + if (enumerator == NULL) { + /* Simply return if we were cancelled or if the dir is not there */ + FileBrowserNodeDir *dir = async->dir; + + /* Otherwise handle the error appropriately */ + g_signal_emit (dir->model, + model_signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_LOAD_DIRECTORY, + error->message); + + file_browser_node_unload (dir->model, (FileBrowserNode *)dir, TRUE); + g_error_free (error); + async_node_free (async); + } else { + next_files_async (enumerator, async); + } +} + +static void +model_load_directory (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + FileBrowserNodeDir *dir; + AsyncNode *async; + + g_return_if_fail (NODE_IS_DIR (node)); + + dir = FILE_BROWSER_NODE_DIR (node); + + /* Cancel a previous load */ + if (dir->cancellable != NULL) { + file_browser_node_unload (dir->model, node, TRUE); + } + + node->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; + model_begin_loading (model, node); + + /* Read the '.hidden' file first (if any) */ + parse_dot_hidden_file (node); + + dir->cancellable = g_cancellable_new (); + + async = g_new (AsyncNode, 1); + async->dir = dir; + async->cancellable = g_object_ref (dir->cancellable); + async->original_children = g_slist_copy (dir->children); + + /* Start loading async */ + g_file_enumerate_children_async (node->file, + STANDARD_ATTRIBUTE_TYPES, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_DEFAULT, + async->cancellable, + (GAsyncReadyCallback)model_iterate_children_cb, + async); +} + +static GList * +get_parent_files (PlumaFileBrowserStore * model, GFile * file) +{ + GList * result = NULL; + + result = g_list_prepend (result, g_object_ref (file)); + + while ((file = g_file_get_parent (file))) { + if (g_file_equal (file, model->priv->root->file)) { + g_object_unref (file); + break; + } + + result = g_list_prepend (result, file); + } + + return result; +} + +static void +model_fill (PlumaFileBrowserStore * model, FileBrowserNode * node, + GtkTreePath ** path) +{ + gboolean free_path = FALSE; + GtkTreeIter iter = {0,}; + GSList *item; + FileBrowserNode *child; + + if (node == NULL) { + node = model->priv->virtual_root; + *path = gtk_tree_path_new (); + free_path = TRUE; + } + + if (*path == NULL) { + *path = + pluma_file_browser_store_get_path_real (model, node); + free_path = TRUE; + } + + if (!model_node_visibility (model, node)) { + if (free_path) + gtk_tree_path_free (*path); + + return; + } + + if (node != model->priv->virtual_root) { + /* Insert node */ + iter.user_data = node; + + row_inserted(model, path, &iter); + } + + if (NODE_IS_DIR (node)) { + /* Go to the first child */ + gtk_tree_path_down (*path); + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; + item = item->next) { + child = (FileBrowserNode *) (item->data); + + if (model_node_visibility (model, child)) { + model_fill (model, child, path); + + /* Increase path for next child */ + gtk_tree_path_next (*path); + } + } + + /* Move back up to node path */ + gtk_tree_path_up (*path); + } + + model_check_dummy (model, node); + + if (free_path) + gtk_tree_path_free (*path); +} + +static void +set_virtual_root_from_node (PlumaFileBrowserStore * model, + FileBrowserNode * node) +{ + FileBrowserNode *next; + FileBrowserNode *prev; + FileBrowserNode *check; + FileBrowserNodeDir *dir; + GSList *item; + GSList *copy; + GtkTreePath *empty = NULL; + + prev = node; + next = prev->parent; + + /* Free all the nodes below that we don't need in cache */ + while (prev != model->priv->root) { + dir = FILE_BROWSER_NODE_DIR (next); + copy = g_slist_copy (dir->children); + + for (item = copy; item; item = item->next) { + check = (FileBrowserNode *) (item->data); + + if (prev == node) { + /* Only free the children, keeping this depth in cache */ + if (check != node) { + file_browser_node_free_children + (model, check); + file_browser_node_unload (model, + check, + FALSE); + } + } else if (check != prev) { + /* Only free when the node is not in the chain */ + dir->children = + g_slist_remove (dir->children, check); + file_browser_node_free (model, check); + } + } + + if (prev != node) + file_browser_node_unload (model, next, FALSE); + + g_slist_free (copy); + prev = next; + next = prev->parent; + } + + /* Free all the nodes up that we don't need in cache */ + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; + item = item->next) { + check = (FileBrowserNode *) (item->data); + + if (NODE_IS_DIR (check)) { + for (copy = + FILE_BROWSER_NODE_DIR (check)->children; copy; + copy = copy->next) { + file_browser_node_free_children (model, + (FileBrowserNode + *) + (copy-> + data)); + file_browser_node_unload (model, + (FileBrowserNode + *) (copy->data), + FALSE); + } + } else if (NODE_IS_DUMMY (check)) { + check->flags |= + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN; + } + } + + /* Now finally, set the virtual root, and load it up! */ + model->priv->virtual_root = node; + + /* Notify that the virtual-root has changed before loading up new nodes so that the + "root_changed" signal can be emitted before any "inserted" signals */ + g_object_notify (G_OBJECT (model), "virtual-root"); + + model_fill (model, NULL, &empty); + + if (!NODE_LOADED (node)) + model_load_directory (model, node); +} + +static void +set_virtual_root_from_file (PlumaFileBrowserStore * model, + GFile * file) +{ + GList * files; + GList * item; + FileBrowserNode * parent; + GFile * check; + + /* Always clear the model before altering the nodes */ + model_clear (model, FALSE); + + /* Create the node path, get all the uri's */ + files = get_parent_files (model, file); + parent = model->priv->root; + + for (item = files; item; item = item->next) { + check = G_FILE (item->data); + + parent = model_add_node_from_dir (model, parent, check); + g_object_unref (check); + } + + g_list_free (files); + set_virtual_root_from_node (model, parent); +} + +static FileBrowserNode * +model_find_node_children (PlumaFileBrowserStore * model, + FileBrowserNode * parent, + GFile * file) +{ + FileBrowserNodeDir *dir; + FileBrowserNode *child; + FileBrowserNode *result; + GSList *children; + + if (!NODE_IS_DIR (parent)) + return NULL; + + dir = FILE_BROWSER_NODE_DIR (parent); + + for (children = dir->children; children; children = children->next) { + child = (FileBrowserNode *)(children->data); + + result = model_find_node (model, child, file); + + if (result) + return result; + } + + return NULL; +} + +static FileBrowserNode * +model_find_node (PlumaFileBrowserStore * model, + FileBrowserNode * node, + GFile * file) +{ + if (node == NULL) + node = model->priv->root; + + if (node->file && g_file_equal (node->file, file)) + return node; + + if (NODE_IS_DIR (node) && g_file_has_prefix (file, node->file)) + return model_find_node_children (model, node, file); + + return NULL; +} + +static GQuark +pluma_file_browser_store_error_quark (void) +{ + static GQuark quark = 0; + + if (G_UNLIKELY (quark == 0)) { + quark = g_quark_from_string ("pluma_file_browser_store_error"); + } + + return quark; +} + +static GFile * +unique_new_name (GFile * directory, gchar const * name) +{ + GFile * newuri = NULL; + guint num = 0; + gchar * newname; + + while (newuri == NULL || g_file_query_exists (newuri, NULL)) { + if (newuri != NULL) + g_object_unref (newuri); + + if (num == 0) + newname = g_strdup (name); + else + newname = g_strdup_printf ("%s(%d)", name, num); + + newuri = g_file_get_child (directory, newname); + g_free (newname); + + ++num; + } + + return newuri; +} + +static PlumaFileBrowserStoreResult +model_root_mounted (PlumaFileBrowserStore * model, gchar const * virtual_root) +{ + model_check_dummy (model, model->priv->root); + g_object_notify (G_OBJECT (model), "root"); + + if (virtual_root != NULL) + return + pluma_file_browser_store_set_virtual_root_from_string + (model, virtual_root); + else + set_virtual_root_from_node (model, + model->priv->root); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +static void +handle_root_error (PlumaFileBrowserStore * model, GError *error) +{ + FileBrowserNode * root; + + g_signal_emit (model, + model_signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + error->message); + + /* Set the virtual root to the root */ + root = model->priv->root; + model->priv->virtual_root = root; + + /* Set the root to be loaded */ + root->flags |= PLUMA_FILE_BROWSER_STORE_FLAG_LOADED; + + /* Check the dummy */ + model_check_dummy (model, root); + + g_object_notify (G_OBJECT (model), "root"); + g_object_notify (G_OBJECT (model), "virtual-root"); +} + +static void +mount_cb (GFile * file, + GAsyncResult * res, + MountInfo * mount_info) +{ + gboolean mounted; + GError * error = NULL; + PlumaFileBrowserStore * model = mount_info->model; + + mounted = g_file_mount_enclosing_volume_finish (file, res, &error); + + if (mount_info->model) + { + model->priv->mount_info = NULL; + model_end_loading (model, model->priv->root); + } + + if (!mount_info->model || g_cancellable_is_cancelled (mount_info->cancellable)) + { + // Reset because it might be reused? + g_cancellable_reset (mount_info->cancellable); + } + else if (mounted) + { + model_root_mounted (model, mount_info->virtual_root); + } + else if (error->code != G_IO_ERROR_CANCELLED) + { + handle_root_error (model, error); + } + + if (error) + g_error_free (error); + + g_object_unref (mount_info->operation); + g_object_unref (mount_info->cancellable); + g_free (mount_info->virtual_root); + + g_free (mount_info); +} + +static PlumaFileBrowserStoreResult +model_mount_root (PlumaFileBrowserStore * model, gchar const * virtual_root) +{ + GFileInfo * info; + GError * error = NULL; + MountInfo * mount_info; + + info = g_file_query_info (model->priv->root->file, + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + + if (!info) { + if (error->code == G_IO_ERROR_NOT_MOUNTED) { + /* Try to mount it */ + FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable = g_cancellable_new (); + + mount_info = g_new(MountInfo, 1); + mount_info->model = model; + mount_info->virtual_root = g_strdup (virtual_root); + + /* FIXME: we should be setting the correct window */ + mount_info->operation = gtk_mount_operation_new (NULL); + mount_info->cancellable = g_object_ref (FILE_BROWSER_NODE_DIR (model->priv->root)->cancellable); + + model_begin_loading (model, model->priv->root); + g_file_mount_enclosing_volume (model->priv->root->file, + G_MOUNT_MOUNT_NONE, + mount_info->operation, + mount_info->cancellable, + (GAsyncReadyCallback)mount_cb, + mount_info); + + model->priv->mount_info = mount_info; + return PLUMA_FILE_BROWSER_STORE_RESULT_MOUNTING; + } + else + { + handle_root_error (model, error); + } + + g_error_free (error); + } else { + g_object_unref (info); + + return model_root_mounted (model, virtual_root); + } + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +/* Public */ +PlumaFileBrowserStore * +pluma_file_browser_store_new (gchar const *root) +{ + PlumaFileBrowserStore *obj = + PLUMA_FILE_BROWSER_STORE (g_object_new + (PLUMA_TYPE_FILE_BROWSER_STORE, + NULL)); + + pluma_file_browser_store_set_root (obj, root); + return obj; +} + +void +pluma_file_browser_store_set_value (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter, gint column, + GValue * value) +{ + gpointer data; + FileBrowserNode *node; + GtkTreePath *path; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (tree_model)); + g_return_if_fail (column == + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM); + g_return_if_fail (G_VALUE_HOLDS_OBJECT (value)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + data = g_value_get_object (value); + + if (data) + g_return_if_fail (GDK_IS_PIXBUF (data)); + + node = (FileBrowserNode *) (iter->user_data); + + if (node->emblem) + g_object_unref (node->emblem); + + if (data) + node->emblem = g_object_ref (GDK_PIXBUF (data)); + else + node->emblem = NULL; + + model_recomposite_icon (tree_model, iter); + + if (model_node_visibility (tree_model, node)) { + path = pluma_file_browser_store_get_path (GTK_TREE_MODEL (tree_model), + iter); + row_changed (tree_model, &path, iter); + gtk_tree_path_free (path); + } +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter != NULL, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter->user_data != NULL, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + model_clear (model, FALSE); + set_virtual_root_from_node (model, + (FileBrowserNode *) (iter->user_data)); + + return TRUE; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_from_string + (PlumaFileBrowserStore * model, gchar const *root) { + GFile *file; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + file = g_file_new_for_uri (root); + if (file == NULL) { + g_warning ("Invalid uri (%s)", root); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + + /* Check if uri is already the virtual root */ + if (model->priv->virtual_root && + g_file_equal (model->priv->virtual_root->file, file)) { + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + + /* Check if uri is the root itself */ + if (g_file_equal (model->priv->root->file, file)) { + g_object_unref (file); + + /* Always clear the model before altering the nodes */ + model_clear (model, FALSE); + set_virtual_root_from_node (model, model->priv->root); + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; + } + + if (!g_file_has_prefix (file, model->priv->root->file)) { + gchar *str, *str1; + + str = g_file_get_parse_name (model->priv->root->file); + str1 = g_file_get_parse_name (file); + + g_warning + ("Virtual root (%s) is not below actual root (%s)", + str1, str); + + g_free (str); + g_free (str1); + + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_ERROR; + } + + set_virtual_root_from_file (model, file); + g_object_unref (file); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_top (PlumaFileBrowserStore * + model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (model->priv->virtual_root == model->priv->root) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + model_clear (model, FALSE); + set_virtual_root_from_node (model, model->priv->root); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_up (PlumaFileBrowserStore * + model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (model->priv->virtual_root == model->priv->root) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + model_clear (model, FALSE); + set_virtual_root_from_node (model, + model->priv->virtual_root->parent); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +gboolean +pluma_file_browser_store_get_iter_virtual_root (PlumaFileBrowserStore * + model, GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + if (model->priv->virtual_root == NULL) + return FALSE; + + iter->user_data = model->priv->virtual_root; + return TRUE; +} + +gboolean +pluma_file_browser_store_get_iter_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + if (model->priv->root == NULL) + return FALSE; + + iter->user_data = model->priv->root; + return TRUE; +} + +gboolean +pluma_file_browser_store_iter_equal (PlumaFileBrowserStore * model, + GtkTreeIter * iter1, + GtkTreeIter * iter2) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (iter1 != NULL, FALSE); + g_return_val_if_fail (iter2 != NULL, FALSE); + g_return_val_if_fail (iter1->user_data != NULL, FALSE); + g_return_val_if_fail (iter2->user_data != NULL, FALSE); + + return (iter1->user_data == iter2->user_data); +} + +void +pluma_file_browser_store_cancel_mount_operation (PlumaFileBrowserStore *store) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (store)); + + cancel_mount_operation (store); +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root_and_virtual_root (PlumaFileBrowserStore * + model, + gchar const *root, + gchar const *virtual_root) +{ + GFile * file = NULL; + GFile * vfile = NULL; + FileBrowserNode * node; + gboolean equal = FALSE; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (root == NULL && model->priv->root == NULL) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + if (root != NULL) { + file = g_file_new_for_uri (root); + } + + if (root != NULL && model->priv->root != NULL) { + equal = g_file_equal (file, model->priv->root->file); + + if (equal && virtual_root == NULL) { + g_object_unref (file); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + } + + if (virtual_root) { + vfile = g_file_new_for_uri (virtual_root); + + if (equal && g_file_equal (vfile, model->priv->virtual_root->file)) { + if (file) + g_object_unref (file); + + g_object_unref (vfile); + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + } + + g_object_unref (vfile); + } + + /* make sure to cancel any previous mount operations */ + cancel_mount_operation (model); + + /* Always clear the model before altering the nodes */ + model_clear (model, TRUE); + file_browser_node_free (model, model->priv->root); + + model->priv->root = NULL; + model->priv->virtual_root = NULL; + + if (file != NULL) { + /* Create the root node */ + node = file_browser_node_dir_new (model, file, NULL); + + g_object_unref (file); + + model->priv->root = node; + return model_mount_root (model, virtual_root); + } else { + g_object_notify (G_OBJECT (model), "root"); + g_object_notify (G_OBJECT (model), "virtual-root"); + } + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root (PlumaFileBrowserStore * model, + gchar const *root) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + return pluma_file_browser_store_set_root_and_virtual_root (model, + root, + NULL); +} + +gchar * +pluma_file_browser_store_get_root (PlumaFileBrowserStore * model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), NULL); + + if (model->priv->root == NULL || model->priv->root->file == NULL) + return NULL; + else + return g_file_get_uri (model->priv->root->file); +} + +gchar * +pluma_file_browser_store_get_virtual_root (PlumaFileBrowserStore * model) +{ + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), NULL); + + if (model->priv->virtual_root == NULL || model->priv->virtual_root->file == NULL) + return NULL; + else + return g_file_get_uri (model->priv->virtual_root->file); +} + +void +_pluma_file_browser_store_iter_expanded (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + node = (FileBrowserNode *) (iter->user_data); + + if (NODE_IS_DIR (node) && !NODE_LOADED (node)) { + /* Load it now */ + model_load_directory (model, node); + } +} + +void +_pluma_file_browser_store_iter_collapsed (PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + FileBrowserNode *node; + GSList *item; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + g_return_if_fail (iter != NULL); + g_return_if_fail (iter->user_data != NULL); + + node = (FileBrowserNode *) (iter->user_data); + + if (NODE_IS_DIR (node) && NODE_LOADED (node)) { + /* Unload children of the children, keeping 1 depth in cache */ + + for (item = FILE_BROWSER_NODE_DIR (node)->children; item; + item = item->next) { + node = (FileBrowserNode *) (item->data); + + if (NODE_IS_DIR (node) && NODE_LOADED (node)) { + file_browser_node_unload (model, node, + TRUE); + model_check_dummy (model, node); + } + } + } +} + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_get_filter_mode (PlumaFileBrowserStore * model) +{ + return model->priv->filter_mode; +} + +void +pluma_file_browser_store_set_filter_mode (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterMode + mode) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + + if (model->priv->filter_mode == mode) + return; + + model->priv->filter_mode = mode; + model_refilter (model); + + g_object_notify (G_OBJECT (model), "filter-mode"); +} + +void +pluma_file_browser_store_set_filter_func (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterFunc + func, gpointer user_data) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + + model->priv->filter_func = func; + model->priv->filter_user_data = user_data; + model_refilter (model); +} + +void +pluma_file_browser_store_refilter (PlumaFileBrowserStore * model) +{ + model_refilter (model); +} + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_filter_mode_get_default (void) +{ + return PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; +} + +void +pluma_file_browser_store_refresh (PlumaFileBrowserStore * model) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model)); + + if (model->priv->root == NULL || model->priv->virtual_root == NULL) + return; + + /* Clear the model */ + g_signal_emit (model, model_signals[BEGIN_REFRESH], 0); + file_browser_node_unload (model, model->priv->virtual_root, TRUE); + model_load_directory (model, model->priv->virtual_root); + g_signal_emit (model, model_signals[END_REFRESH], 0); +} + +static void +reparent_node (FileBrowserNode * node, gboolean reparent) +{ + FileBrowserNodeDir * dir; + GSList * child; + GFile * parent; + gchar * base; + + if (!node->file) { + return; + } + + if (reparent) { + parent = node->parent->file; + base = g_file_get_basename (node->file); + g_object_unref (node->file); + + node->file = g_file_get_child (parent, base); + g_free (base); + } + + if (NODE_IS_DIR (node)) { + dir = FILE_BROWSER_NODE_DIR (node); + + for (child = dir->children; child; child = child->next) { + reparent_node ((FileBrowserNode *)child->data, TRUE); + } + } +} + +gboolean +pluma_file_browser_store_rename (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + const gchar * new_name, + GError ** error) +{ + FileBrowserNode *node; + GFile * file; + GFile * parent; + GFile * previous; + GError * err = NULL; + gchar * olduri; + gchar * newuri; + GtkTreePath *path; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (iter->user_data != NULL, FALSE); + + node = (FileBrowserNode *) (iter->user_data); + + parent = g_file_get_parent (node->file); + g_return_val_if_fail (parent != NULL, FALSE); + + file = g_file_get_child (parent, new_name); + g_object_unref (parent); + + if (g_file_equal (node->file, file)) { + g_object_unref (file); + return TRUE; + } + + if (g_file_move (node->file, file, G_FILE_COPY_NONE, NULL, NULL, NULL, &err)) { + previous = node->file; + node->file = file; + + /* This makes sure the actual info for the node is requeried */ + file_browser_node_set_name (node); + file_browser_node_set_from_info (model, node, NULL, TRUE); + + reparent_node (node, FALSE); + + if (model_node_visibility (model, node)) { + path = pluma_file_browser_store_get_path_real (model, node); + row_changed (model, &path, iter); + gtk_tree_path_free (path); + + /* Reorder this item */ + model_resort_node (model, node); + } else { + g_object_unref (previous); + + if (error != NULL) + *error = g_error_new_literal (pluma_file_browser_store_error_quark (), + PLUMA_FILE_BROWSER_ERROR_RENAME, + _("The renamed file is currently filtered out. You need to adjust your filter settings to make the file visible")); + return FALSE; + } + + olduri = g_file_get_uri (previous); + newuri = g_file_get_uri (node->file); + + g_signal_emit (model, model_signals[RENAME], 0, olduri, newuri); + + g_object_unref (previous); + g_free (olduri); + g_free (newuri); + + return TRUE; + } else { + g_object_unref (file); + + if (err) { + if (error != NULL) { + *error = + g_error_new_literal + (pluma_file_browser_store_error_quark (), + PLUMA_FILE_BROWSER_ERROR_RENAME, + err->message); + } + + g_error_free (err); + } + + return FALSE; + } +} + +static void +async_data_free (AsyncData * data) +{ + g_object_unref (data->cancellable); + + g_list_foreach (data->files, (GFunc)g_object_unref, NULL); + g_list_free (data->files); + + if (!data->removed) + data->model->priv->async_handles = g_slist_remove (data->model->priv->async_handles, data); + + g_free (data); +} + +static gboolean +emit_no_trash (AsyncData * data) +{ + /* Emit the no trash error */ + gboolean ret; + + g_signal_emit (data->model, model_signals[NO_TRASH], 0, data->files, &ret); + return ret; +} + +typedef struct { + PlumaFileBrowserStore * model; + GFile * file; +} IdleDelete; + +static gboolean +file_deleted (IdleDelete * data) +{ + FileBrowserNode * node; + node = model_find_node (data->model, NULL, data->file); + + if (node != NULL) + model_remove_node (data->model, node, NULL, TRUE); + + return FALSE; +} + +static gboolean +delete_files (GIOSchedulerJob * job, + GCancellable * cancellable, + AsyncData * data) +{ + GFile * file; + GError * error = NULL; + gboolean ret; + gint code; + IdleDelete delete; + + /* Check if our job is done */ + if (!data->iter) + return FALSE; + + /* Move a file to the trash */ + file = G_FILE (data->iter->data); + + if (data->trash) + ret = g_file_trash (file, cancellable, &error); + else + ret = g_file_delete (file, cancellable, &error); + + if (ret) { + delete.model = data->model; + delete.file = file; + + /* Remove the file from the model in the main loop */ + g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)file_deleted, &delete, NULL); + } else if (!ret && error) { + code = error->code; + g_error_free (error); + + if (data->trash && code == G_IO_ERROR_NOT_SUPPORTED) { + /* Trash is not supported on this system ... */ + if (g_io_scheduler_job_send_to_mainloop (job, (GSourceFunc)emit_no_trash, data, NULL)) + { + /* Changes this into a delete job */ + data->trash = FALSE; + data->iter = data->files; + + return TRUE; + } + + /* End the job */ + return FALSE; + } else if (code == G_IO_ERROR_CANCELLED) { + /* Job has been cancelled, just let the job end */ + return FALSE; + } + } + + /* Process the next item */ + data->iter = data->iter->next; + return TRUE; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete_all (PlumaFileBrowserStore *model, + GList *rows, gboolean trash) +{ + FileBrowserNode * node; + AsyncData * data; + GList * files = NULL; + GList * row; + GtkTreeIter iter; + GtkTreePath * prev = NULL; + GtkTreePath * path; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + if (rows == NULL) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + /* First we sort the paths so that we can later on remove any + files/directories that are actually subfiles/directories of + a directory that's also deleted */ + rows = g_list_sort (g_list_copy (rows), (GCompareFunc)gtk_tree_path_compare); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) + continue; + + /* Skip if the current path is actually a descendant of the + previous path */ + if (prev != NULL && gtk_tree_path_is_descendant (path, prev)) + continue; + + prev = path; + node = (FileBrowserNode *)(iter.user_data); + files = g_list_prepend (files, g_object_ref (node->file)); + } + + data = g_new (AsyncData, 1); + + data->model = model; + data->cancellable = g_cancellable_new (); + data->files = files; + data->trash = trash; + data->iter = files; + data->removed = FALSE; + + model->priv->async_handles = + g_slist_prepend (model->priv->async_handles, data); + + g_io_scheduler_push_job ((GIOSchedulerJobFunc)delete_files, + data, + (GDestroyNotify)async_data_free, + G_PRIORITY_DEFAULT, + data->cancellable); + g_list_free (rows); + + return PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete (PlumaFileBrowserStore * model, + GtkTreeIter * iter, gboolean trash) +{ + FileBrowserNode *node; + GList *rows = NULL; + PlumaFileBrowserStoreResult result; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter != NULL, PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + g_return_val_if_fail (iter->user_data != NULL, PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE); + + node = (FileBrowserNode *) (iter->user_data); + + if (NODE_IS_DUMMY (node)) + return PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE; + + rows = g_list_append(NULL, pluma_file_browser_store_get_path_real (model, node)); + result = pluma_file_browser_store_delete_all (model, rows, trash); + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +gboolean +pluma_file_browser_store_new_file (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter) +{ + GFile * file; + GFileOutputStream * stream; + FileBrowserNodeDir *parent_node; + gboolean result = FALSE; + FileBrowserNode *node; + GError * error = NULL; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (parent != NULL, FALSE); + g_return_val_if_fail (parent->user_data != NULL, FALSE); + g_return_val_if_fail (NODE_IS_DIR + ((FileBrowserNode *) (parent->user_data)), + FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + parent_node = FILE_BROWSER_NODE_DIR (parent->user_data); + /* Translators: This is the default name of new files created by the file browser pane. */ + file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("file")); + + stream = g_file_create (file, G_FILE_CREATE_NONE, NULL, &error); + + if (!stream) + { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_NEW_FILE, + error->message); + g_error_free (error); + } else { + g_object_unref (stream); + node = model_add_node_from_file (model, + (FileBrowserNode *)parent_node, + file, + NULL); + + if (model_node_visibility (model, node)) { + iter->user_data = node; + result = TRUE; + } else { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_NEW_FILE, + _ + ("The new file is currently filtered out. You need to adjust your filter settings to make the file visible")); + } + } + + g_object_unref (file); + return result; +} + +gboolean +pluma_file_browser_store_new_directory (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter) +{ + GFile * file; + FileBrowserNodeDir *parent_node; + GError * error = NULL; + FileBrowserNode *node; + gboolean result = FALSE; + + g_return_val_if_fail (PLUMA_IS_FILE_BROWSER_STORE (model), FALSE); + g_return_val_if_fail (parent != NULL, FALSE); + g_return_val_if_fail (parent->user_data != NULL, FALSE); + g_return_val_if_fail (NODE_IS_DIR + ((FileBrowserNode *) (parent->user_data)), + FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + parent_node = FILE_BROWSER_NODE_DIR (parent->user_data); + /* Translators: This is the default name of new directories created by the file browser pane. */ + file = unique_new_name (((FileBrowserNode *) parent_node)->file, _("directory")); + + if (!g_file_make_directory (file, NULL, &error)) { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_NEW_DIRECTORY, + error->message); + g_error_free (error); + } else { + node = model_add_node_from_file (model, + (FileBrowserNode *)parent_node, + file, + NULL); + + if (model_node_visibility (model, node)) { + iter->user_data = node; + result = TRUE; + } else { + g_signal_emit (model, model_signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_NEW_FILE, + _ + ("The new directory is currently filtered out. You need to adjust your filter settings to make the directory visible")); + } + } + + g_object_unref (file); + return result; +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-store.h b/plugins/filebrowser/pluma-file-browser-store.h new file mode 100755 index 00000000..65b75e08 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-store.h @@ -0,0 +1,200 @@ +/* + * pluma-file-browser-store.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_STORE_H__ +#define __PLUMA_FILE_BROWSER_STORE_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_STORE (pluma_file_browser_store_get_type ()) +#define PLUMA_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStore)) +#define PLUMA_FILE_BROWSER_STORE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStore const)) +#define PLUMA_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStoreClass)) +#define PLUMA_IS_FILE_BROWSER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_STORE)) +#define PLUMA_IS_FILE_BROWSER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_STORE)) +#define PLUMA_FILE_BROWSER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_STORE, PlumaFileBrowserStoreClass)) + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON = 0, + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, + PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM, + PLUMA_FILE_BROWSER_STORE_COLUMN_NUM +} PlumaFileBrowserStoreColumn; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY = 1 << 0, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN = 1 << 1, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT = 1 << 2, + PLUMA_FILE_BROWSER_STORE_FLAG_LOADED = 1 << 3, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED = 1 << 4, + PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY = 1 << 5 +} PlumaFileBrowserStoreFlag; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_RESULT_OK, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE, + PLUMA_FILE_BROWSER_STORE_RESULT_ERROR, + PLUMA_FILE_BROWSER_STORE_RESULT_NO_TRASH, + PLUMA_FILE_BROWSER_STORE_RESULT_MOUNTING, + PLUMA_FILE_BROWSER_STORE_RESULT_NUM +} PlumaFileBrowserStoreResult; + +typedef enum +{ + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_NONE = 0, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN = 1 << 0, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY = 1 << 1 +} PlumaFileBrowserStoreFilterMode; + +#define FILE_IS_DIR(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_DIRECTORY) +#define FILE_IS_HIDDEN(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_HIDDEN) +#define FILE_IS_TEXT(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_TEXT) +#define FILE_LOADED(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_LOADED) +#define FILE_IS_FILTERED(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_FILTERED) +#define FILE_IS_DUMMY(flags) (flags & PLUMA_FILE_BROWSER_STORE_FLAG_IS_DUMMY) + +typedef struct _PlumaFileBrowserStore PlumaFileBrowserStore; +typedef struct _PlumaFileBrowserStoreClass PlumaFileBrowserStoreClass; +typedef struct _PlumaFileBrowserStorePrivate PlumaFileBrowserStorePrivate; + +typedef gboolean (*PlumaFileBrowserStoreFilterFunc) (PlumaFileBrowserStore + * model, + GtkTreeIter * iter, + gpointer user_data); + +struct _PlumaFileBrowserStore +{ + GObject parent; + + PlumaFileBrowserStorePrivate *priv; +}; + +struct _PlumaFileBrowserStoreClass { + GObjectClass parent_class; + + /* Signals */ + void (*begin_loading) (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + void (*end_loading) (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + void (*error) (PlumaFileBrowserStore * model, + guint code, + gchar * message); + gboolean (*no_trash) (PlumaFileBrowserStore * model, + GList * files); + void (*rename) (PlumaFileBrowserStore * model, + const gchar * olduri, + const gchar * newuri); + void (*begin_refresh) (PlumaFileBrowserStore * model); + void (*end_refresh) (PlumaFileBrowserStore * model); + void (*unload) (PlumaFileBrowserStore * model, + const gchar * uri); +}; + +GType pluma_file_browser_store_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_store_register_type (GTypeModule * module); + +PlumaFileBrowserStore *pluma_file_browser_store_new (gchar const *root); + +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root_and_virtual_root (PlumaFileBrowserStore * model, + gchar const *root, + gchar const *virtual_root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_root (PlumaFileBrowserStore * model, + gchar const *root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_from_string (PlumaFileBrowserStore * model, + gchar const *root); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_up (PlumaFileBrowserStore * model); +PlumaFileBrowserStoreResult +pluma_file_browser_store_set_virtual_root_top (PlumaFileBrowserStore * model); + +gboolean +pluma_file_browser_store_get_iter_virtual_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +gboolean pluma_file_browser_store_get_iter_root (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +gchar * pluma_file_browser_store_get_root (PlumaFileBrowserStore * model); +gchar * pluma_file_browser_store_get_virtual_root (PlumaFileBrowserStore * model); + +gboolean pluma_file_browser_store_iter_equal (PlumaFileBrowserStore * model, + GtkTreeIter * iter1, + GtkTreeIter * iter2); + +void pluma_file_browser_store_set_value (PlumaFileBrowserStore * tree_model, + GtkTreeIter * iter, + gint column, + GValue * value); + +void _pluma_file_browser_store_iter_expanded (PlumaFileBrowserStore * model, + GtkTreeIter * iter); +void _pluma_file_browser_store_iter_collapsed (PlumaFileBrowserStore * model, + GtkTreeIter * iter); + +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_get_filter_mode (PlumaFileBrowserStore * model); +void pluma_file_browser_store_set_filter_mode (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterMode mode); +void pluma_file_browser_store_set_filter_func (PlumaFileBrowserStore * model, + PlumaFileBrowserStoreFilterFunc func, + gpointer user_data); +void pluma_file_browser_store_refilter (PlumaFileBrowserStore * model); +PlumaFileBrowserStoreFilterMode +pluma_file_browser_store_filter_mode_get_default (void); + +void pluma_file_browser_store_refresh (PlumaFileBrowserStore * model); +gboolean pluma_file_browser_store_rename (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + gchar const *new_name, + GError ** error); +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete (PlumaFileBrowserStore * model, + GtkTreeIter * iter, + gboolean trash); +PlumaFileBrowserStoreResult +pluma_file_browser_store_delete_all (PlumaFileBrowserStore * model, + GList *rows, + gboolean trash); + +gboolean pluma_file_browser_store_new_file (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter); +gboolean pluma_file_browser_store_new_directory (PlumaFileBrowserStore * model, + GtkTreeIter * parent, + GtkTreeIter * iter); + +void pluma_file_browser_store_cancel_mount_operation (PlumaFileBrowserStore *store); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_STORE_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-utils.c b/plugins/filebrowser/pluma-file-browser-utils.c new file mode 100755 index 00000000..6949486d --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-utils.c @@ -0,0 +1,198 @@ +/* + * pluma-file-bookmarks-store.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "pluma-file-browser-utils.h" +#include + +static GdkPixbuf * +process_icon_pixbuf (GdkPixbuf * pixbuf, + gchar const * name, + gint size, + GError * error) +{ + GdkPixbuf * scale; + + if (error != NULL) { + g_warning ("Could not load theme icon %s: %s", + name, + error->message); + g_error_free (error); + } + + if (pixbuf && gdk_pixbuf_get_width (pixbuf) > size) { + scale = gdk_pixbuf_scale_simple (pixbuf, + size, + size, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + pixbuf = scale; + } + + return pixbuf; +} + +GdkPixbuf * +pluma_file_browser_utils_pixbuf_from_theme (gchar const * name, + GtkIconSize size) +{ + gint width; + GError *error = NULL; + GdkPixbuf *pixbuf; + + gtk_icon_size_lookup (size, &width, NULL); + + pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + name, + width, + 0, + &error); + + pixbuf = process_icon_pixbuf (pixbuf, name, width, error); + + return pixbuf; +} + +GdkPixbuf * +pluma_file_browser_utils_pixbuf_from_icon (GIcon * icon, + GtkIconSize size) +{ + GdkPixbuf * ret = NULL; + GtkIconTheme *theme; + GtkIconInfo *info; + gint width; + + if (!icon) + return NULL; + + theme = gtk_icon_theme_get_default (); + gtk_icon_size_lookup (size, &width, NULL); + + info = gtk_icon_theme_lookup_by_gicon (theme, + icon, + width, + GTK_ICON_LOOKUP_USE_BUILTIN); + + if (!info) + return NULL; + + ret = gtk_icon_info_load_icon (info, NULL); + gtk_icon_info_free (info); + + return ret; +} + +GdkPixbuf * +pluma_file_browser_utils_pixbuf_from_file (GFile * file, + GtkIconSize size) +{ + GIcon * icon; + GFileInfo * info; + GdkPixbuf * ret = NULL; + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_ICON, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (!info) + return NULL; + + icon = g_file_info_get_icon (info); + if (icon != NULL) + ret = pluma_file_browser_utils_pixbuf_from_icon (icon, size); + + g_object_unref (info); + + return ret; +} + +gchar * +pluma_file_browser_utils_file_basename (GFile * file) +{ + gchar *uri; + gchar *ret; + + uri = g_file_get_uri (file); + ret = pluma_file_browser_utils_uri_basename (uri); + g_free (uri); + + return ret; +} + +gchar * +pluma_file_browser_utils_uri_basename (gchar const * uri) +{ + return pluma_utils_basename_for_display (uri); +} + +gboolean +pluma_file_browser_utils_confirmation_dialog (PlumaWindow * window, + GtkMessageType type, + gchar const *message, + gchar const *secondary, + gchar const * button_stock, + gchar const * button_label) +{ + GtkWidget *dlg; + gint ret; + GtkWidget *button; + + dlg = gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT, + type, + GTK_BUTTONS_NONE, "%s", message); + + if (secondary) + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dlg), "%s", secondary); + + /* Add a cancel button */ + button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_widget_show (button); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_dialog_add_action_widget (GTK_DIALOG (dlg), + button, + GTK_RESPONSE_CANCEL); + + /* Add custom button */ + button = gtk_button_new_from_stock (button_stock); + + if (button_label) { + gtk_button_set_use_stock (GTK_BUTTON (button), FALSE); + gtk_button_set_label (GTK_BUTTON (button), button_label); + } + + gtk_widget_show (button); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_dialog_add_action_widget (GTK_DIALOG (dlg), + button, + GTK_RESPONSE_OK); + + ret = gtk_dialog_run (GTK_DIALOG (dlg)); + gtk_widget_destroy (dlg); + + return (ret == GTK_RESPONSE_OK); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-utils.h b/plugins/filebrowser/pluma-file-browser-utils.h new file mode 100755 index 00000000..0ac4296a --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-utils.h @@ -0,0 +1,27 @@ +#ifndef __PLUMA_FILE_BROWSER_UTILS_H__ +#define __PLUMA_FILE_BROWSER_UTILS_H__ + +#include +#include + +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_theme (gchar const *name, + GtkIconSize size); + +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_icon (GIcon * icon, + GtkIconSize size); +GdkPixbuf *pluma_file_browser_utils_pixbuf_from_file (GFile * file, + GtkIconSize size); + +gchar * pluma_file_browser_utils_file_basename (GFile * file); +gchar * pluma_file_browser_utils_uri_basename (gchar const * uri); + +gboolean pluma_file_browser_utils_confirmation_dialog (PlumaWindow * window, + GtkMessageType type, + gchar const *message, + gchar const *secondary, + gchar const * button_stock, + gchar const * button_label); + +#endif /* __PLUMA_FILE_BROWSER_UTILS_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-view.c b/plugins/filebrowser/pluma-file-browser-view.c new file mode 100755 index 00000000..64e90c28 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-view.c @@ -0,0 +1,1256 @@ +/* + * pluma-file-browser-view.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-view.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" + +#define PLUMA_FILE_BROWSER_VIEW_GET_PRIVATE(object)( \ + G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewPrivate)) + +struct _PlumaFileBrowserViewPrivate +{ + GtkTreeViewColumn *column; + GtkCellRenderer *pixbuf_renderer; + GtkCellRenderer *text_renderer; + + GtkTreeModel *model; + GtkTreeRowReference *editable; + + GdkCursor *busy_cursor; + + /* CLick policy */ + PlumaFileBrowserViewClickPolicy click_policy; + GtkTreePath *double_click_path[2]; /* Both clicks in a double click need to be on the same row */ + GtkTreePath *hover_path; + GdkCursor *hand_cursor; + gboolean ignore_release; + gboolean selected_on_button_down; + gint drag_button; + gboolean drag_started; + + gboolean restore_expand_state; + gboolean is_refresh; + GHashTable * expand_state; +}; + +/* Properties */ +enum +{ + PROP_0, + + PROP_CLICK_POLICY, + PROP_RESTORE_EXPAND_STATE +}; + +/* Signals */ +enum +{ + ERROR, + FILE_ACTIVATED, + DIRECTORY_ACTIVATED, + BOOKMARK_ACTIVATED, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0 }; + +static const GtkTargetEntry drag_source_targets[] = { + { "text/uri-list", 0, 0 } +}; + +PLUMA_PLUGIN_DEFINE_TYPE (PlumaFileBrowserView, pluma_file_browser_view, + GTK_TYPE_TREE_VIEW) + +static void on_cell_edited (GtkCellRendererText * cell, + gchar * path, + gchar * new_text, + PlumaFileBrowserView * tree_view); + +static void on_begin_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view); +static void on_end_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view); + +static void on_unload (PlumaFileBrowserStore * model, + gchar const * uri, + PlumaFileBrowserView * view); + +static void on_row_inserted (PlumaFileBrowserStore * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserView * view); + +static void +pluma_file_browser_view_finalize (GObject * object) +{ + PlumaFileBrowserView *obj = PLUMA_FILE_BROWSER_VIEW(object); + + if (obj->priv->hand_cursor) + gdk_cursor_unref(obj->priv->hand_cursor); + + if (obj->priv->hover_path) + gtk_tree_path_free (obj->priv->hover_path); + + if (obj->priv->expand_state) + { + g_hash_table_destroy (obj->priv->expand_state); + obj->priv->expand_state = NULL; + } + + gdk_cursor_unref (obj->priv->busy_cursor); + + G_OBJECT_CLASS (pluma_file_browser_view_parent_class)-> + finalize (object); +} + +static void +add_expand_state (PlumaFileBrowserView * view, + gchar const * uri) +{ + GFile * file; + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + + if (view->priv->expand_state) + g_hash_table_insert (view->priv->expand_state, file, file); + else + g_object_unref (file); +} + +static void +remove_expand_state (PlumaFileBrowserView * view, + gchar const * uri) +{ + GFile * file; + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + + if (view->priv->expand_state) + g_hash_table_remove (view->priv->expand_state, file); + + g_object_unref (file); +} + +static void +row_expanded (GtkTreeView * tree_view, + GtkTreeIter * iter, + GtkTreePath * path) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (tree_view); + gchar * uri; + + if (GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_expanded) + GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_expanded (tree_view, iter, path); + + if (!PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + return; + + if (view->priv->restore_expand_state) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + add_expand_state (view, uri); + g_free (uri); + } + + _pluma_file_browser_store_iter_expanded (PLUMA_FILE_BROWSER_STORE (view->priv->model), + iter); +} + +static void +row_collapsed (GtkTreeView * tree_view, + GtkTreeIter * iter, + GtkTreePath * path) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (tree_view); + gchar * uri; + + if (GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_collapsed) + GTK_TREE_VIEW_CLASS (pluma_file_browser_view_parent_class)->row_collapsed (tree_view, iter, path); + + if (!PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + return; + + if (view->priv->restore_expand_state) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + remove_expand_state (view, uri); + g_free (uri); + } + + _pluma_file_browser_store_iter_collapsed (PLUMA_FILE_BROWSER_STORE (view->priv->model), + iter); +} + +static gboolean +leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE && + view->priv->hover_path != NULL) { + gtk_tree_path_free (view->priv->hover_path); + view->priv->hover_path = NULL; + } + + // Chainup + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->leave_notify_event (widget, event); +} + +static gboolean +enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + if (view->priv->hover_path != NULL) + gtk_tree_path_free (view->priv->hover_path); + + gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), + event->x, event->y, + &view->priv->hover_path, + NULL, NULL, NULL); + + if (view->priv->hover_path != NULL) + gdk_window_set_cursor (gtk_widget_get_window (widget), + view->priv->hand_cursor); + } + + // Chainup + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->enter_notify_event (widget, event); +} + +static gboolean +motion_notify_event (GtkWidget * widget, + GdkEventMotion * event) +{ + GtkTreePath *old_hover_path; + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (view->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + old_hover_path = view->priv->hover_path; + gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), + event->x, event->y, + &view->priv->hover_path, + NULL, NULL, NULL); + + if ((old_hover_path != NULL) != (view->priv->hover_path != NULL)) { + if (view->priv->hover_path != NULL) + gdk_window_set_cursor (gtk_widget_get_window (widget), + view->priv->hand_cursor); + else + gdk_window_set_cursor (gtk_widget_get_window (widget), + NULL); + } + + if (old_hover_path != NULL) + gtk_tree_path_free (old_hover_path); + } + + // Chainup + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->motion_notify_event (widget, event); +} + +static void +set_click_policy_property (PlumaFileBrowserView *obj, + PlumaFileBrowserViewClickPolicy click_policy) +{ + GtkTreeIter iter; + GdkDisplay *display; + GdkWindow *win; + + obj->priv->click_policy = click_policy; + + if (click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + if (obj->priv->hand_cursor == NULL) + obj->priv->hand_cursor = gdk_cursor_new(GDK_HAND2); + } else if (click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE) { + if (obj->priv->hover_path != NULL) { + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (obj->priv->model), + &iter, obj->priv->hover_path)) + gtk_tree_model_row_changed (GTK_TREE_MODEL (obj->priv->model), + obj->priv->hover_path, &iter); + + gtk_tree_path_free (obj->priv->hover_path); + obj->priv->hover_path = NULL; + } + + if (GTK_WIDGET_REALIZED (GTK_WIDGET (obj))) { + win = gtk_widget_get_window (GTK_WIDGET (obj)); + gdk_window_set_cursor (win, NULL); + + display = gtk_widget_get_display (GTK_WIDGET (obj)); + + if (display != NULL) + gdk_display_flush (display); + } + + if (obj->priv->hand_cursor) { + gdk_cursor_unref (obj->priv->hand_cursor); + obj->priv->hand_cursor = NULL; + } + } +} + +static void +directory_activated (PlumaFileBrowserView *view, + GtkTreeIter *iter) +{ + pluma_file_browser_store_set_virtual_root (PLUMA_FILE_BROWSER_STORE (view->priv->model), iter); +} + +static void +activate_selected_files (PlumaFileBrowserView *view) { + GtkTreeView *tree_view = GTK_TREE_VIEW (view); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); + GList *rows, *row; + GtkTreePath *directory = NULL; + GtkTreePath *path; + GtkTreeIter iter; + PlumaFileBrowserStoreFlag flags; + + rows = gtk_tree_selection_get_selected_rows (selection, &view->priv->model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + /* Get iter from path */ + if (!gtk_tree_model_get_iter (view->priv->model, &iter, path)) + continue; + + gtk_tree_model_get (view->priv->model, &iter, PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, -1); + + if (FILE_IS_DIR (flags)) { + if (directory == NULL) + directory = path; + + } else if (!FILE_IS_DUMMY (flags)) { + g_signal_emit (view, signals[FILE_ACTIVATED], 0, &iter); + } + } + + if (directory != NULL) { + if (gtk_tree_model_get_iter (view->priv->model, &iter, directory)) + g_signal_emit (view, signals[DIRECTORY_ACTIVATED], 0, &iter); + } + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); +} + +static void +activate_selected_bookmark (PlumaFileBrowserView *view) { + GtkTreeView *tree_view = GTK_TREE_VIEW (view); + GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected (selection, &view->priv->model, &iter)) + g_signal_emit (view, signals[BOOKMARK_ACTIVATED], 0, &iter); +} + +static void +activate_selected_items (PlumaFileBrowserView *view) +{ + if (PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + activate_selected_files (view); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (view->priv->model)) + activate_selected_bookmark (view); +} + +static void +toggle_hidden_filter (PlumaFileBrowserView *view) +{ + PlumaFileBrowserStoreFilterMode mode; + + if (PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + { + mode = pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (view->priv->model)); + mode ^= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN; + pluma_file_browser_store_set_filter_mode + (PLUMA_FILE_BROWSER_STORE (view->priv->model), mode); + } +} + +static gboolean +button_event_modifies_selection (GdkEventButton *event) +{ + return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0; +} + +static void +drag_begin (GtkWidget *widget, + GdkDragContext *context) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + view->priv->drag_button = 0; + view->priv->drag_started = TRUE; + + /* Chain up */ + GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->drag_begin (widget, context); +} + +static void +did_not_drag (PlumaFileBrowserView *view, + GdkEventButton *event) +{ + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreePath *path; + + tree_view = GTK_TREE_VIEW (view); + selection = gtk_tree_view_get_selection (tree_view); + + if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, + &path, NULL, NULL, NULL)) { + if ((view->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) + && !button_event_modifies_selection(event) + && (event->button == 1 || event->button == 2)) { + /* Activate all selected items, and leave them selected */ + activate_selected_items (view); + } else if ((event->button == 1 || event->button == 2) + && ((event->state & GDK_CONTROL_MASK) != 0 || + (event->state & GDK_SHIFT_MASK) == 0) + && view->priv->selected_on_button_down) { + if (!button_event_modifies_selection (event)) { + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, path); + } else { + gtk_tree_selection_unselect_path (selection, path); + } + } + + gtk_tree_path_free (path); + } +} + +static gboolean +button_release_event (GtkWidget *widget, + GdkEventButton *event) +{ + PlumaFileBrowserView *view = PLUMA_FILE_BROWSER_VIEW (widget); + + if (event->button == view->priv->drag_button) { + view->priv->drag_button = 0; + + if (!view->priv->drag_started && + !view->priv->ignore_release) + did_not_drag (view, event); + } + + /* Chain up */ + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->button_release_event (widget, event); +} + +static gboolean +button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + int double_click_time; + static int click_count = 0; + static guint32 last_click_time = 0; + PlumaFileBrowserView *view; + GtkTreeView *tree_view; + GtkTreeSelection *selection; + GtkTreePath *path; + int expander_size; + int horizontal_separator; + gboolean on_expander; + gboolean call_parent; + gboolean selected; + GtkWidgetClass *widget_parent = GTK_WIDGET_CLASS(pluma_file_browser_view_parent_class); + + tree_view = GTK_TREE_VIEW (widget); + view = PLUMA_FILE_BROWSER_VIEW (widget); + selection = gtk_tree_view_get_selection (tree_view); + + /* Get double click time */ + g_object_get (G_OBJECT (gtk_widget_get_settings (widget)), + "gtk-double-click-time", &double_click_time, + NULL); + + /* Determine click count */ + if (event->time - last_click_time < double_click_time) + click_count++; + else + click_count = 0; + + last_click_time = event->time; + + /* Ignore double click if we are in single click mode */ + if (view->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE && + click_count >= 2) { + return TRUE; + } + + view->priv->ignore_release = FALSE; + call_parent = TRUE; + + if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, + &path, NULL, NULL, NULL)) { + /* Keep track of path of last click so double clicks only happen + * on the same item */ + if ((event->button == 1 || event->button == 2) && + event->type == GDK_BUTTON_PRESS) { + if (view->priv->double_click_path[1]) + gtk_tree_path_free (view->priv->double_click_path[1]); + + view->priv->double_click_path[1] = view->priv->double_click_path[0]; + view->priv->double_click_path[0] = gtk_tree_path_copy (path); + } + + if (event->type == GDK_2BUTTON_PRESS) { + if (view->priv->double_click_path[1] && + gtk_tree_path_compare (view->priv->double_click_path[0], view->priv->double_click_path[1]) == 0) + activate_selected_items (view); + + /* Chain up */ + widget_parent->button_press_event (widget, event); + } else { + /* We're going to filter out some situations where + * we can't let the default code run because all + * but one row would be would be deselected. We don't + * want that; we want the right click menu or single + * click to apply to everything that's currently selected. */ + selected = gtk_tree_selection_path_is_selected (selection, path); + + if (event->button == 3 && selected) + call_parent = FALSE; + + if ((event->button == 1 || event->button == 2) && + ((event->state & GDK_CONTROL_MASK) != 0 || + (event->state & GDK_SHIFT_MASK) == 0)) { + gtk_widget_style_get (widget, + "expander-size", &expander_size, + "horizontal-separator", &horizontal_separator, + NULL); + on_expander = (event->x <= horizontal_separator / 2 + + gtk_tree_path_get_depth (path) * expander_size); + + view->priv->selected_on_button_down = selected; + + if (selected) { + call_parent = on_expander || gtk_tree_selection_count_selected_rows (selection) == 1; + view->priv->ignore_release = call_parent && view->priv->click_policy != PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE; + } else if ((event->state & GDK_CONTROL_MASK) != 0) { + call_parent = FALSE; + gtk_tree_selection_select_path (selection, path); + } else { + view->priv->ignore_release = on_expander; + } + } + + if (call_parent) { + /* Chain up */ + widget_parent->button_press_event (widget, event); + } else if (selected) { + gtk_widget_grab_focus (widget); + } + + if ((event->button == 1 || event->button == 2) && + event->type == GDK_BUTTON_PRESS) { + view->priv->drag_started = FALSE; + view->priv->drag_button = event->button; + } + } + + gtk_tree_path_free (path); + } else { + if ((event->button == 1 || event->button == 2) && + event->type == GDK_BUTTON_PRESS) { + if (view->priv->double_click_path[1]) + gtk_tree_path_free (view->priv->double_click_path[1]); + + view->priv->double_click_path[1] = view->priv->double_click_path[0]; + view->priv->double_click_path[0] = NULL; + } + + gtk_tree_selection_unselect_all (selection); + /* Chain up */ + widget_parent->button_press_event (widget, event); + } + + /* We already chained up if nescessary, so just return TRUE */ + return TRUE; +} + +static gboolean +key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + PlumaFileBrowserView *view; + guint modifiers; + gboolean handled; + + view = PLUMA_FILE_BROWSER_VIEW (widget); + handled = FALSE; + + modifiers = gtk_accelerator_get_default_mod_mask (); + + switch (event->keyval) { + case GDK_space: + if (event->state & GDK_CONTROL_MASK) { + handled = FALSE; + break; + } + if (!GTK_WIDGET_HAS_FOCUS (widget)) { + handled = FALSE; + break; + } + + activate_selected_items (view); + handled = TRUE; + break; + + case GDK_Return: + case GDK_KP_Enter: + activate_selected_items (view); + handled = TRUE; + break; + + case GDK_h: + if ((event->state & modifiers) == GDK_CONTROL_MASK) { + toggle_hidden_filter (view); + handled = TRUE; + break; + } + + default: + handled = FALSE; + } + + /* Chain up */ + if (!handled) + return GTK_WIDGET_CLASS (pluma_file_browser_view_parent_class)->key_press_event (widget, event); + + return TRUE; +} + +static void +fill_expand_state (PlumaFileBrowserView * view, GtkTreeIter * iter) +{ + GtkTreePath * path; + GtkTreeIter child; + gchar * uri; + + if (!gtk_tree_model_iter_has_child (view->priv->model, iter)) + return; + + path = gtk_tree_model_get_path (view->priv->model, iter); + + if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), path)) + { + gtk_tree_model_get (view->priv->model, + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + add_expand_state (view, uri); + g_free (uri); + } + + if (gtk_tree_model_iter_children (view->priv->model, &child, iter)) + { + do { + fill_expand_state (view, &child); + } while (gtk_tree_model_iter_next (view->priv->model, &child)); + } + + gtk_tree_path_free (path); +} + +static void +uninstall_restore_signals (PlumaFileBrowserView * tree_view, + GtkTreeModel * model) +{ + g_signal_handlers_disconnect_by_func (model, + on_begin_refresh, + tree_view); + + g_signal_handlers_disconnect_by_func (model, + on_end_refresh, + tree_view); + + g_signal_handlers_disconnect_by_func (model, + on_unload, + tree_view); + + g_signal_handlers_disconnect_by_func (model, + on_row_inserted, + tree_view); +} + +static void +install_restore_signals (PlumaFileBrowserView * tree_view, + GtkTreeModel * model) +{ + g_signal_connect (model, + "begin-refresh", + G_CALLBACK (on_begin_refresh), + tree_view); + + g_signal_connect (model, + "end-refresh", + G_CALLBACK (on_end_refresh), + tree_view); + + g_signal_connect (model, + "unload", + G_CALLBACK (on_unload), + tree_view); + + g_signal_connect_after (model, + "row-inserted", + G_CALLBACK (on_row_inserted), + tree_view); +} + +static void +set_restore_expand_state (PlumaFileBrowserView * view, + gboolean state) +{ + if (state == view->priv->restore_expand_state) + return; + + if (view->priv->expand_state) + { + g_hash_table_destroy (view->priv->expand_state); + view->priv->expand_state = NULL; + } + + if (state) + { + view->priv->expand_state = g_hash_table_new_full (g_file_hash, + (GEqualFunc)g_file_equal, + g_object_unref, + NULL); + + if (view->priv->model && PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + { + fill_expand_state (view, NULL); + + install_restore_signals (view, view->priv->model); + } + } + else if (view->priv->model && PLUMA_IS_FILE_BROWSER_STORE (view->priv->model)) + { + uninstall_restore_signals (view, view->priv->model); + } + + view->priv->restore_expand_state = state; +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserView *obj = PLUMA_FILE_BROWSER_VIEW (object); + + switch (prop_id) + { + case PROP_CLICK_POLICY: + g_value_set_enum (value, obj->priv->click_policy); + break; + case PROP_RESTORE_EXPAND_STATE: + g_value_set_boolean (value, obj->priv->restore_expand_state); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserView *obj = PLUMA_FILE_BROWSER_VIEW (object); + + switch (prop_id) + { + case PROP_CLICK_POLICY: + set_click_policy_property (obj, g_value_get_enum (value)); + break; + case PROP_RESTORE_EXPAND_STATE: + set_restore_expand_state (obj, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_view_class_init (PlumaFileBrowserViewClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkTreeViewClass *tree_view_class = GTK_TREE_VIEW_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = pluma_file_browser_view_finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; + + /* Event handlers */ + widget_class->motion_notify_event = motion_notify_event; + widget_class->enter_notify_event = enter_notify_event; + widget_class->leave_notify_event = leave_notify_event; + widget_class->button_press_event = button_press_event; + widget_class->button_release_event = button_release_event; + widget_class->drag_begin = drag_begin; + widget_class->key_press_event = key_press_event; + + /* Tree view handlers */ + tree_view_class->row_expanded = row_expanded; + tree_view_class->row_collapsed = row_collapsed; + + /* Default handlers */ + klass->directory_activated = directory_activated; + + g_object_class_install_property (object_class, PROP_CLICK_POLICY, + g_param_spec_enum ("click-policy", + "Click Policy", + "The click policy", + PLUMA_TYPE_FILE_BROWSER_VIEW_CLICK_POLICY, + PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_RESTORE_EXPAND_STATE, + g_param_spec_boolean ("restore-expand-state", + "Restore Expand State", + "Restore expanded state of loaded directories", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + signals[ERROR] = + g_signal_new ("error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserViewClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); + signals[FILE_ACTIVATED] = + g_signal_new ("file-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserViewClass, + file_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); + signals[DIRECTORY_ACTIVATED] = + g_signal_new ("directory-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserViewClass, + directory_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); + signals[BOOKMARK_ACTIVATED] = + g_signal_new ("bookmark-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserViewClass, + bookmark_activated), NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, GTK_TYPE_TREE_ITER); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserViewPrivate)); +} + +static void +cell_data_cb (GtkTreeViewColumn * tree_column, GtkCellRenderer * cell, + GtkTreeModel * tree_model, GtkTreeIter * iter, + PlumaFileBrowserView * obj) +{ + GtkTreePath *path; + PangoUnderline underline = PANGO_UNDERLINE_NONE; + gboolean editable = FALSE; + + path = gtk_tree_model_get_path (tree_model, iter); + + if (obj->priv->click_policy == PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE) { + if (obj->priv->hover_path != NULL && + gtk_tree_path_compare (path, obj->priv->hover_path) == 0) + underline = PANGO_UNDERLINE_SINGLE; + } + + if (PLUMA_IS_FILE_BROWSER_STORE (tree_model)) + { + if (obj->priv->editable != NULL && + gtk_tree_row_reference_valid (obj->priv->editable)) + { + GtkTreePath *edpath = gtk_tree_row_reference_get_path (obj->priv->editable); + + editable = edpath && gtk_tree_path_compare (path, edpath) == 0; + } + } + + gtk_tree_path_free (path); + g_object_set (cell, "editable", editable, "underline", underline, NULL); +} + +static void +pluma_file_browser_view_init (PlumaFileBrowserView * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_VIEW_GET_PRIVATE (obj); + + obj->priv->column = gtk_tree_view_column_new (); + + obj->priv->pixbuf_renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (obj->priv->column, + obj->priv->pixbuf_renderer, + FALSE); + gtk_tree_view_column_add_attribute (obj->priv->column, + obj->priv->pixbuf_renderer, + "pixbuf", + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON); + + obj->priv->text_renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (obj->priv->column, + obj->priv->text_renderer, TRUE); + gtk_tree_view_column_add_attribute (obj->priv->column, + obj->priv->text_renderer, + "text", + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME); + + g_signal_connect (obj->priv->text_renderer, "edited", + G_CALLBACK (on_cell_edited), obj); + + gtk_tree_view_append_column (GTK_TREE_VIEW (obj), + obj->priv->column); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (obj), FALSE); + + gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (obj), + GDK_BUTTON1_MASK, + drag_source_targets, + G_N_ELEMENTS (drag_source_targets), + GDK_ACTION_COPY); + + obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); +} + +static gboolean +bookmarks_separator_func (GtkTreeModel * model, GtkTreeIter * iter, + gpointer user_data) +{ + guint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, -1); + + return (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_SEPARATOR); +} + +/* Public */ +GtkWidget * +pluma_file_browser_view_new (void) +{ + PlumaFileBrowserView *obj = + PLUMA_FILE_BROWSER_VIEW (g_object_new + (PLUMA_TYPE_FILE_BROWSER_VIEW, NULL)); + + return GTK_WIDGET (obj); +} + +void +pluma_file_browser_view_set_model (PlumaFileBrowserView * tree_view, + GtkTreeModel * model) +{ + GtkTreeSelection *selection; + + if (tree_view->priv->model == model) + return; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW + (tree_view), + bookmarks_separator_func, + NULL, NULL); + gtk_tree_view_column_set_cell_data_func (tree_view->priv-> + column, + tree_view->priv-> + text_renderer, + (GtkTreeCellDataFunc) + cell_data_cb, + tree_view, NULL); + } else { + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW + (tree_view), NULL, + NULL, NULL); + gtk_tree_view_column_set_cell_data_func (tree_view->priv-> + column, + tree_view->priv-> + text_renderer, + (GtkTreeCellDataFunc) + cell_data_cb, + tree_view, NULL); + + if (tree_view->priv->restore_expand_state) + install_restore_signals (tree_view, model); + + } + + if (tree_view->priv->hover_path != NULL) { + gtk_tree_path_free (tree_view->priv->hover_path); + tree_view->priv->hover_path = NULL; + } + + if (PLUMA_IS_FILE_BROWSER_STORE (tree_view->priv->model)) { + if (tree_view->priv->restore_expand_state) + uninstall_restore_signals (tree_view, + tree_view->priv->model); + } + + tree_view->priv->model = model; + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); +} + +void +pluma_file_browser_view_start_rename (PlumaFileBrowserView * tree_view, + GtkTreeIter * iter) +{ + guint flags; + GtkTreeRowReference *rowref; + GtkTreePath *path; + + g_return_if_fail (PLUMA_IS_FILE_BROWSER_VIEW (tree_view)); + g_return_if_fail (PLUMA_IS_FILE_BROWSER_STORE + (tree_view->priv->model)); + g_return_if_fail (iter != NULL); + + gtk_tree_model_get (tree_view->priv->model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!(FILE_IS_DIR (flags) || !FILE_IS_DUMMY (flags))) + return; + + path = gtk_tree_model_get_path (tree_view->priv->model, iter); + rowref = gtk_tree_row_reference_new (tree_view->priv->model, path); + + /* Start editing */ + gtk_widget_grab_focus (GTK_WIDGET (tree_view)); + + if (gtk_tree_path_up (path)) + gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree_view), + path); + + gtk_tree_path_free (path); + tree_view->priv->editable = rowref; + + gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree_view), + gtk_tree_row_reference_get_path (tree_view->priv->editable), + tree_view->priv->column, TRUE); + + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), + gtk_tree_row_reference_get_path (tree_view->priv->editable), + tree_view->priv->column, + FALSE, 0.0, 0.0); +} + +void +pluma_file_browser_view_set_click_policy (PlumaFileBrowserView *tree_view, + PlumaFileBrowserViewClickPolicy policy) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_VIEW (tree_view)); + + set_click_policy_property (tree_view, policy); + + g_object_notify (G_OBJECT (tree_view), "click-policy"); +} + +void +pluma_file_browser_view_set_restore_expand_state (PlumaFileBrowserView * tree_view, + gboolean restore_expand_state) +{ + g_return_if_fail (PLUMA_IS_FILE_BROWSER_VIEW (tree_view)); + + set_restore_expand_state (tree_view, restore_expand_state); + g_object_notify (G_OBJECT (tree_view), "restore-expand-state"); +} + +/* Signal handlers */ +static void +on_cell_edited (GtkCellRendererText * cell, gchar * path, gchar * new_text, + PlumaFileBrowserView * tree_view) +{ + GtkTreePath * treepath; + GtkTreeIter iter; + gboolean ret; + GError * error = NULL; + + gtk_tree_row_reference_free (tree_view->priv->editable); + tree_view->priv->editable = NULL; + + if (new_text == NULL || *new_text == '\0') + return; + + treepath = gtk_tree_path_new_from_string (path); + ret = gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model), &iter, treepath); + gtk_tree_path_free (treepath); + + if (ret) { + if (pluma_file_browser_store_rename (PLUMA_FILE_BROWSER_STORE (tree_view->priv->model), + &iter, new_text, &error)) { + treepath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_view->priv->model), &iter); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), + treepath, NULL, + FALSE, 0.0, 0.0); + gtk_tree_path_free (treepath); + } + else { + if (error) { + g_signal_emit (tree_view, signals[ERROR], 0, + error->code, error->message); + g_error_free (error); + } + } + } +} + +static void +on_begin_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view) +{ + /* Store the refresh state, so we can handle unloading of nodes while + refreshing properly */ + view->priv->is_refresh = TRUE; +} + +static void +on_end_refresh (PlumaFileBrowserStore * model, + PlumaFileBrowserView * view) +{ + /* Store the refresh state, so we can handle unloading of nodes while + refreshing properly */ + view->priv->is_refresh = FALSE; +} + +static void +on_unload (PlumaFileBrowserStore * model, + gchar const * uri, + PlumaFileBrowserView * view) +{ + /* Don't remove the expand state if we are refreshing */ + if (!view->priv->restore_expand_state || view->priv->is_refresh) + return; + + remove_expand_state (view, uri); +} + +static void +restore_expand_state (PlumaFileBrowserView * view, + PlumaFileBrowserStore * model, + GtkTreeIter * iter) +{ + gchar * uri; + GFile * file; + GtkTreePath * path; + + gtk_tree_model_get (GTK_TREE_MODEL (model), + iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, + -1); + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter); + + if (g_hash_table_lookup (view->priv->expand_state, file)) + { + gtk_tree_view_expand_row (GTK_TREE_VIEW (view), + path, + FALSE); + } + + gtk_tree_path_free (path); + + g_object_unref (file); + g_free (uri); +} + +static void +on_row_inserted (PlumaFileBrowserStore * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserView * view) +{ + GtkTreeIter parent; + GtkTreePath * copy; + + if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (model), iter)) + restore_expand_state (view, model, iter); + + copy = gtk_tree_path_copy (path); + + if (gtk_tree_path_up (copy) && + (gtk_tree_path_get_depth (copy) != 0) && + gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &parent, copy)) + { + restore_expand_state (view, model, &parent); + } + + gtk_tree_path_free (copy); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-view.h b/plugins/filebrowser/pluma-file-browser-view.h new file mode 100755 index 00000000..04e64953 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-view.h @@ -0,0 +1,84 @@ +/* + * pluma-file-browser-view.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_VIEW_H__ +#define __PLUMA_FILE_BROWSER_VIEW_H__ + +#include + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_VIEW (pluma_file_browser_view_get_type ()) +#define PLUMA_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserView)) +#define PLUMA_FILE_BROWSER_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserView const)) +#define PLUMA_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewClass)) +#define PLUMA_IS_FILE_BROWSER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW)) +#define PLUMA_IS_FILE_BROWSER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_VIEW)) +#define PLUMA_FILE_BROWSER_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_VIEW, PlumaFileBrowserViewClass)) + +typedef struct _PlumaFileBrowserView PlumaFileBrowserView; +typedef struct _PlumaFileBrowserViewClass PlumaFileBrowserViewClass; +typedef struct _PlumaFileBrowserViewPrivate PlumaFileBrowserViewPrivate; + +typedef enum { + PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_DOUBLE, + PLUMA_FILE_BROWSER_VIEW_CLICK_POLICY_SINGLE +} PlumaFileBrowserViewClickPolicy; + +struct _PlumaFileBrowserView +{ + GtkTreeView parent; + + PlumaFileBrowserViewPrivate *priv; +}; + +struct _PlumaFileBrowserViewClass +{ + GtkTreeViewClass parent_class; + + /* Signals */ + void (*error) (PlumaFileBrowserView * filetree, + guint code, + gchar const *message); + void (*file_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); + void (*directory_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); + void (*bookmark_activated) (PlumaFileBrowserView * filetree, + GtkTreeIter *iter); +}; + +GType pluma_file_browser_view_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_view_register_type (GTypeModule * module); + +GtkWidget *pluma_file_browser_view_new (void); +void pluma_file_browser_view_set_model (PlumaFileBrowserView * tree_view, + GtkTreeModel * model); +void pluma_file_browser_view_start_rename (PlumaFileBrowserView * tree_view, + GtkTreeIter * iter); +void pluma_file_browser_view_set_click_policy (PlumaFileBrowserView * tree_view, + PlumaFileBrowserViewClickPolicy policy); +void pluma_file_browser_view_set_restore_expand_state (PlumaFileBrowserView * tree_view, + gboolean restore_expand_state); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_VIEW_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-widget-ui.xml b/plugins/filebrowser/pluma-file-browser-widget-ui.xml new file mode 100755 index 00000000..472fd185 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget-ui.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/filebrowser/pluma-file-browser-widget.c b/plugins/filebrowser/pluma-file-browser-widget.c new file mode 100755 index 00000000..969c2ae4 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget.c @@ -0,0 +1,3143 @@ +/* + * pluma-file-browser-widget.c - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pluma-file-browser-utils.h" +#include "pluma-file-browser-error.h" +#include "pluma-file-browser-widget.h" +#include "pluma-file-browser-view.h" +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-marshal.h" +#include "pluma-file-browser-enum-types.h" + +#define PLUMA_FILE_BROWSER_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ + PLUMA_TYPE_FILE_BROWSER_WIDGET, \ + PlumaFileBrowserWidgetPrivate)) + +#define XML_UI_FILE "pluma-file-browser-widget-ui.xml" +#define LOCATION_DATA_KEY "pluma-file-browser-widget-location" + +enum +{ + BOOKMARKS_ID, + SEPARATOR_CUSTOM_ID, + SEPARATOR_ID, + PATH_ID, + NUM_DEFAULT_IDS +}; + +enum +{ + COLUMN_INDENT, + COLUMN_ICON, + COLUMN_NAME, + COLUMN_FILE, + COLUMN_ID, + N_COLUMNS +}; + +/* Properties */ +enum +{ + PROP_0, + + PROP_FILTER_PATTERN, + PROP_ENABLE_DELETE +}; + +/* Signals */ +enum +{ + URI_ACTIVATED, + ERROR, + CONFIRM_DELETE, + CONFIRM_NO_TRASH, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS] = { 0 }; + +typedef struct _SignalNode +{ + GObject *object; + gulong id; +} SignalNode; + +typedef struct +{ + gulong id; + PlumaFileBrowserWidgetFilterFunc func; + gpointer user_data; + GDestroyNotify destroy_notify; +} FilterFunc; + +typedef struct +{ + GFile *root; + GFile *virtual_root; +} Location; + +typedef struct +{ + gchar *name; + GdkPixbuf *icon; +} NameIcon; + +struct _PlumaFileBrowserWidgetPrivate +{ + PlumaFileBrowserView *treeview; + PlumaFileBrowserStore *file_store; + PlumaFileBookmarksStore *bookmarks_store; + + GHashTable *bookmarks_hash; + + GtkWidget *combo; + GtkTreeStore *combo_model; + + GtkWidget *filter_expander; + GtkWidget *filter_entry; + + GtkUIManager *manager; + GtkActionGroup *action_group; + GtkActionGroup *action_group_selection; + GtkActionGroup *action_group_file_selection; + GtkActionGroup *action_group_single_selection; + GtkActionGroup *action_group_single_most_selection; + GtkActionGroup *action_group_sensitive; + GtkActionGroup *bookmark_action_group; + + GSList *signal_pool; + + GSList *filter_funcs; + gulong filter_id; + gulong glob_filter_id; + GPatternSpec *filter_pattern; + gchar *filter_pattern_str; + + GList *locations; + GList *current_location; + gboolean changing_location; + GtkWidget *location_previous_menu; + GtkWidget *location_next_menu; + GtkWidget *current_location_menu_item; + + gboolean enable_delete; + + GCancellable *cancellable; + + GdkCursor *busy_cursor; +}; + +static void set_enable_delete (PlumaFileBrowserWidget *obj, + gboolean enable); +static void on_model_set (GObject * gobject, + GParamSpec * arg1, + PlumaFileBrowserWidget * obj); +static void on_treeview_error (PlumaFileBrowserView * tree_view, + guint code, + gchar * message, + PlumaFileBrowserWidget * obj); +static void on_file_store_error (PlumaFileBrowserStore * store, + guint code, + gchar * message, + PlumaFileBrowserWidget * obj); +static gboolean on_file_store_no_trash (PlumaFileBrowserStore * store, + GList * files, + PlumaFileBrowserWidget * obj); +static void on_combo_changed (GtkComboBox * combo, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_popup_menu (PlumaFileBrowserView * treeview, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_button_press_event (PlumaFileBrowserView * treeview, + GdkEventButton * event, + PlumaFileBrowserWidget * obj); +static gboolean on_treeview_key_press_event (PlumaFileBrowserView * treeview, + GdkEventKey * event, + PlumaFileBrowserWidget * obj); +static void on_selection_changed (GtkTreeSelection * selection, + PlumaFileBrowserWidget * obj); + +static void on_virtual_root_changed (PlumaFileBrowserStore * model, + GParamSpec *param, + PlumaFileBrowserWidget * obj); + +static gboolean on_entry_filter_activate (PlumaFileBrowserWidget * obj); +static void on_location_jump_activate (GtkMenuItem * item, + PlumaFileBrowserWidget * obj); +static void on_bookmarks_row_changed (GtkTreeModel * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserWidget * obj); +static void on_bookmarks_row_deleted (GtkTreeModel * model, + GtkTreePath * path, + PlumaFileBrowserWidget * obj); +static void on_filter_mode_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj); +static void on_action_directory_previous (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_next (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_up (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_new (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_open (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_new (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_rename (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_delete (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_file_move_to_trash (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_refresh (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_directory_open (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_filter_hidden (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_filter_binary (GtkAction * action, + PlumaFileBrowserWidget * obj); +static void on_action_bookmark_open (GtkAction * action, + PlumaFileBrowserWidget * obj); + +PLUMA_PLUGIN_DEFINE_TYPE (PlumaFileBrowserWidget, pluma_file_browser_widget, + GTK_TYPE_VBOX) + +static void +free_name_icon (gpointer data) +{ + NameIcon * item; + + if (data == NULL) + return; + + item = (NameIcon *)(data); + + g_free (item->name); + + if (item->icon) + g_object_unref (item->icon); + + g_free (item); +} + +static FilterFunc * +filter_func_new (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + FilterFunc *result; + + result = g_new (FilterFunc, 1); + + result->id = ++obj->priv->filter_id; + result->func = func; + result->user_data = user_data; + result->destroy_notify = notify; + return result; +} + +static void +location_free (Location * loc) +{ + if (loc->root) + g_object_unref (loc->root); + + if (loc->virtual_root) + g_object_unref (loc->virtual_root); + + g_free (loc); +} + +static gboolean +combo_find_by_id (PlumaFileBrowserWidget * obj, guint id, + GtkTreeIter * iter) +{ + guint checkid; + GtkTreeModel *model = GTK_TREE_MODEL (obj->priv->combo_model); + + if (iter == NULL) + return FALSE; + + if (gtk_tree_model_get_iter_first (model, iter)) { + do { + gtk_tree_model_get (model, iter, COLUMN_ID, + &checkid, -1); + + if (checkid == id) + return TRUE; + } while (gtk_tree_model_iter_next (model, iter)); + } + + return FALSE; +} + +static void +remove_path_items (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + + while (combo_find_by_id (obj, PATH_ID, &iter)) + gtk_tree_store_remove (obj->priv->combo_model, &iter); +} + +static void +cancel_async_operation (PlumaFileBrowserWidget *widget) +{ + if (!widget->priv->cancellable) + return; + + g_cancellable_cancel (widget->priv->cancellable); + g_object_unref (widget->priv->cancellable); + + widget->priv->cancellable = NULL; +} + +static void +pluma_file_browser_widget_finalize (GObject * object) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + GList *loc; + + remove_path_items (obj); + pluma_file_browser_store_set_filter_func (obj->priv->file_store, + NULL, NULL); + + g_object_unref (obj->priv->manager); + g_object_unref (obj->priv->file_store); + g_object_unref (obj->priv->bookmarks_store); + g_object_unref (obj->priv->combo_model); + + g_slist_foreach (obj->priv->filter_funcs, (GFunc) g_free, NULL); + g_slist_free (obj->priv->filter_funcs); + + for (loc = obj->priv->locations; loc; loc = loc->next) + location_free ((Location *) (loc->data)); + + if (obj->priv->current_location_menu_item) + g_object_unref (obj->priv->current_location_menu_item); + + g_list_free (obj->priv->locations); + + g_hash_table_destroy (obj->priv->bookmarks_hash); + + cancel_async_operation (obj); + + gdk_cursor_unref (obj->priv->busy_cursor); + + G_OBJECT_CLASS (pluma_file_browser_widget_parent_class)->finalize (object); +} + +static void +pluma_file_browser_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + + switch (prop_id) + { + case PROP_FILTER_PATTERN: + g_value_set_string (value, obj->priv->filter_pattern_str); + break; + case PROP_ENABLE_DELETE: + g_value_set_boolean (value, obj->priv->enable_delete); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaFileBrowserWidget *obj = PLUMA_FILE_BROWSER_WIDGET (object); + + switch (prop_id) + { + case PROP_FILTER_PATTERN: + pluma_file_browser_widget_set_filter_pattern (obj, + g_value_get_string (value)); + break; + case PROP_ENABLE_DELETE: + set_enable_delete (obj, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_file_browser_widget_class_init (PlumaFileBrowserWidgetClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = pluma_file_browser_widget_finalize; + + object_class->get_property = pluma_file_browser_widget_get_property; + object_class->set_property = pluma_file_browser_widget_set_property; + + g_object_class_install_property (object_class, PROP_FILTER_PATTERN, + g_param_spec_string ("filter-pattern", + "Filter Pattern", + "The filter pattern", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_ENABLE_DELETE, + g_param_spec_boolean ("enable-delete", + "Enable delete", + "Enable permanently deleting items", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[URI_ACTIVATED] = + g_signal_new ("uri-activated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + uri_activated), NULL, NULL, + g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, + G_TYPE_STRING); + signals[ERROR] = + g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + error), NULL, NULL, + pluma_file_browser_marshal_VOID__UINT_STRING, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); + + signals[CONFIRM_DELETE] = + g_signal_new ("confirm-delete", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + confirm_delete), + g_signal_accumulator_true_handled, + NULL, + pluma_file_browser_marshal_BOOL__OBJECT_POINTER, + G_TYPE_BOOLEAN, + 2, + G_TYPE_OBJECT, + G_TYPE_POINTER); + + signals[CONFIRM_NO_TRASH] = + g_signal_new ("confirm-no-trash", G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaFileBrowserWidgetClass, + confirm_no_trash), + g_signal_accumulator_true_handled, + NULL, + pluma_file_browser_marshal_BOOL__POINTER, + G_TYPE_BOOLEAN, + 1, + G_TYPE_POINTER); + + g_type_class_add_private (object_class, + sizeof (PlumaFileBrowserWidgetPrivate)); +} + +static void +add_signal (PlumaFileBrowserWidget * obj, gpointer object, gulong id) +{ + SignalNode *node = g_new (SignalNode, 1); + + node->object = G_OBJECT (object); + node->id = id; + + obj->priv->signal_pool = + g_slist_prepend (obj->priv->signal_pool, node); +} + +static void +clear_signals (PlumaFileBrowserWidget * obj) +{ + GSList *item; + SignalNode *node; + + for (item = obj->priv->signal_pool; item; item = item->next) { + node = (SignalNode *) (item->data); + + g_signal_handler_disconnect (node->object, node->id); + g_free (item->data); + } + + g_slist_free (obj->priv->signal_pool); + obj->priv->signal_pool = NULL; +} + +static gboolean +separator_func (GtkTreeModel * model, GtkTreeIter * iter, gpointer data) +{ + guint id; + + gtk_tree_model_get (model, iter, COLUMN_ID, &id, -1); + + return (id == SEPARATOR_ID); +} + +static gboolean +get_from_bookmark_file (PlumaFileBrowserWidget * obj, GFile * file, + gchar ** name, GdkPixbuf ** icon) +{ + gpointer data; + NameIcon * item; + + data = g_hash_table_lookup (obj->priv->bookmarks_hash, file); + + if (data == NULL) + return FALSE; + + item = (NameIcon *)data; + + *name = g_strdup (item->name); + *icon = item->icon; + + if (item->icon != NULL) + { + g_object_ref (item->icon); + } + + return TRUE; +} + +static void +insert_path_item (PlumaFileBrowserWidget * obj, + GFile * file, + GtkTreeIter * after, + GtkTreeIter * iter, + guint indent) +{ + gchar * unescape; + GdkPixbuf * icon = NULL; + + /* Try to get the icon and name from the bookmarks hash */ + if (!get_from_bookmark_file (obj, file, &unescape, &icon)) { + /* It's not a bookmark, fetch the name and the icon ourselves */ + unescape = pluma_file_browser_utils_file_basename (file); + + /* Get the icon */ + icon = pluma_file_browser_utils_pixbuf_from_file (file, GTK_ICON_SIZE_MENU); + } + + gtk_tree_store_insert_after (obj->priv->combo_model, iter, NULL, + after); + + gtk_tree_store_set (obj->priv->combo_model, + iter, + COLUMN_INDENT, indent, + COLUMN_ICON, icon, + COLUMN_NAME, unescape, + COLUMN_FILE, file, + COLUMN_ID, PATH_ID, + -1); + + if (icon) + g_object_unref (icon); + + g_free (unescape); +} + +static void +insert_separator_item (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + + gtk_tree_store_insert (obj->priv->combo_model, &iter, NULL, 1); + gtk_tree_store_set (obj->priv->combo_model, &iter, + COLUMN_ICON, NULL, + COLUMN_NAME, NULL, + COLUMN_ID, SEPARATOR_ID, -1); +} + +static void +combo_set_active_by_id (PlumaFileBrowserWidget * obj, guint id) +{ + GtkTreeIter iter; + + if (combo_find_by_id (obj, id, &iter)) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX + (obj->priv->combo), &iter); +} + +static guint +uri_num_parents (GFile * from, GFile * to) +{ + /* Determine the number of 'levels' to get from #from to #to. */ + guint parents = 0; + GFile * parent; + + if (from == NULL) + return 0; + + g_object_ref (from); + + while ((parent = g_file_get_parent (from)) && !(to && g_file_equal (from, to))) { + g_object_unref (from); + from = parent; + + ++parents; + } + + g_object_unref (from); + return parents; +} + +static void +insert_location_path (PlumaFileBrowserWidget * obj) +{ + Location *loc; + GFile *current = NULL; + GFile * tmp; + GtkTreeIter separator; + GtkTreeIter iter; + guint indent; + + if (!obj->priv->current_location) { + g_message ("insert_location_path: no current location"); + return; + } + + loc = (Location *) (obj->priv->current_location->data); + + current = loc->virtual_root; + combo_find_by_id (obj, SEPARATOR_ID, &separator); + + indent = uri_num_parents (loc->virtual_root, loc->root); + + while (current != NULL) { + insert_path_item (obj, current, &separator, &iter, indent--); + + if (current == loc->virtual_root) { + g_signal_handlers_block_by_func (obj->priv->combo, + on_combo_changed, + obj); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX + (obj->priv->combo), + &iter); + g_signal_handlers_unblock_by_func (obj->priv-> + combo, + on_combo_changed, + obj); + } + + if (g_file_equal (current, loc->root) || !pluma_utils_file_has_parent (current)) { + if (current != loc->virtual_root) + g_object_unref (current); + break; + } + + tmp = g_file_get_parent (current); + + if (current != loc->virtual_root) + g_object_unref (current); + + current = tmp; + } +} + +static void +check_current_item (PlumaFileBrowserWidget * obj, gboolean show_path) +{ + GtkTreeIter separator; + gboolean has_sep; + + remove_path_items (obj); + has_sep = combo_find_by_id (obj, SEPARATOR_ID, &separator); + + if (show_path) { + if (!has_sep) + insert_separator_item (obj); + + insert_location_path (obj); + } else if (has_sep) + gtk_tree_store_remove (obj->priv->combo_model, &separator); +} + +static void +fill_combo_model (PlumaFileBrowserWidget * obj) +{ + GtkTreeStore *store = obj->priv->combo_model; + GtkTreeIter iter; + GdkPixbuf *icon; + + icon = pluma_file_browser_utils_pixbuf_from_theme (GTK_STOCK_HOME, GTK_ICON_SIZE_MENU); + + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, + COLUMN_ICON, icon, + COLUMN_NAME, _("Bookmarks"), + COLUMN_ID, BOOKMARKS_ID, -1); + g_object_unref (icon); + + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (obj->priv->combo), + separator_func, obj, NULL); + gtk_combo_box_set_active (GTK_COMBO_BOX (obj->priv->combo), 0); +} + +static void +indent_cell_data_func (GtkCellLayout * cell_layout, + GtkCellRenderer * cell, + GtkTreeModel * model, + GtkTreeIter * iter, + gpointer data) +{ + gchar * indent; + guint num; + + gtk_tree_model_get (model, iter, COLUMN_INDENT, &num, -1); + + if (num == 0) + g_object_set (cell, "text", "", NULL); + else { + indent = g_strnfill (num * 2, ' '); + + g_object_set (cell, "text", indent, NULL); + g_free (indent); + } +} + +static void +create_combo (PlumaFileBrowserWidget * obj) +{ + GtkCellRenderer *renderer; + + obj->priv->combo_model = gtk_tree_store_new (N_COLUMNS, + G_TYPE_UINT, + GDK_TYPE_PIXBUF, + G_TYPE_STRING, + G_TYPE_FILE, + G_TYPE_UINT); + obj->priv->combo = + gtk_combo_box_new_with_model (GTK_TREE_MODEL + (obj->priv->combo_model)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, FALSE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT + (obj->priv->combo), renderer, + indent_cell_data_func, obj, NULL); + + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, "pixbuf", COLUMN_ICON); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (obj->priv->combo), + renderer, "text", COLUMN_NAME); + + g_object_set (renderer, "ellipsize-set", TRUE, + "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + gtk_box_pack_start (GTK_BOX (obj), GTK_WIDGET (obj->priv->combo), + FALSE, FALSE, 0); + + fill_combo_model (obj); + g_signal_connect (obj->priv->combo, "changed", + G_CALLBACK (on_combo_changed), obj); + + gtk_widget_show (obj->priv->combo); +} + +static GtkActionEntry toplevel_actions[] = +{ + {"FilterMenuAction", NULL, N_("_Filter")} +}; + +static const GtkActionEntry tree_actions_selection[] = +{ + {"FileMoveToTrash", "mate-stock-trash", N_("_Move to Trash"), NULL, + N_("Move selected file or folder to trash"), + G_CALLBACK (on_action_file_move_to_trash)}, + {"FileDelete", GTK_STOCK_DELETE, N_("_Delete"), NULL, + N_("Delete selected file or folder"), + G_CALLBACK (on_action_file_delete)} +}; + +static const GtkActionEntry tree_actions_file_selection[] = +{ + {"FileOpen", GTK_STOCK_OPEN, NULL, NULL, + N_("Open selected file"), + G_CALLBACK (on_action_file_open)} +}; + +static const GtkActionEntry tree_actions[] = +{ + {"DirectoryUp", GTK_STOCK_GO_UP, N_("Up"), NULL, + N_("Open the parent folder"), G_CALLBACK (on_action_directory_up)} +}; + +static const GtkActionEntry tree_actions_single_most_selection[] = +{ + {"DirectoryNew", GTK_STOCK_ADD, N_("_New Folder"), NULL, + N_("Add new empty folder"), + G_CALLBACK (on_action_directory_new)}, + {"FileNew", GTK_STOCK_NEW, N_("New F_ile"), NULL, + N_("Add new empty file"), G_CALLBACK (on_action_file_new)} +}; + +static const GtkActionEntry tree_actions_single_selection[] = +{ + {"FileRename", NULL, N_("_Rename"), NULL, + N_("Rename selected file or folder"), + G_CALLBACK (on_action_file_rename)} +}; + +static const GtkActionEntry tree_actions_sensitive[] = +{ + {"DirectoryPrevious", GTK_STOCK_GO_BACK, N_("_Previous Location"), + NULL, + N_("Go to the previous visited location"), + G_CALLBACK (on_action_directory_previous)}, + {"DirectoryNext", GTK_STOCK_GO_FORWARD, N_("_Next Location"), NULL, + N_("Go to the next visited location"), G_CALLBACK (on_action_directory_next)}, + {"DirectoryRefresh", GTK_STOCK_REFRESH, N_("Re_fresh View"), NULL, + N_("Refresh the view"), G_CALLBACK (on_action_directory_refresh)}, + {"DirectoryOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, + N_("View folder in file manager"), + G_CALLBACK (on_action_directory_open)} +}; + +static const GtkToggleActionEntry tree_actions_toggle[] = +{ + {"FilterHidden", GTK_STOCK_DIALOG_AUTHENTICATION, + N_("Show _Hidden"), NULL, + N_("Show hidden files and folders"), + G_CALLBACK (on_action_filter_hidden), FALSE}, + {"FilterBinary", NULL, N_("Show _Binary"), NULL, + N_("Show binary files"), G_CALLBACK (on_action_filter_binary), + FALSE} +}; + +static const GtkActionEntry bookmark_actions[] = +{ + {"BookmarkOpen", GTK_STOCK_OPEN, N_("_View Folder"), NULL, + N_("View folder in file manager"), G_CALLBACK (on_action_bookmark_open)} +}; + +static void +create_toolbar (PlumaFileBrowserWidget * obj, + const gchar *data_dir) +{ + GtkUIManager *manager; + GError *error = NULL; + GtkActionGroup *action_group; + GtkWidget *toolbar; + GtkWidget *widget; + GtkAction *action; + gchar *ui_file; + + manager = gtk_ui_manager_new (); + obj->priv->manager = manager; + + ui_file = g_build_filename (data_dir, XML_UI_FILE, NULL); + gtk_ui_manager_add_ui_from_file (manager, ui_file, &error); + + g_free (ui_file); + + if (error != NULL) { + g_warning ("Error in adding ui from file %s: %s", + XML_UI_FILE, error->message); + g_error_free (error); + return; + } + + action_group = gtk_action_group_new ("FileBrowserWidgetActionGroupToplevel"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + toplevel_actions, + G_N_ELEMENTS (toplevel_actions), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + + action_group = gtk_action_group_new ("FileBrowserWidgetActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions, + G_N_ELEMENTS (tree_actions), + obj); + gtk_action_group_add_toggle_actions (action_group, + tree_actions_toggle, + G_N_ELEMENTS (tree_actions_toggle), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_selection, + G_N_ELEMENTS (tree_actions_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetFileSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_file_selection, + G_N_ELEMENTS (tree_actions_file_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_file_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSingleSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_single_selection, + G_N_ELEMENTS (tree_actions_single_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_single_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSingleMostSelectionActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_single_most_selection, + G_N_ELEMENTS (tree_actions_single_most_selection), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_single_most_selection = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetSensitiveActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + tree_actions_sensitive, + G_N_ELEMENTS (tree_actions_sensitive), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->action_group_sensitive = action_group; + + action_group = gtk_action_group_new ("FileBrowserWidgetBookmarkActionGroup"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, + bookmark_actions, + G_N_ELEMENTS (bookmark_actions), + obj); + gtk_ui_manager_insert_action_group (manager, action_group, 0); + obj->priv->bookmark_action_group = action_group; + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, FALSE); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryNext"); + gtk_action_set_sensitive (action, FALSE); + + toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); + gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU); + + /* Previous directory menu tool item */ + obj->priv->location_previous_menu = gtk_menu_new (); + gtk_widget_show (obj->priv->location_previous_menu); + + widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_BACK)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), + obj->priv->location_previous_menu); + + g_object_set (widget, "label", _("Previous location"), NULL); + gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), + _("Go to previous location")); + gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), + _("Go to a previously opened location")); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + g_object_set (action, "is_important", TRUE, "short_label", + _("Previous location"), NULL); + gtk_action_connect_proxy (action, widget); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 0); + + /* Next directory menu tool item */ + obj->priv->location_next_menu = gtk_menu_new (); + gtk_widget_show (obj->priv->location_next_menu); + + widget = GTK_WIDGET (gtk_menu_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), + obj->priv->location_next_menu); + + g_object_set (widget, "label", _("Next location"), NULL); + gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (widget), + _("Go to next location")); + gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (widget), + _("Go to a previously opened location")); + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryNext"); + g_object_set (action, "is_important", TRUE, "short_label", + _("Previous location"), NULL); + gtk_action_connect_proxy (action, widget); + gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget), 1); + + gtk_box_pack_start (GTK_BOX (obj), toolbar, FALSE, FALSE, 0); + gtk_widget_show (toolbar); + + set_enable_delete (obj, obj->priv->enable_delete); +} + +static void +set_enable_delete (PlumaFileBrowserWidget *obj, + gboolean enable) +{ + GtkAction *action; + obj->priv->enable_delete = enable; + + if (obj->priv->action_group_selection == NULL) + return; + + action = + gtk_action_group_get_action (obj->priv->action_group_selection, + "FileDelete"); + + g_object_set (action, "visible", enable, "sensitive", enable, NULL); +} + +static gboolean +filter_real (PlumaFileBrowserStore * model, GtkTreeIter * iter, + PlumaFileBrowserWidget * obj) +{ + GSList *item; + FilterFunc *func; + + for (item = obj->priv->filter_funcs; item; item = item->next) { + func = (FilterFunc *) (item->data); + + if (!func->func (obj, model, iter, func->user_data)) + return FALSE; + } + + return TRUE; +} + +static void +add_bookmark_hash (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter) +{ + GtkTreeModel *model; + GdkPixbuf * pixbuf; + gchar * name; + gchar * uri; + GFile * file; + NameIcon * item; + + model = GTK_TREE_MODEL (obj->priv->bookmarks_store); + + uri = pluma_file_bookmarks_store_get_uri (obj->priv-> + bookmarks_store, + iter); + + if (uri == NULL) + return; + + file = g_file_new_for_uri (uri); + g_free (uri); + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_ICON, + &pixbuf, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_NAME, + &name, -1); + + item = g_new (NameIcon, 1); + item->name = name; + item->icon = pixbuf; + + g_hash_table_insert (obj->priv->bookmarks_hash, + file, + item); +} + +static void +init_bookmarks_hash (PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + model = GTK_TREE_MODEL (obj->priv->bookmarks_store); + + if (!gtk_tree_model_get_iter_first (model, &iter)) + return; + + do { + add_bookmark_hash (obj, &iter); + } while (gtk_tree_model_iter_next (model, &iter)); + + g_signal_connect (obj->priv->bookmarks_store, + "row-changed", + G_CALLBACK (on_bookmarks_row_changed), + obj); + + g_signal_connect (obj->priv->bookmarks_store, + "row-deleted", + G_CALLBACK (on_bookmarks_row_deleted), + obj); +} + +static void +on_begin_loading (PlumaFileBrowserStore *model, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)))) + return; + + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)), + obj->priv->busy_cursor); +} + +static void +on_end_loading (PlumaFileBrowserStore *model, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + if (!GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)))) + return; + + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (obj)), NULL); +} + +static void +create_tree (PlumaFileBrowserWidget * obj) +{ + GtkWidget *sw; + + obj->priv->file_store = pluma_file_browser_store_new (NULL); + obj->priv->bookmarks_store = pluma_file_bookmarks_store_new (); + obj->priv->treeview = + PLUMA_FILE_BROWSER_VIEW (pluma_file_browser_view_new ()); + + pluma_file_browser_view_set_restore_expand_state (obj->priv->treeview, TRUE); + + pluma_file_browser_store_set_filter_mode (obj->priv->file_store, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN + | + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); + pluma_file_browser_store_set_filter_func (obj->priv->file_store, + (PlumaFileBrowserStoreFilterFunc) + filter_real, obj); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), + GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + + gtk_container_add (GTK_CONTAINER (sw), + GTK_WIDGET (obj->priv->treeview)); + gtk_box_pack_start (GTK_BOX (obj), sw, TRUE, TRUE, 0); + + g_signal_connect (obj->priv->treeview, "notify::model", + G_CALLBACK (on_model_set), obj); + g_signal_connect (obj->priv->treeview, "error", + G_CALLBACK (on_treeview_error), obj); + g_signal_connect (obj->priv->treeview, "popup-menu", + G_CALLBACK (on_treeview_popup_menu), obj); + g_signal_connect (obj->priv->treeview, "button-press-event", + G_CALLBACK (on_treeview_button_press_event), + obj); + g_signal_connect (obj->priv->treeview, "key-press-event", + G_CALLBACK (on_treeview_key_press_event), obj); + + g_signal_connect (gtk_tree_view_get_selection + (GTK_TREE_VIEW (obj->priv->treeview)), "changed", + G_CALLBACK (on_selection_changed), obj); + g_signal_connect (obj->priv->file_store, "notify::filter-mode", + G_CALLBACK (on_filter_mode_changed), obj); + + g_signal_connect (obj->priv->file_store, "notify::virtual-root", + G_CALLBACK (on_virtual_root_changed), obj); + + g_signal_connect (obj->priv->file_store, "begin-loading", + G_CALLBACK (on_begin_loading), obj); + + g_signal_connect (obj->priv->file_store, "end-loading", + G_CALLBACK (on_end_loading), obj); + + g_signal_connect (obj->priv->file_store, "error", + G_CALLBACK (on_file_store_error), obj); + + init_bookmarks_hash (obj); + + gtk_widget_show (sw); + gtk_widget_show (GTK_WIDGET (obj->priv->treeview)); +} + +static void +create_filter (PlumaFileBrowserWidget * obj) +{ + GtkWidget *expander; + GtkWidget *vbox; + GtkWidget *entry; + + expander = gtk_expander_new_with_mnemonic (_("_Match Filename")); + gtk_widget_show (expander); + gtk_box_pack_start (GTK_BOX (obj), expander, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 3); + gtk_widget_show (vbox); + + obj->priv->filter_expander = expander; + + entry = gtk_entry_new (); + gtk_widget_show (entry); + + obj->priv->filter_entry = entry; + + g_signal_connect_swapped (entry, "activate", + G_CALLBACK (on_entry_filter_activate), + obj); + g_signal_connect_swapped (entry, "focus_out_event", + G_CALLBACK (on_entry_filter_activate), + obj); + + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (expander), vbox); +} + +static void +pluma_file_browser_widget_init (PlumaFileBrowserWidget * obj) +{ + obj->priv = PLUMA_FILE_BROWSER_WIDGET_GET_PRIVATE (obj); + + obj->priv->bookmarks_hash = g_hash_table_new_full (g_file_hash, + (GEqualFunc)g_file_equal, + g_object_unref, + free_name_icon); + + gtk_box_set_spacing (GTK_BOX (obj), 3); + + obj->priv->busy_cursor = gdk_cursor_new (GDK_WATCH); +} + +/* Private */ + +static void +update_sensitivity (PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + GtkAction *action; + gint mode; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) { + gtk_action_group_set_sensitive (obj->priv->action_group, + TRUE); + gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, + FALSE); + + mode = + pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (model)); + + action = + gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden"); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + !(mode & + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN)); + } else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + gtk_action_group_set_sensitive (obj->priv->action_group, + FALSE); + gtk_action_group_set_sensitive (obj->priv->bookmark_action_group, + TRUE); + + /* Set the filter toggle to normal up state, just for visual pleasure */ + action = + gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden"); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + FALSE); + } + + on_selection_changed (gtk_tree_view_get_selection + (GTK_TREE_VIEW (obj->priv->treeview)), obj); +} + +static gboolean +pluma_file_browser_widget_get_first_selected (PlumaFileBrowserWidget *obj, + GtkTreeIter *iter) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + GtkTreeModel *model; + GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); + gboolean result; + + if (!rows) + return FALSE; + + result = gtk_tree_model_get_iter(model, iter, (GtkTreePath *)(rows->data)); + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +static gboolean +popup_menu (PlumaFileBrowserWidget * obj, GdkEventButton * event, GtkTreeModel * model) +{ + GtkWidget *menu; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + menu = gtk_ui_manager_get_widget (obj->priv->manager, "/FilePopup"); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + menu = gtk_ui_manager_get_widget (obj->priv->manager, "/BookmarkPopup"); + else + return FALSE; + + g_return_val_if_fail (menu != NULL, FALSE); + + if (event != NULL) { + GtkTreeSelection *selection; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (gtk_tree_selection_count_selected_rows (selection) <= 1) { + GtkTreePath *path; + + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (obj->priv->treeview), + (gint)event->x, (gint)event->y, + &path, NULL, NULL, NULL)) + { + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + } + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + } else { + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + pluma_utils_menu_position_under_tree_view, + obj->priv->treeview, 0, + gtk_get_current_event_time ()); + gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE); + } + + return TRUE; +} + +static gboolean +filter_glob (PlumaFileBrowserWidget * obj, PlumaFileBrowserStore * store, + GtkTreeIter * iter, gpointer user_data) +{ + gchar *name; + gboolean result; + guint flags; + + if (obj->priv->filter_pattern == NULL) + return TRUE; + + gtk_tree_model_get (GTK_TREE_MODEL (store), iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_NAME, &name, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (FILE_IS_DIR (flags) || FILE_IS_DUMMY (flags)) + result = TRUE; + else + result = + g_pattern_match_string (obj->priv->filter_pattern, + name); + + g_free (name); + + return result; +} + +static void +rename_selected_file (PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (pluma_file_browser_widget_get_first_selected (obj, &iter)) + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); +} + +static GList * +get_deletable_files (PlumaFileBrowserWidget *obj) { + GtkTreeSelection *selection; + GtkTreeModel *model; + GList *rows; + GList *row; + GList *paths = NULL; + guint flags; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + /* Get all selected files */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + continue; + + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, + &flags, -1); + + if (FILE_IS_DUMMY (flags)) + continue; + + paths = g_list_append (paths, gtk_tree_path_copy (path)); + } + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return paths; +} + +static gboolean +delete_selected_files (PlumaFileBrowserWidget * obj, gboolean trash) +{ + GtkTreeModel *model; + gboolean confirm; + PlumaFileBrowserStoreResult result; + GList *rows; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return FALSE; + + rows = get_deletable_files (obj); + + if (!rows) + return FALSE; + + if (!trash) { + g_signal_emit (obj, signals[CONFIRM_DELETE], 0, model, rows, &confirm); + + if (!confirm) + return FALSE; + } + + result = pluma_file_browser_store_delete_all (PLUMA_FILE_BROWSER_STORE (model), + rows, trash); + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result == PLUMA_FILE_BROWSER_STORE_RESULT_OK; +} + +static gboolean +on_file_store_no_trash (PlumaFileBrowserStore * store, + GList * files, + PlumaFileBrowserWidget * obj) +{ + gboolean confirm = FALSE; + + g_signal_emit (obj, signals[CONFIRM_NO_TRASH], 0, files, &confirm); + + return confirm; +} + +static GFile * +get_topmost_file (GFile * file) +{ + GFile * tmp; + GFile * current; + + current = g_object_ref (file); + + while ((tmp = g_file_get_parent (current)) != NULL) { + g_object_unref (current); + current = tmp; + } + + return current; +} + +static GtkWidget * +create_goto_menu_item (PlumaFileBrowserWidget * obj, GList * item, + GdkPixbuf * icon) +{ + GtkWidget *result; + GtkWidget *image; + gchar *unescape; + GdkPixbuf *pixbuf = NULL; + Location *loc; + + loc = (Location *) (item->data); + + if (!get_from_bookmark_file (obj, loc->virtual_root, &unescape, &pixbuf)) { + unescape = pluma_file_browser_utils_file_basename (loc->virtual_root); + + if (icon) + pixbuf = g_object_ref (icon); + } + + if (pixbuf) { + image = gtk_image_new_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + + gtk_widget_show (image); + + result = gtk_image_menu_item_new_with_label (unescape); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (result), + image); + } else { + result = gtk_menu_item_new_with_label (unescape); + } + + g_object_set_data (G_OBJECT (result), LOCATION_DATA_KEY, item); + g_signal_connect (result, "activate", + G_CALLBACK (on_location_jump_activate), obj); + + gtk_widget_show (result); + + g_free (unescape); + + return result; +} + +static GList * +list_next_iterator (GList * list) +{ + if (!list) + return NULL; + + return list->next; +} + +static GList * +list_prev_iterator (GList * list) +{ + if (!list) + return NULL; + + return list->prev; +} + +static void +jump_to_location (PlumaFileBrowserWidget * obj, GList * item, + gboolean previous) +{ + Location *loc; + GtkWidget *widget; + GList *children; + GList *child; + GList *(*iter_func) (GList *); + GtkWidget *menu_from; + GtkWidget *menu_to; + gchar *root; + gchar *virtual_root; + + if (!obj->priv->locations) + return; + + if (previous) { + iter_func = list_next_iterator; + menu_from = obj->priv->location_previous_menu; + menu_to = obj->priv->location_next_menu; + } else { + iter_func = list_prev_iterator; + menu_from = obj->priv->location_next_menu; + menu_to = obj->priv->location_previous_menu; + } + + children = gtk_container_get_children (GTK_CONTAINER (menu_from)); + child = children; + + /* This is the menuitem for the current location, which is the first + to be added to the menu */ + widget = obj->priv->current_location_menu_item; + + while (obj->priv->current_location != item) { + if (widget) { + /* Prepend the menu item to the menu */ + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_to), + widget); + + g_object_unref (widget); + } + + widget = GTK_WIDGET (child->data); + + /* Make sure the widget isn't destroyed when removed */ + g_object_ref (widget); + gtk_container_remove (GTK_CONTAINER (menu_from), widget); + + obj->priv->current_location_menu_item = widget; + + if (obj->priv->current_location == NULL) { + obj->priv->current_location = obj->priv->locations; + + if (obj->priv->current_location == item) + break; + } else { + obj->priv->current_location = + iter_func (obj->priv->current_location); + } + + child = child->next; + } + + g_list_free (children); + + obj->priv->changing_location = TRUE; + + loc = (Location *) (obj->priv->current_location->data); + + /* Set the new root + virtual root */ + root = g_file_get_uri (loc->root); + virtual_root = g_file_get_uri (loc->virtual_root); + + pluma_file_browser_widget_set_root_and_virtual_root (obj, + root, + virtual_root); + + g_free (root); + g_free (virtual_root); + + obj->priv->changing_location = FALSE; +} + +static void +clear_next_locations (PlumaFileBrowserWidget * obj) +{ + GList *children; + GList *item; + + if (obj->priv->current_location == NULL) + return; + + while (obj->priv->current_location->prev) { + location_free ((Location *) (obj->priv->current_location-> + prev->data)); + obj->priv->locations = + g_list_remove_link (obj->priv->locations, + obj->priv->current_location->prev); + } + + children = + gtk_container_get_children (GTK_CONTAINER + (obj->priv->location_next_menu)); + + for (item = children; item; item = item->next) { + gtk_container_remove (GTK_CONTAINER + (obj->priv->location_next_menu), + GTK_WIDGET (item->data)); + } + + g_list_free (children); + + gtk_action_set_sensitive (gtk_action_group_get_action + (obj->priv->action_group_sensitive, + "DirectoryNext"), FALSE); +} + +static void +update_filter_mode (PlumaFileBrowserWidget * obj, + GtkAction * action, + PlumaFileBrowserStoreFilterMode mode) +{ + gboolean active = + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + gint now; + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) { + now = + pluma_file_browser_store_get_filter_mode + (PLUMA_FILE_BROWSER_STORE (model)); + + if (active) + now &= ~mode; + else + now |= mode; + + pluma_file_browser_store_set_filter_mode + (PLUMA_FILE_BROWSER_STORE (model), now); + } +} + +static void +set_filter_pattern_real (PlumaFileBrowserWidget * obj, + gchar const * pattern, + gboolean update_entry) +{ + GtkTreeModel *model; + + model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (pattern != NULL && *pattern == '\0') + pattern = NULL; + + if (pattern == NULL && obj->priv->filter_pattern_str == NULL) + return; + + if (pattern != NULL && obj->priv->filter_pattern_str != NULL && + strcmp (pattern, obj->priv->filter_pattern_str) == 0) + return; + + /* Free the old pattern */ + g_free (obj->priv->filter_pattern_str); + obj->priv->filter_pattern_str = g_strdup (pattern); + + if (obj->priv->filter_pattern) { + g_pattern_spec_free (obj->priv->filter_pattern); + obj->priv->filter_pattern = NULL; + } + + if (pattern == NULL) { + if (obj->priv->glob_filter_id != 0) { + pluma_file_browser_widget_remove_filter (obj, + obj-> + priv-> + glob_filter_id); + obj->priv->glob_filter_id = 0; + } + } else { + obj->priv->filter_pattern = g_pattern_spec_new (pattern); + + if (obj->priv->glob_filter_id == 0) + obj->priv->glob_filter_id = + pluma_file_browser_widget_add_filter (obj, + filter_glob, + NULL, + NULL); + } + + if (update_entry) { + if (obj->priv->filter_pattern_str == NULL) + gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), + ""); + else { + gtk_entry_set_text (GTK_ENTRY (obj->priv->filter_entry), + obj->priv->filter_pattern_str); + + gtk_expander_set_expanded (GTK_EXPANDER (obj->priv->filter_expander), + TRUE); + } + } + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refilter (PLUMA_FILE_BROWSER_STORE + (model)); + + g_object_notify (G_OBJECT (obj), "filter-pattern"); +} + + +/* Public */ + +GtkWidget * +pluma_file_browser_widget_new (const gchar *data_dir) +{ + PlumaFileBrowserWidget *obj = + g_object_new (PLUMA_TYPE_FILE_BROWSER_WIDGET, NULL); + + create_toolbar (obj, data_dir); + create_combo (obj); + create_tree (obj); + create_filter (obj); + + pluma_file_browser_widget_show_bookmarks (obj); + + return GTK_WIDGET (obj); +} + +void +pluma_file_browser_widget_show_bookmarks (PlumaFileBrowserWidget * obj) +{ + /* Select bookmarks in the combo box */ + g_signal_handlers_block_by_func (obj->priv->combo, + on_combo_changed, obj); + combo_set_active_by_id (obj, BOOKMARKS_ID); + g_signal_handlers_unblock_by_func (obj->priv->combo, + on_combo_changed, obj); + + check_current_item (obj, FALSE); + + pluma_file_browser_view_set_model (obj->priv->treeview, + GTK_TREE_MODEL (obj->priv-> + bookmarks_store)); +} + +static void +show_files_real (PlumaFileBrowserWidget *obj, + gboolean do_root_changed) +{ + pluma_file_browser_view_set_model (obj->priv->treeview, + GTK_TREE_MODEL (obj->priv-> + file_store)); + + if (do_root_changed) + on_virtual_root_changed (obj->priv->file_store, NULL, obj); +} + +void +pluma_file_browser_widget_show_files (PlumaFileBrowserWidget * obj) +{ + show_files_real (obj, TRUE); +} + +void +pluma_file_browser_widget_set_root_and_virtual_root (PlumaFileBrowserWidget *obj, + gchar const *root, + gchar const *virtual_root) +{ + PlumaFileBrowserStoreResult result; + + if (!virtual_root) + result = + pluma_file_browser_store_set_root_and_virtual_root + (obj->priv->file_store, root, root); + else + result = + pluma_file_browser_store_set_root_and_virtual_root + (obj->priv->file_store, root, virtual_root); + + if (result == PLUMA_FILE_BROWSER_STORE_RESULT_NO_CHANGE) + show_files_real (obj, TRUE); +} + +void +pluma_file_browser_widget_set_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gboolean virtual_root) +{ + GFile *file; + GFile *parent; + gchar *str; + + if (!virtual_root) { + pluma_file_browser_widget_set_root_and_virtual_root (obj, + root, + NULL); + return; + } + + if (!root) + return; + + file = g_file_new_for_uri (root); + parent = get_topmost_file (file); + str = g_file_get_uri (parent); + + pluma_file_browser_widget_set_root_and_virtual_root + (obj, str, root); + + g_free (str); + + g_object_unref (file); + g_object_unref (parent); +} + +PlumaFileBrowserStore * +pluma_file_browser_widget_get_browser_store (PlumaFileBrowserWidget * obj) +{ + return obj->priv->file_store; +} + +PlumaFileBookmarksStore * +pluma_file_browser_widget_get_bookmarks_store (PlumaFileBrowserWidget * obj) +{ + return obj->priv->bookmarks_store; +} + +PlumaFileBrowserView * +pluma_file_browser_widget_get_browser_view (PlumaFileBrowserWidget * obj) +{ + return obj->priv->treeview; +} + +GtkUIManager * +pluma_file_browser_widget_get_ui_manager (PlumaFileBrowserWidget * obj) +{ + return obj->priv->manager; +} + +GtkWidget * +pluma_file_browser_widget_get_filter_entry (PlumaFileBrowserWidget * obj) +{ + return obj->priv->filter_entry; +} + +gulong +pluma_file_browser_widget_add_filter (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify) +{ + FilterFunc *f; + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + f = filter_func_new (obj, func, user_data, notify); + obj->priv->filter_funcs = + g_slist_append (obj->priv->filter_funcs, f); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refilter (PLUMA_FILE_BROWSER_STORE + (model)); + + return f->id; +} + +void +pluma_file_browser_widget_remove_filter (PlumaFileBrowserWidget * obj, + gulong id) +{ + GSList *item; + FilterFunc *func; + + for (item = obj->priv->filter_funcs; item; item = item->next) + { + func = (FilterFunc *) (item->data); + + if (func->id == id) + { + if (func->destroy_notify) + func->destroy_notify (func->user_data); + + obj->priv->filter_funcs = + g_slist_remove_link (obj->priv->filter_funcs, + item); + g_free (func); + break; + } + } +} + +void +pluma_file_browser_widget_set_filter_pattern (PlumaFileBrowserWidget * obj, + gchar const *pattern) +{ + set_filter_pattern_real (obj, pattern, TRUE); +} + +gboolean +pluma_file_browser_widget_get_selected_directory (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + GtkTreeIter parent; + guint flags; + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return FALSE; + + if (!pluma_file_browser_widget_get_first_selected (obj, iter)) { + if (!pluma_file_browser_store_get_iter_virtual_root + (PLUMA_FILE_BROWSER_STORE (model), iter)) + return FALSE; + } + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!FILE_IS_DIR (flags)) { + /* Get the parent, because the selection is a file */ + gtk_tree_model_iter_parent (model, &parent, iter); + *iter = parent; + } + + return TRUE; +} + +static guint +pluma_file_browser_widget_get_num_selected_files_or_directories (PlumaFileBrowserWidget *obj, + guint *files, + guint *dirs) +{ + GList *rows, *row; + GtkTreePath *path; + GtkTreeIter iter; + PlumaFileBrowserStoreFlag flags; + guint result = 0; + GtkTreeSelection *selection; + GtkTreeModel *model; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + return 0; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + /* Get iter from path */ + if (!gtk_tree_model_get_iter (model, &iter, path)) + continue; + + gtk_tree_model_get (model, &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + -1); + + if (!FILE_IS_DUMMY (flags)) { + if (!FILE_IS_DIR (flags)) + ++(*files); + else + ++(*dirs); + + ++result; + } + } + + g_list_foreach (rows, (GFunc)gtk_tree_path_free, NULL); + g_list_free (rows); + + return result; +} + +typedef struct +{ + PlumaFileBrowserWidget *widget; + GCancellable *cancellable; +} AsyncData; + +static AsyncData * +async_data_new (PlumaFileBrowserWidget *widget) +{ + AsyncData *ret; + + ret = g_new (AsyncData, 1); + ret->widget = widget; + + cancel_async_operation (widget); + widget->priv->cancellable = g_cancellable_new (); + + ret->cancellable = g_object_ref (widget->priv->cancellable); + + return ret; +} + +static void +async_free (AsyncData *async) +{ + g_object_unref (async->cancellable); + g_free (async); +} + +static void +set_busy (PlumaFileBrowserWidget *obj, gboolean busy) +{ + GdkCursor *cursor; + GdkWindow *window; + + window = gtk_widget_get_window (GTK_WIDGET (obj->priv->treeview)); + + if (!GDK_IS_WINDOW (window)) + return; + + if (busy) + { + cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (window, cursor); + gdk_cursor_unref (cursor); + } + else + { + gdk_window_set_cursor (window, NULL); + } +} + +static void try_mount_volume (PlumaFileBrowserWidget *widget, GVolume *volume); + +static void +activate_mount (PlumaFileBrowserWidget *widget, + GVolume *volume, + GMount *mount) +{ + GFile *root; + gchar *uri; + + if (!mount) + { + gchar *message; + gchar *name; + + name = g_volume_get_name (volume); + message = g_strdup_printf (_("No mount object for mounted volume: %s"), name); + + g_signal_emit (widget, + signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + message); + + g_free (name); + g_free (message); + return; + } + + root = g_mount_get_root (mount); + uri = g_file_get_uri (root); + + pluma_file_browser_widget_set_root (widget, uri, FALSE); + + g_free (uri); + g_object_unref (root); +} + +static void +try_activate_drive (PlumaFileBrowserWidget *widget, + GDrive *drive) +{ + GList *volumes; + GVolume *volume; + GMount *mount; + + volumes = g_drive_get_volumes (drive); + + volume = G_VOLUME (volumes->data); + mount = g_volume_get_mount (volume); + + if (mount) + { + /* try set the root of the mount */ + activate_mount (widget, volume, mount); + g_object_unref (mount); + } + else + { + /* try to mount it then? */ + try_mount_volume (widget, volume); + } + + g_list_foreach (volumes, (GFunc)g_object_unref, NULL); + g_list_free (volumes); +} + +static void +poll_for_media_cb (GDrive *drive, + GAsyncResult *res, + AsyncData *async) +{ + GError *error = NULL; + + /* check for cancelled state */ + if (g_cancellable_is_cancelled (async->cancellable)) + { + async_free (async); + return; + } + + /* finish poll operation */ + set_busy (async->widget, FALSE); + + if (g_drive_poll_for_media_finish (drive, res, &error) && + g_drive_has_media (drive) && + g_drive_has_volumes (drive)) + { + try_activate_drive (async->widget, drive); + } + else + { + gchar *message; + gchar *name; + + name = g_drive_get_name (drive); + message = g_strdup_printf (_("Could not open media: %s"), name); + + g_signal_emit (async->widget, + signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + message); + + g_free (name); + g_free (message); + + g_error_free (error); + } + + async_free (async); +} + +static void +mount_volume_cb (GVolume *volume, + GAsyncResult *res, + AsyncData *async) +{ + GError *error = NULL; + + /* check for cancelled state */ + if (g_cancellable_is_cancelled (async->cancellable)) + { + async_free (async); + return; + } + + if (g_volume_mount_finish (volume, res, &error)) + { + GMount *mount; + + mount = g_volume_get_mount (volume); + activate_mount (async->widget, volume, mount); + + if (mount) + g_object_unref (mount); + } + else + { + gchar *message; + gchar *name; + + name = g_volume_get_name (volume); + message = g_strdup_printf (_("Could not mount volume: %s"), name); + + g_signal_emit (async->widget, + signals[ERROR], + 0, + PLUMA_FILE_BROWSER_ERROR_SET_ROOT, + message); + + g_free (name); + g_free (message); + + g_error_free (error); + } + + set_busy (async->widget, FALSE); + async_free (async); +} + +static void +activate_drive (PlumaFileBrowserWidget *obj, + GtkTreeIter *iter) +{ + GDrive *drive; + AsyncData *async; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &drive, -1); + + /* most common use case is a floppy drive, we'll poll for media and + go from there */ + async = async_data_new (obj); + g_drive_poll_for_media (drive, + async->cancellable, + (GAsyncReadyCallback)poll_for_media_cb, + async); + + g_object_unref (drive); + set_busy (obj, TRUE); +} + +static void +try_mount_volume (PlumaFileBrowserWidget *widget, + GVolume *volume) +{ + GMountOperation *operation; + AsyncData *async; + + operation = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); + async = async_data_new (widget); + + g_volume_mount (volume, + G_MOUNT_MOUNT_NONE, + operation, + async->cancellable, + (GAsyncReadyCallback)mount_volume_cb, + async); + + g_object_unref (operation); + set_busy (widget, TRUE); +} + +static void +activate_volume (PlumaFileBrowserWidget *obj, + GtkTreeIter *iter) +{ + GVolume *volume; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->bookmarks_store), iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_OBJECT, + &volume, -1); + + /* see if we can mount the volume */ + try_mount_volume (obj, volume); + g_object_unref (volume); +} + +void +pluma_file_browser_widget_refresh (PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = + gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + pluma_file_browser_store_refresh (PLUMA_FILE_BROWSER_STORE + (model)); + else if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + g_hash_table_ref (obj->priv->bookmarks_hash); + g_hash_table_destroy (obj->priv->bookmarks_hash); + + pluma_file_bookmarks_store_refresh + (PLUMA_FILE_BOOKMARKS_STORE (model)); + } +} + +void +pluma_file_browser_widget_history_back (PlumaFileBrowserWidget *obj) +{ + if (obj->priv->locations) { + if (obj->priv->current_location) + jump_to_location (obj, + obj->priv->current_location-> + next, TRUE); + else { + jump_to_location (obj, obj->priv->locations, TRUE); + } + } +} + +void +pluma_file_browser_widget_history_forward (PlumaFileBrowserWidget *obj) +{ + if (obj->priv->locations) + jump_to_location (obj, obj->priv->current_location->prev, + FALSE); +} + +static void +bookmark_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gchar *uri; + gint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BOOKMARKS_STORE_COLUMN_FLAGS, + &flags, -1); + + if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_DRIVE) + { + /* handle a drive node */ + pluma_file_browser_store_cancel_mount_operation (obj->priv->file_store); + activate_drive (obj, iter); + return; + } + else if (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_VOLUME) + { + /* handle a volume node */ + pluma_file_browser_store_cancel_mount_operation (obj->priv->file_store); + activate_volume (obj, iter); + return; + } + + uri = + pluma_file_bookmarks_store_get_uri + (PLUMA_FILE_BOOKMARKS_STORE (model), iter); + + if (uri) { + /* here we check if the bookmark is a mount point, or if it + is a remote bookmark. If that's the case, we will set the + root to the uri of the bookmark and not try to set the + topmost parent as root (since that may as well not be the + mount point anymore) */ + if ((flags & PLUMA_FILE_BOOKMARKS_STORE_IS_MOUNT) || + (flags & PLUMA_FILE_BOOKMARKS_STORE_IS_REMOTE_BOOKMARK)) { + pluma_file_browser_widget_set_root (obj, + uri, + FALSE); + } else { + pluma_file_browser_widget_set_root (obj, + uri, + TRUE); + } + } else { + g_warning ("No uri!"); + } + + g_free (uri); +} + +static void +file_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gchar *uri; + gint flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + if (!FILE_IS_DIR (flags) && !FILE_IS_DUMMY (flags)) { + g_signal_emit (obj, signals[URI_ACTIVATED], 0, uri); + } + + g_free (uri); +} + +static gboolean +directory_open (PlumaFileBrowserWidget *obj, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + gboolean result = FALSE; + GError *error = NULL; + gchar *uri = NULL; + PlumaFileBrowserStoreFlag flags; + + gtk_tree_model_get (model, iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri, + -1); + + if (FILE_IS_DIR (flags)) { + result = TRUE; + + if (!gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (obj)), uri, GDK_CURRENT_TIME, &error)) { + g_signal_emit (obj, signals[ERROR], 0, + PLUMA_FILE_BROWSER_ERROR_OPEN_DIRECTORY, + error->message); + + g_error_free (error); + error = NULL; + } + } + + g_free (uri); + + return result; +} + +static void +on_bookmark_activated (PlumaFileBrowserView *tree_view, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + + bookmark_open (obj, model, iter); +} + +static void +on_file_activated (PlumaFileBrowserView *tree_view, + GtkTreeIter *iter, + PlumaFileBrowserWidget *obj) +{ + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + + file_open (obj, model, iter); +} + +static gboolean +virtual_root_is_root (PlumaFileBrowserWidget * obj, + PlumaFileBrowserStore * model) +{ + GtkTreeIter root; + GtkTreeIter virtual_root; + + if (!pluma_file_browser_store_get_iter_root (model, &root)) + return TRUE; + + if (!pluma_file_browser_store_get_iter_virtual_root (model, &virtual_root)) + return TRUE; + + return pluma_file_browser_store_iter_equal (model, &root, &virtual_root); +} + +static void +on_virtual_root_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + gchar *uri; + gchar *root_uri; + GtkTreeIter root; + GtkAction *action; + Location *loc; + GdkPixbuf *pixbuf; + + if (gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)) != + GTK_TREE_MODEL (obj->priv->file_store)) + { + show_files_real (obj, FALSE); + } + + if (pluma_file_browser_store_get_iter_virtual_root (model, &iter)) { + gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_URI, + &uri, -1); + + if (pluma_file_browser_store_get_iter_root (model, &root)) { + if (!obj->priv->changing_location) { + /* Remove all items from obj->priv->current_location on */ + if (obj->priv->current_location) + clear_next_locations (obj); + + root_uri = + pluma_file_browser_store_get_root + (model); + + loc = g_new (Location, 1); + loc->root = g_file_new_for_uri (root_uri); + loc->virtual_root = g_file_new_for_uri (uri); + g_free (root_uri); + + if (obj->priv->current_location) { + /* Add current location to the menu so we can go back + to it later */ + gtk_menu_shell_prepend + (GTK_MENU_SHELL + (obj->priv-> + location_previous_menu), + obj->priv-> + current_location_menu_item); + } + + obj->priv->locations = + g_list_prepend (obj->priv->locations, + loc); + + gtk_tree_model_get (GTK_TREE_MODEL (model), + &iter, + PLUMA_FILE_BROWSER_STORE_COLUMN_ICON, + &pixbuf, -1); + + obj->priv->current_location = + obj->priv->locations; + obj->priv->current_location_menu_item = + create_goto_menu_item (obj, + obj->priv-> + current_location, + pixbuf); + + g_object_ref_sink (obj->priv-> + current_location_menu_item); + + if (pixbuf) + g_object_unref (pixbuf); + + } + + action = + gtk_action_group_get_action (obj->priv-> + action_group, + "DirectoryUp"); + gtk_action_set_sensitive (action, + !virtual_root_is_root (obj, model)); + + action = + gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, + obj->priv-> + current_location != NULL + && obj->priv-> + current_location->next != + NULL); + + action = + gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryNext"); + gtk_action_set_sensitive (action, + obj->priv-> + current_location != NULL + && obj->priv-> + current_location->prev != + NULL); + } + + check_current_item (obj, TRUE); + g_free (uri); + } else { + g_message ("NO!"); + } +} + +static void +on_model_set (GObject * gobject, GParamSpec * arg1, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (gobject)); + + clear_signals (obj); + + if (PLUMA_IS_FILE_BOOKMARKS_STORE (model)) { + clear_next_locations (obj); + + /* Add the current location to the back menu */ + if (obj->priv->current_location) { + GtkAction *action; + + gtk_menu_shell_prepend (GTK_MENU_SHELL (obj->priv->location_previous_menu), + obj->priv->current_location_menu_item); + + g_object_unref (obj->priv->current_location_menu_item); + obj->priv->current_location = NULL; + obj->priv->current_location_menu_item = NULL; + + action = gtk_action_group_get_action (obj->priv->action_group_sensitive, + "DirectoryPrevious"); + gtk_action_set_sensitive (action, TRUE); + } + + gtk_widget_set_sensitive (obj->priv->filter_expander, FALSE); + + add_signal (obj, gobject, + g_signal_connect (gobject, "bookmark-activated", + G_CALLBACK + (on_bookmark_activated), obj)); + } else if (PLUMA_IS_FILE_BROWSER_STORE (model)) { + /* make sure any async operation is cancelled */ + cancel_async_operation (obj); + + add_signal (obj, gobject, + g_signal_connect (gobject, "file-activated", + G_CALLBACK + (on_file_activated), obj)); + + add_signal (obj, model, + g_signal_connect (model, "no-trash", + G_CALLBACK + (on_file_store_no_trash), obj)); + + gtk_widget_set_sensitive (obj->priv->filter_expander, TRUE); + } + + update_sensitivity (obj); +} + +static void +on_file_store_error (PlumaFileBrowserStore * store, guint code, + gchar * message, PlumaFileBrowserWidget * obj) +{ + g_signal_emit (obj, signals[ERROR], 0, code, message); +} + +static void +on_treeview_error (PlumaFileBrowserView * tree_view, guint code, + gchar * message, PlumaFileBrowserWidget * obj) +{ + g_signal_emit (obj, signals[ERROR], 0, code, message); +} + +static void +on_combo_changed (GtkComboBox * combo, PlumaFileBrowserWidget * obj) +{ + GtkTreeIter iter; + guint id; + gchar * uri; + GFile * file; + + if (!gtk_combo_box_get_active_iter (combo, &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (obj->priv->combo_model), &iter, + COLUMN_ID, &id, -1); + + switch (id) { + case BOOKMARKS_ID: + pluma_file_browser_widget_show_bookmarks (obj); + break; + + case PATH_ID: + gtk_tree_model_get (GTK_TREE_MODEL + (obj->priv->combo_model), &iter, + COLUMN_FILE, &file, -1); + + uri = g_file_get_uri (file); + pluma_file_browser_store_set_virtual_root_from_string + (obj->priv->file_store, uri); + + g_free (uri); + g_object_unref (file); + break; + } +} + +static gboolean +on_treeview_popup_menu (PlumaFileBrowserView * treeview, + PlumaFileBrowserWidget * obj) +{ + return popup_menu (obj, NULL, gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); +} + +static gboolean +on_treeview_button_press_event (PlumaFileBrowserView * treeview, + GdkEventButton * event, + PlumaFileBrowserWidget * obj) +{ + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + return popup_menu (obj, event, + gtk_tree_view_get_model (GTK_TREE_VIEW (treeview))); + } + + return FALSE; +} + +static gboolean +do_change_directory (PlumaFileBrowserWidget * obj, + GdkEventKey * event) +{ + GtkAction * action = NULL; + + if ((event->state & + (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK & ~GDK_MOD1_MASK)) == + event->state && event->keyval == GDK_BackSpace) + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + else if (!((event->state & GDK_MOD1_MASK) && + (event->state & (~GDK_CONTROL_MASK & ~GDK_SHIFT_MASK)) == event->state)) + return FALSE; + + switch (event->keyval) { + case GDK_Left: + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryPrevious"); + break; + case GDK_Right: + action = gtk_action_group_get_action (obj->priv-> + action_group_sensitive, + "DirectoryNext"); + break; + case GDK_Up: + action = gtk_action_group_get_action (obj->priv-> + action_group, + "DirectoryUp"); + break; + default: + break; + } + + if (action != NULL) { + gtk_action_activate (action); + return TRUE; + } + + return FALSE; +} + +static gboolean +on_treeview_key_press_event (PlumaFileBrowserView * treeview, + GdkEventKey * event, + PlumaFileBrowserWidget * obj) +{ + guint modifiers; + + if (do_change_directory (obj, event)) + return TRUE; + + if (!PLUMA_IS_FILE_BROWSER_STORE + (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)))) + return FALSE; + + modifiers = gtk_accelerator_get_default_mod_mask (); + + if (event->keyval == GDK_Delete + || event->keyval == GDK_KP_Delete) { + + if ((event->state & modifiers) == GDK_SHIFT_MASK) { + if (obj->priv->enable_delete) { + delete_selected_files (obj, FALSE); + return TRUE; + } + } else if ((event->state & modifiers) == 0) { + delete_selected_files (obj, TRUE); + return TRUE; + } + } + + if ((event->keyval == GDK_F2) + && (event->state & modifiers) == 0) { + rename_selected_file (obj); + + return TRUE; + } + + return FALSE; +} + +static void +on_selection_changed (GtkTreeSelection * selection, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + guint selected = 0; + guint files = 0; + guint dirs = 0; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (PLUMA_IS_FILE_BROWSER_STORE (model)) + { + selected = pluma_file_browser_widget_get_num_selected_files_or_directories (obj, + &files, + &dirs); + } + + gtk_action_group_set_sensitive (obj->priv->action_group_selection, + selected > 0); + gtk_action_group_set_sensitive (obj->priv->action_group_file_selection, + (selected > 0) && (selected == files)); + gtk_action_group_set_sensitive (obj->priv->action_group_single_selection, + selected == 1); + gtk_action_group_set_sensitive (obj->priv->action_group_single_most_selection, + selected <= 1); +} + +static gboolean +on_entry_filter_activate (PlumaFileBrowserWidget * obj) +{ + gchar const *text; + + text = gtk_entry_get_text (GTK_ENTRY (obj->priv->filter_entry)); + set_filter_pattern_real (obj, text, FALSE); + + return FALSE; +} + +static void +on_location_jump_activate (GtkMenuItem * item, + PlumaFileBrowserWidget * obj) +{ + GList *location; + + location = g_object_get_data (G_OBJECT (item), LOCATION_DATA_KEY); + + if (obj->priv->current_location) { + jump_to_location (obj, location, + g_list_position (obj->priv->locations, + location) > + g_list_position (obj->priv->locations, + obj->priv-> + current_location)); + } else { + jump_to_location (obj, location, TRUE); + } + +} + +static void +on_bookmarks_row_changed (GtkTreeModel * model, + GtkTreePath * path, + GtkTreeIter * iter, + PlumaFileBrowserWidget *obj) +{ + add_bookmark_hash (obj, iter); +} + +static void +on_bookmarks_row_deleted (GtkTreeModel * model, + GtkTreePath * path, + PlumaFileBrowserWidget *obj) +{ + GtkTreeIter iter; + gchar * uri; + GFile * file; + + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; + + uri = pluma_file_bookmarks_store_get_uri (obj->priv->bookmarks_store, &iter); + + if (!uri) + return; + + file = g_file_new_for_uri (uri); + g_hash_table_remove (obj->priv->bookmarks_hash, file); + + g_object_unref (file); + g_free (uri); +} + +static void +on_filter_mode_changed (PlumaFileBrowserStore * model, + GParamSpec * param, + PlumaFileBrowserWidget * obj) +{ + gint mode; + GtkToggleAction * action; + gboolean active; + + mode = pluma_file_browser_store_get_filter_mode (model); + + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, + "FilterHidden")); + active = !(mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); + + if (active != gtk_toggle_action_get_active (action)) + gtk_toggle_action_set_active (action, active); + + action = GTK_TOGGLE_ACTION (gtk_action_group_get_action (obj->priv->action_group, + "FilterBinary")); + active = !(mode & PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); + + if (active != gtk_toggle_action_get_active (action)) + gtk_toggle_action_set_active (action, active); +} + +static void +on_action_directory_next (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_history_forward (obj); +} + +static void +on_action_directory_previous (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_history_back (obj); +} + +static void +on_action_directory_up (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + pluma_file_browser_store_set_virtual_root_up (PLUMA_FILE_BROWSER_STORE (model)); +} + +static void +on_action_directory_new (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter parent; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (!pluma_file_browser_widget_get_selected_directory (obj, &parent)) + return; + + if (pluma_file_browser_store_new_directory + (PLUMA_FILE_BROWSER_STORE (model), &parent, &iter)) { + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); + } +} + +static void +on_action_file_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GList *rows; + GList *row; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (gtk_tree_model_get_iter (model, &iter, path)) + file_open (obj, model, &iter); + + gtk_tree_path_free (path); + } + + g_list_free (rows); +} + +static void +on_action_file_new (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeIter parent; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + if (!pluma_file_browser_widget_get_selected_directory (obj, &parent)) + return; + + if (pluma_file_browser_store_new_file + (PLUMA_FILE_BROWSER_STORE (model), &parent, &iter)) { + pluma_file_browser_view_start_rename (obj->priv->treeview, + &iter); + } +} + +static void +on_action_file_rename (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + rename_selected_file (obj); +} + +static void +on_action_file_delete (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + delete_selected_files (obj, FALSE); +} + +static void +on_action_file_move_to_trash (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + delete_selected_files (obj, TRUE); +} + +static void +on_action_directory_refresh (GtkAction * action, + PlumaFileBrowserWidget * obj) +{ + pluma_file_browser_widget_refresh (obj); +} + +static void +on_action_directory_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GList *rows; + GList *row; + gboolean directory_opened = FALSE; + GtkTreeIter iter; + GtkTreePath *path; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BROWSER_STORE (model)) + return; + + rows = gtk_tree_selection_get_selected_rows (selection, &model); + + for (row = rows; row; row = row->next) { + path = (GtkTreePath *)(row->data); + + if (gtk_tree_model_get_iter (model, &iter, path)) + directory_opened |= directory_open (obj, model, &iter); + + gtk_tree_path_free (path); + } + + if (!directory_opened) { + if (pluma_file_browser_widget_get_selected_directory (obj, &iter)) + directory_open (obj, model, &iter); + } + + g_list_free (rows); +} + +static void +on_action_filter_hidden (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + update_filter_mode (obj, + action, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN); +} + +static void +on_action_filter_binary (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + update_filter_mode (obj, + action, + PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY); +} + +static void +on_action_bookmark_open (GtkAction * action, PlumaFileBrowserWidget * obj) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (obj->priv->treeview)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (obj->priv->treeview)); + + if (!PLUMA_IS_FILE_BOOKMARKS_STORE (model)) + return; + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + bookmark_open (obj, model, &iter); +} + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser-widget.h b/plugins/filebrowser/pluma-file-browser-widget.h new file mode 100755 index 00000000..4d7f43ef --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser-widget.h @@ -0,0 +1,121 @@ +/* + * pluma-file-browser-widget.h - Pluma plugin providing easy file access + * from the sidepanel + * + * Copyright (C) 2006 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_FILE_BROWSER_WIDGET_H__ +#define __PLUMA_FILE_BROWSER_WIDGET_H__ + +#include +#include "pluma-file-browser-store.h" +#include "pluma-file-bookmarks-store.h" +#include "pluma-file-browser-view.h" + +G_BEGIN_DECLS +#define PLUMA_TYPE_FILE_BROWSER_WIDGET (pluma_file_browser_widget_get_type ()) +#define PLUMA_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidget)) +#define PLUMA_FILE_BROWSER_WIDGET_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidget const)) +#define PLUMA_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidgetClass)) +#define PLUMA_IS_FILE_BROWSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET)) +#define PLUMA_IS_FILE_BROWSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_FILE_BROWSER_WIDGET)) +#define PLUMA_FILE_BROWSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_FILE_BROWSER_WIDGET, PlumaFileBrowserWidgetClass)) + +typedef struct _PlumaFileBrowserWidget PlumaFileBrowserWidget; +typedef struct _PlumaFileBrowserWidgetClass PlumaFileBrowserWidgetClass; +typedef struct _PlumaFileBrowserWidgetPrivate PlumaFileBrowserWidgetPrivate; + +typedef +gboolean (*PlumaFileBrowserWidgetFilterFunc) (PlumaFileBrowserWidget * obj, + PlumaFileBrowserStore * + model, GtkTreeIter * iter, + gpointer user_data); + +struct _PlumaFileBrowserWidget +{ + GtkVBox parent; + + PlumaFileBrowserWidgetPrivate *priv; +}; + +struct _PlumaFileBrowserWidgetClass +{ + GtkVBoxClass parent_class; + + /* Signals */ + void (*uri_activated) (PlumaFileBrowserWidget * widget, + gchar const *uri); + void (*error) (PlumaFileBrowserWidget * widget, + guint code, + gchar const *message); + gboolean (*confirm_delete) (PlumaFileBrowserWidget * widget, + PlumaFileBrowserStore * model, + GList *list); + gboolean (*confirm_no_trash) (PlumaFileBrowserWidget * widget, + GList *list); +}; + +GType pluma_file_browser_widget_get_type (void) G_GNUC_CONST; +GType pluma_file_browser_widget_register_type (GTypeModule * module); + +GtkWidget *pluma_file_browser_widget_new (const gchar *data_dir); + +void pluma_file_browser_widget_show_bookmarks (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_show_files (PlumaFileBrowserWidget * obj); + +void pluma_file_browser_widget_set_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gboolean virtual_root); +void +pluma_file_browser_widget_set_root_and_virtual_root (PlumaFileBrowserWidget * obj, + gchar const *root, + gchar const *virtual_root); + +gboolean +pluma_file_browser_widget_get_selected_directory (PlumaFileBrowserWidget * obj, + GtkTreeIter * iter); + +PlumaFileBrowserStore * +pluma_file_browser_widget_get_browser_store (PlumaFileBrowserWidget * obj); +PlumaFileBookmarksStore * +pluma_file_browser_widget_get_bookmarks_store (PlumaFileBrowserWidget * obj); +PlumaFileBrowserView * +pluma_file_browser_widget_get_browser_view (PlumaFileBrowserWidget * obj); +GtkWidget * +pluma_file_browser_widget_get_filter_entry (PlumaFileBrowserWidget * obj); + +GtkUIManager * +pluma_file_browser_widget_get_ui_manager (PlumaFileBrowserWidget * obj); + +gulong pluma_file_browser_widget_add_filter (PlumaFileBrowserWidget * obj, + PlumaFileBrowserWidgetFilterFunc func, + gpointer user_data, + GDestroyNotify notify); +void pluma_file_browser_widget_remove_filter (PlumaFileBrowserWidget * obj, + gulong id); +void pluma_file_browser_widget_set_filter_pattern (PlumaFileBrowserWidget * obj, + gchar const *pattern); + +void pluma_file_browser_widget_refresh (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_history_back (PlumaFileBrowserWidget * obj); +void pluma_file_browser_widget_history_forward (PlumaFileBrowserWidget * obj); + +G_END_DECLS +#endif /* __PLUMA_FILE_BROWSER_WIDGET_H__ */ + +// ex:ts=8:noet: diff --git a/plugins/filebrowser/pluma-file-browser.schemas.in b/plugins/filebrowser/pluma-file-browser.schemas.in new file mode 100755 index 00000000..0ae807d6 --- /dev/null +++ b/plugins/filebrowser/pluma-file-browser.schemas.in @@ -0,0 +1,97 @@ + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/tree_view + /apps/pluma-2/plugins/filebrowser/on_load/tree_view + pluma + bool + TRUE + + Open With Tree View + Open the tree view when the file browser plugin gets loaded instead of the bookmarks view + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/root + /apps/pluma-2/plugins/filebrowser/on_load/root + pluma + string + + + File Browser Root Directory + The file browser root directory to use when loading the file + browser plugin and onload/tree_view is TRUE. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/virtual_root + /apps/pluma-2/plugins/filebrowser/on_load/virtual_root + pluma + string + + + File Browser Virtual Root Directory + The file browser virtual root directory to use when loading the + file browser plugin when onload/tree_view is TRUE. The virtual root + must always be below the actual root. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/on_load/enable_remote + /apps/pluma-2/plugins/filebrowser/on_load/enable_remote + pluma + bool + FALSE + + Enable Restore of Remote Locations + Sets whether to enable restoring of remote locations. + + + + + /schemas/apps/pluma-2/plugins/filebrowser/open_at_first_doc + /apps/pluma-2/plugins/filebrowser/open_at_first_doc + pluma + bool + TRUE + + Set Location to First Document + If TRUE the file browser plugin will view the directory of + the first opened document given that the file browser hasn't been + used yet. (Thus this generally applies to opening a document from + the command line or opening it with Caja, etc.) + + + + + /schemas/apps/pluma-2/plugins/filebrowser/filter_mode + /apps/pluma-2/plugins/filebrowser/filter_mode + pluma + string + hidden_and_binary + + File Browser Filter Mode + This value determines what files get filtered from the file + browser. Valid values are: none (filter nothing), + hidden (filter hidden files), binary (filter binary files) and + hidden_and_binary (filter both hidden and binary files). + + + + + /schemas/apps/pluma-2/plugins/filebrowser/filter_pattern + /apps/pluma-2/plugins/filebrowser/filter_pattern + pluma + string + + + File Browser Filter Pattern + The filter pattern to filter the file browser with. This filter + works on top of the filter_mode. + + + + diff --git a/plugins/modelines/Makefile.am b/plugins/modelines/Makefile.am index ddcfccc8..d1b59b85 100755 --- a/plugins/modelines/Makefile.am +++ b/plugins/modelines/Makefile.am @@ -1,31 +1,31 @@ # Modelines Plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) -modelinesdir = $(GEDIT_PLUGINS_DATA_DIR)/modelines +modelinesdir = $(PLUMA_PLUGINS_DATA_DIR)/modelines modelines_DATA = \ language-mappings plugin_LTLIBRARIES = libmodelines.la libmodelines_la_SOURCES = \ - gedit-modeline-plugin.h \ - gedit-modeline-plugin.c \ + pluma-modeline-plugin.h \ + pluma-modeline-plugin.c \ modeline-parser.h \ modeline-parser.c libmodelines_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libmodelines_la_LIBADD = $(GEDIT_LIBS) +libmodelines_la_LIBADD = $(PLUMA_LIBS) -plugin_in_files = modelines.gedit-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = modelines.pluma-plugin.desktop.in +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = \ $(plugin_in_files) \ diff --git a/plugins/modelines/gedit-modeline-plugin.c b/plugins/modelines/gedit-modeline-plugin.c deleted file mode 100755 index 49fc2f69..00000000 --- a/plugins/modelines/gedit-modeline-plugin.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * gedit-modeline-plugin.c - * Emacs, Kate and Vim-style modelines support for gedit. - * - * Copyright (C) 2005-2007 - Steve Frécinaux - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "gedit-modeline-plugin.h" -#include "modeline-parser.h" - -#include -#include - -#define WINDOW_DATA_KEY "GeditModelinePluginWindowData" -#define DOCUMENT_DATA_KEY "GeditModelinePluginDocumentData" - -typedef struct -{ - gulong tab_added_handler_id; - gulong tab_removed_handler_id; -} WindowData; - -typedef struct -{ - gulong document_loaded_handler_id; - gulong document_saved_handler_id; -} DocumentData; - -static void gedit_modeline_plugin_activate (GeditPlugin *plugin, GeditWindow *window); -static void gedit_modeline_plugin_deactivate (GeditPlugin *plugin, GeditWindow *window); -static GObject *gedit_modeline_plugin_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_param); -static void gedit_modeline_plugin_finalize (GObject *object); - -GEDIT_PLUGIN_REGISTER_TYPE(GeditModelinePlugin, gedit_modeline_plugin) - -static void -window_data_free (WindowData *wdata) -{ - g_slice_free (WindowData, wdata); -} - -static void -document_data_free (DocumentData *ddata) -{ - g_slice_free (DocumentData, ddata); -} - -static void -gedit_modeline_plugin_class_init (GeditModelinePluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->constructor = gedit_modeline_plugin_constructor; - object_class->finalize = gedit_modeline_plugin_finalize; - - plugin_class->activate = gedit_modeline_plugin_activate; - plugin_class->deactivate = gedit_modeline_plugin_deactivate; -} - -static GObject * -gedit_modeline_plugin_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_param) -{ - GObject *object; - gchar *data_dir; - - object = G_OBJECT_CLASS (gedit_modeline_plugin_parent_class)->constructor (type, - n_construct_properties, - construct_param); - - data_dir = gedit_plugin_get_data_dir (GEDIT_PLUGIN (object)); - - modeline_parser_init (data_dir); - - g_free (data_dir); - - return object; -} - -static void -gedit_modeline_plugin_init (GeditModelinePlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditModelinePlugin initializing"); -} - -static void -gedit_modeline_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditModelinePlugin finalizing"); - - modeline_parser_shutdown (); - - G_OBJECT_CLASS (gedit_modeline_plugin_parent_class)->finalize (object); -} - -static void -on_document_loaded_or_saved (GeditDocument *document, - const GError *error, - GtkSourceView *view) -{ - modeline_parser_apply_modeline (view); -} - -static void -connect_handlers (GeditView *view) -{ - DocumentData *data; - GtkTextBuffer *doc; - - doc = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - data = g_slice_new (DocumentData); - - data->document_loaded_handler_id = - g_signal_connect (doc, "loaded", - G_CALLBACK (on_document_loaded_or_saved), - view); - data->document_saved_handler_id = - g_signal_connect (doc, "saved", - G_CALLBACK (on_document_loaded_or_saved), - view); - - g_object_set_data_full (G_OBJECT (doc), DOCUMENT_DATA_KEY, - data, (GDestroyNotify) document_data_free); -} - -static void -disconnect_handlers (GeditView *view) -{ - DocumentData *data; - GtkTextBuffer *doc; - - doc = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - data = g_object_steal_data (G_OBJECT (doc), DOCUMENT_DATA_KEY); - - if (data) - { - g_signal_handler_disconnect (doc, data->document_loaded_handler_id); - g_signal_handler_disconnect (doc, data->document_saved_handler_id); - - document_data_free (data); - } - else - { - g_warning ("Modeline handlers not found"); - } -} - -static void -on_window_tab_added (GeditWindow *window, - GeditTab *tab, - gpointer user_data) -{ - connect_handlers (gedit_tab_get_view (tab)); -} - -static void -on_window_tab_removed (GeditWindow *window, - GeditTab *tab, - gpointer user_data) -{ - disconnect_handlers (gedit_tab_get_view (tab)); -} - -static void -gedit_modeline_plugin_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *wdata; - GList *views; - GList *l; - - gedit_debug (DEBUG_PLUGINS); - - views = gedit_window_get_views (window); - for (l = views; l != NULL; l = l->next) - { - connect_handlers (GEDIT_VIEW (l->data)); - modeline_parser_apply_modeline (GTK_SOURCE_VIEW (l->data)); - } - g_list_free (views); - - wdata = g_slice_new (WindowData); - - wdata->tab_added_handler_id = - g_signal_connect (window, "tab-added", - G_CALLBACK (on_window_tab_added), NULL); - - wdata->tab_removed_handler_id = - g_signal_connect (window, "tab-removed", - G_CALLBACK (on_window_tab_removed), NULL); - - g_object_set_data_full (G_OBJECT (window), WINDOW_DATA_KEY, - wdata, (GDestroyNotify) window_data_free); -} - -static void -gedit_modeline_plugin_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *wdata; - GList *views; - GList *l; - - gedit_debug (DEBUG_PLUGINS); - - wdata = g_object_steal_data (G_OBJECT (window), WINDOW_DATA_KEY); - - g_signal_handler_disconnect (window, wdata->tab_added_handler_id); - g_signal_handler_disconnect (window, wdata->tab_removed_handler_id); - - window_data_free (wdata); - - views = gedit_window_get_views (window); - - for (l = views; l != NULL; l = l->next) - { - disconnect_handlers (GEDIT_VIEW (l->data)); - - modeline_parser_deactivate (GTK_SOURCE_VIEW (l->data)); - } - - g_list_free (views); -} - diff --git a/plugins/modelines/gedit-modeline-plugin.h b/plugins/modelines/gedit-modeline-plugin.h deleted file mode 100755 index 92b01e70..00000000 --- a/plugins/modelines/gedit-modeline-plugin.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * gedit-modeline-plugin.h - * Emacs, Kate and Vim-style modelines support for gedit. - * - * Copyright (C) 2005-2007 - Steve Frécinaux - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEDIT_MODELINE_PLUGIN_H__ -#define __GEDIT_MODELINE_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GEDIT_TYPE_MODELINE_PLUGIN (gedit_modeline_plugin_get_type ()) -#define GEDIT_MODELINE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_MODELINE_PLUGIN, GeditModelinePlugin)) -#define GEDIT_MODELINE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_MODELINE_PLUGIN, GeditModelinePluginClass)) -#define GEDIT_IS_MODELINE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_MODELINE_PLUGIN)) -#define GEDIT_IS_MODELINE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_MODELINE_PLUGIN)) -#define GEDIT_MODELINE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_MODELINE_PLUGIN, GeditModelinePluginClass)) - -/* Private structure type */ -typedef GeditPluginClass GeditModelinePluginClass; -typedef GeditPlugin GeditModelinePlugin; - -GType gedit_modeline_plugin_get_type (void) G_GNUC_CONST; - -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_MODELINE_PLUGIN_H__ */ diff --git a/plugins/modelines/modeline-parser.c b/plugins/modelines/modeline-parser.c index 6feafc55..23304e38 100755 --- a/plugins/modelines/modeline-parser.c +++ b/plugins/modelines/modeline-parser.c @@ -1,6 +1,6 @@ /* * modeline-parser.c - * Emacs, Kate and Vim-style modelines support for gedit. + * Emacs, Kate and Vim-style modelines support for pluma. * * Copyright (C) 2005-2007 - Steve Frécinaux * @@ -22,9 +22,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "modeline-parser.h" #define MODELINES_LANGUAGE_MAPPINGS_FILE "language-mappings" @@ -32,7 +32,7 @@ /* base dir to lookup configuration files */ static gchar *modelines_data_dir; -/* Mappings: language name -> Gedit language ID */ +/* Mappings: language name -> Pluma language ID */ static GHashTable *vim_languages; static GHashTable *emacs_languages; static GHashTable *kate_languages; @@ -112,7 +112,7 @@ load_language_mappings_group (GKeyFile *key_file, const gchar *group) keys = g_key_file_get_keys (key_file, group, &length, NULL); - gedit_debug_message (DEBUG_PLUGINS, + pluma_debug_message (DEBUG_PLUGINS, "%" G_GSIZE_FORMAT " mappings in group %s", length, group); @@ -143,7 +143,7 @@ load_language_mappings (void) if (g_key_file_load_from_file (mappings, fname, 0, &error)) { - gedit_debug_message (DEBUG_PLUGINS, + pluma_debug_message (DEBUG_PLUGINS, "Loaded language mappings from %s", fname); @@ -153,7 +153,7 @@ load_language_mappings (void) } else { - gedit_debug_message (DEBUG_PLUGINS, + pluma_debug_message (DEBUG_PLUGINS, "Failed to loaded language mappings from %s: %s", fname, error->message); @@ -395,7 +395,7 @@ parse_emacs_modeline (gchar *s, s++; } - gedit_debug_message (DEBUG_PLUGINS, + pluma_debug_message (DEBUG_PLUGINS, "Emacs modeline bit: %s = %s", key->str, value->str); @@ -493,7 +493,7 @@ parse_kate_modeline (gchar *s, s++; } - gedit_debug_message (DEBUG_PLUGINS, + pluma_debug_message (DEBUG_PLUGINS, "Kate modeline bit: %s = %s", key->str, value->str); @@ -582,21 +582,21 @@ parse_modeline (gchar *s, strncmp (s, "vi:", 3) == 0 || strncmp (s, "vim:", 4) == 0)) { - gedit_debug_message (DEBUG_PLUGINS, "Vim modeline on line %d", line_number); + pluma_debug_message (DEBUG_PLUGINS, "Vim modeline on line %d", line_number); while (*s != ':') s++; s = parse_vim_modeline (s + 1, options); } else if (line_number <= 2 && strncmp (s, "-*-", 3) == 0) { - gedit_debug_message (DEBUG_PLUGINS, "Emacs modeline on line %d", line_number); + pluma_debug_message (DEBUG_PLUGINS, "Emacs modeline on line %d", line_number); s = parse_emacs_modeline (s + 3, options); } else if ((line_number <= 10 || line_number > line_count - 10) && strncmp (s, "kate:", 5) == 0) { - gedit_debug_message (DEBUG_PLUGINS, "Kate modeline on line %d", line_number); + pluma_debug_message (DEBUG_PLUGINS, "Kate modeline on line %d", line_number); s = parse_kate_modeline (s + 5, options); } @@ -744,7 +744,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) GtkSourceLanguageManager *manager; GtkSourceLanguage *language; - manager = gedit_get_language_manager (); + manager = pluma_get_language_manager (); language = gtk_source_language_manager_get_language (manager, options.language_id); @@ -769,7 +769,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) { gtk_source_view_set_insert_spaces_instead_of_tabs (view, - gedit_prefs_manager_get_insert_spaces ()); + pluma_prefs_manager_get_insert_spaces ()); } if (has_option (&options, MODELINE_SET_TAB_WIDTH)) @@ -779,7 +779,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) else if (check_previous (view, previous, MODELINE_SET_TAB_WIDTH)) { gtk_source_view_set_tab_width (view, - gedit_prefs_manager_get_tabs_size ()); + pluma_prefs_manager_get_tabs_size ()); } if (has_option (&options, MODELINE_SET_INDENT_WIDTH)) @@ -798,7 +798,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) else if (check_previous (view, previous, MODELINE_SET_WRAP_MODE)) { gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), - gedit_prefs_manager_get_wrap_mode ()); + pluma_prefs_manager_get_wrap_mode ()); } if (has_option (&options, MODELINE_SET_RIGHT_MARGIN_POSITION)) @@ -808,7 +808,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) else if (check_previous (view, previous, MODELINE_SET_RIGHT_MARGIN_POSITION)) { gtk_source_view_set_right_margin_position (view, - gedit_prefs_manager_get_right_margin_position ()); + pluma_prefs_manager_get_right_margin_position ()); } if (has_option (&options, MODELINE_SET_SHOW_RIGHT_MARGIN)) @@ -818,7 +818,7 @@ modeline_parser_apply_modeline (GtkSourceView *view) else if (check_previous (view, previous, MODELINE_SET_SHOW_RIGHT_MARGIN)) { gtk_source_view_set_show_right_margin (view, - gedit_prefs_manager_get_display_right_margin ()); + pluma_prefs_manager_get_display_right_margin ()); } if (previous) diff --git a/plugins/modelines/modeline-parser.h b/plugins/modelines/modeline-parser.h index 2e8559e4..11e06c34 100755 --- a/plugins/modelines/modeline-parser.h +++ b/plugins/modelines/modeline-parser.h @@ -1,6 +1,6 @@ /* * modelie-parser.h - * Emacs, Kate and Vim-style modelines support for gedit. + * Emacs, Kate and Vim-style modelines support for pluma. * * Copyright (C) 2005-2007 - Steve Frécinaux * diff --git a/plugins/modelines/modelines.gedit-plugin.desktop.in b/plugins/modelines/modelines.gedit-plugin.desktop.in deleted file mode 100755 index c72f0199..00000000 --- a/plugins/modelines/modelines.gedit-plugin.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Gedit Plugin] -Module=modelines -IAge=2 -_Name=Modelines -_Description=Emacs, Kate and Vim-style modelines support for gedit. -Authors=Steve Frécinaux -Copyright=Copyright © 2005 Steve Frécinaux -Website=http://www.gedit.org diff --git a/plugins/modelines/modelines.pluma-plugin.desktop.in b/plugins/modelines/modelines.pluma-plugin.desktop.in new file mode 100755 index 00000000..0d5f8389 --- /dev/null +++ b/plugins/modelines/modelines.pluma-plugin.desktop.in @@ -0,0 +1,8 @@ +[Pluma Plugin] +Module=modelines +IAge=2 +_Name=Modelines +_Description=Emacs, Kate and Vim-style modelines support for pluma. +Authors=Steve Frécinaux +Copyright=Copyright © 2005 Steve Frécinaux +Website=http://www.pluma.org diff --git a/plugins/modelines/pluma-modeline-plugin.c b/plugins/modelines/pluma-modeline-plugin.c new file mode 100755 index 00000000..db5fc1e3 --- /dev/null +++ b/plugins/modelines/pluma-modeline-plugin.c @@ -0,0 +1,248 @@ +/* + * pluma-modeline-plugin.c + * Emacs, Kate and Vim-style modelines support for pluma. + * + * Copyright (C) 2005-2007 - Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include "pluma-modeline-plugin.h" +#include "modeline-parser.h" + +#include +#include + +#define WINDOW_DATA_KEY "PlumaModelinePluginWindowData" +#define DOCUMENT_DATA_KEY "PlumaModelinePluginDocumentData" + +typedef struct +{ + gulong tab_added_handler_id; + gulong tab_removed_handler_id; +} WindowData; + +typedef struct +{ + gulong document_loaded_handler_id; + gulong document_saved_handler_id; +} DocumentData; + +static void pluma_modeline_plugin_activate (PlumaPlugin *plugin, PlumaWindow *window); +static void pluma_modeline_plugin_deactivate (PlumaPlugin *plugin, PlumaWindow *window); +static GObject *pluma_modeline_plugin_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_param); +static void pluma_modeline_plugin_finalize (GObject *object); + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaModelinePlugin, pluma_modeline_plugin) + +static void +window_data_free (WindowData *wdata) +{ + g_slice_free (WindowData, wdata); +} + +static void +document_data_free (DocumentData *ddata) +{ + g_slice_free (DocumentData, ddata); +} + +static void +pluma_modeline_plugin_class_init (PlumaModelinePluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->constructor = pluma_modeline_plugin_constructor; + object_class->finalize = pluma_modeline_plugin_finalize; + + plugin_class->activate = pluma_modeline_plugin_activate; + plugin_class->deactivate = pluma_modeline_plugin_deactivate; +} + +static GObject * +pluma_modeline_plugin_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_param) +{ + GObject *object; + gchar *data_dir; + + object = G_OBJECT_CLASS (pluma_modeline_plugin_parent_class)->constructor (type, + n_construct_properties, + construct_param); + + data_dir = pluma_plugin_get_data_dir (PLUMA_PLUGIN (object)); + + modeline_parser_init (data_dir); + + g_free (data_dir); + + return object; +} + +static void +pluma_modeline_plugin_init (PlumaModelinePlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaModelinePlugin initializing"); +} + +static void +pluma_modeline_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaModelinePlugin finalizing"); + + modeline_parser_shutdown (); + + G_OBJECT_CLASS (pluma_modeline_plugin_parent_class)->finalize (object); +} + +static void +on_document_loaded_or_saved (PlumaDocument *document, + const GError *error, + GtkSourceView *view) +{ + modeline_parser_apply_modeline (view); +} + +static void +connect_handlers (PlumaView *view) +{ + DocumentData *data; + GtkTextBuffer *doc; + + doc = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + data = g_slice_new (DocumentData); + + data->document_loaded_handler_id = + g_signal_connect (doc, "loaded", + G_CALLBACK (on_document_loaded_or_saved), + view); + data->document_saved_handler_id = + g_signal_connect (doc, "saved", + G_CALLBACK (on_document_loaded_or_saved), + view); + + g_object_set_data_full (G_OBJECT (doc), DOCUMENT_DATA_KEY, + data, (GDestroyNotify) document_data_free); +} + +static void +disconnect_handlers (PlumaView *view) +{ + DocumentData *data; + GtkTextBuffer *doc; + + doc = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + data = g_object_steal_data (G_OBJECT (doc), DOCUMENT_DATA_KEY); + + if (data) + { + g_signal_handler_disconnect (doc, data->document_loaded_handler_id); + g_signal_handler_disconnect (doc, data->document_saved_handler_id); + + document_data_free (data); + } + else + { + g_warning ("Modeline handlers not found"); + } +} + +static void +on_window_tab_added (PlumaWindow *window, + PlumaTab *tab, + gpointer user_data) +{ + connect_handlers (pluma_tab_get_view (tab)); +} + +static void +on_window_tab_removed (PlumaWindow *window, + PlumaTab *tab, + gpointer user_data) +{ + disconnect_handlers (pluma_tab_get_view (tab)); +} + +static void +pluma_modeline_plugin_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *wdata; + GList *views; + GList *l; + + pluma_debug (DEBUG_PLUGINS); + + views = pluma_window_get_views (window); + for (l = views; l != NULL; l = l->next) + { + connect_handlers (PLUMA_VIEW (l->data)); + modeline_parser_apply_modeline (GTK_SOURCE_VIEW (l->data)); + } + g_list_free (views); + + wdata = g_slice_new (WindowData); + + wdata->tab_added_handler_id = + g_signal_connect (window, "tab-added", + G_CALLBACK (on_window_tab_added), NULL); + + wdata->tab_removed_handler_id = + g_signal_connect (window, "tab-removed", + G_CALLBACK (on_window_tab_removed), NULL); + + g_object_set_data_full (G_OBJECT (window), WINDOW_DATA_KEY, + wdata, (GDestroyNotify) window_data_free); +} + +static void +pluma_modeline_plugin_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *wdata; + GList *views; + GList *l; + + pluma_debug (DEBUG_PLUGINS); + + wdata = g_object_steal_data (G_OBJECT (window), WINDOW_DATA_KEY); + + g_signal_handler_disconnect (window, wdata->tab_added_handler_id); + g_signal_handler_disconnect (window, wdata->tab_removed_handler_id); + + window_data_free (wdata); + + views = pluma_window_get_views (window); + + for (l = views; l != NULL; l = l->next) + { + disconnect_handlers (PLUMA_VIEW (l->data)); + + modeline_parser_deactivate (GTK_SOURCE_VIEW (l->data)); + } + + g_list_free (views); +} + diff --git a/plugins/modelines/pluma-modeline-plugin.h b/plugins/modelines/pluma-modeline-plugin.h new file mode 100755 index 00000000..cdd77b20 --- /dev/null +++ b/plugins/modelines/pluma-modeline-plugin.h @@ -0,0 +1,48 @@ +/* + * pluma-modeline-plugin.h + * Emacs, Kate and Vim-style modelines support for pluma. + * + * Copyright (C) 2005-2007 - Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __PLUMA_MODELINE_PLUGIN_H__ +#define __PLUMA_MODELINE_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define PLUMA_TYPE_MODELINE_PLUGIN (pluma_modeline_plugin_get_type ()) +#define PLUMA_MODELINE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_MODELINE_PLUGIN, PlumaModelinePlugin)) +#define PLUMA_MODELINE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_MODELINE_PLUGIN, PlumaModelinePluginClass)) +#define PLUMA_IS_MODELINE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_MODELINE_PLUGIN)) +#define PLUMA_IS_MODELINE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_MODELINE_PLUGIN)) +#define PLUMA_MODELINE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_MODELINE_PLUGIN, PlumaModelinePluginClass)) + +/* Private structure type */ +typedef PlumaPluginClass PlumaModelinePluginClass; +typedef PlumaPlugin PlumaModelinePlugin; + +GType pluma_modeline_plugin_get_type (void) G_GNUC_CONST; + +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_MODELINE_PLUGIN_H__ */ diff --git a/plugins/pythonconsole/Makefile.am b/plugins/pythonconsole/Makefile.am index c27227f3..53361183 100755 --- a/plugins/pythonconsole/Makefile.am +++ b/plugins/pythonconsole/Makefile.am @@ -1,11 +1,11 @@ # Python Console Plugin SUBDIRS = pythonconsole -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -plugin_in_files = pythonconsole.gedit-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = pythonconsole.pluma-plugin.desktop.in +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(plugin_in_files) diff --git a/plugins/pythonconsole/pythonconsole.gedit-plugin.desktop.in b/plugins/pythonconsole/pythonconsole.gedit-plugin.desktop.in deleted file mode 100755 index 8cc65648..00000000 --- a/plugins/pythonconsole/pythonconsole.gedit-plugin.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Gedit Plugin] -Loader=python -Module=pythonconsole -IAge=2 -_Name=Python Console -_Description=Interactive Python console standing in the bottom panel -Icon=mate-mime-text-x-python -Authors=Steve Frécinaux -Copyright=Copyright © 2006 Steve Frécinaux -Website=http://www.gedit.org diff --git a/plugins/pythonconsole/pythonconsole.pluma-plugin.desktop.in b/plugins/pythonconsole/pythonconsole.pluma-plugin.desktop.in new file mode 100755 index 00000000..ca941412 --- /dev/null +++ b/plugins/pythonconsole/pythonconsole.pluma-plugin.desktop.in @@ -0,0 +1,10 @@ +[Pluma Plugin] +Loader=python +Module=pythonconsole +IAge=2 +_Name=Python Console +_Description=Interactive Python console standing in the bottom panel +Icon=mate-mime-text-x-python +Authors=Steve Frécinaux +Copyright=Copyright © 2006 Steve Frécinaux +Website=http://www.pluma.org diff --git a/plugins/pythonconsole/pythonconsole/Makefile.am b/plugins/pythonconsole/pythonconsole/Makefile.am index 7aa91fe9..05327ed6 100755 --- a/plugins/pythonconsole/pythonconsole/Makefile.am +++ b/plugins/pythonconsole/pythonconsole/Makefile.am @@ -1,12 +1,12 @@ # Python console plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR)/pythonconsole +plugindir = $(PLUMA_PLUGINS_LIBS_DIR)/pythonconsole plugin_PYTHON = \ __init__.py \ console.py \ config.py -uidir = $(GEDIT_PLUGINS_DATA_DIR)/pythonconsole/ui +uidir = $(PLUMA_PLUGINS_DATA_DIR)/pythonconsole/ui ui_DATA = config.ui EXTRA_DIST = $(ui_DATA) diff --git a/plugins/pythonconsole/pythonconsole/__init__.py b/plugins/pythonconsole/pythonconsole/__init__.py index 60f70e9f..699225f0 100755 --- a/plugins/pythonconsole/pythonconsole/__init__.py +++ b/plugins/pythonconsole/pythonconsole/__init__.py @@ -21,11 +21,11 @@ # Parts from "Interactive Python-GTK Console" (stolen from epiphany's console.py) # Copyright (C), 1998 James Henstridge # Copyright (C), 2005 Adam Hooper -# Bits from gedit Python Console Plugin +# Bits from pluma Python Console Plugin # Copyrignt (C), 2005 Raphaël Slinckx import gtk -import gedit +import pluma from console import PythonConsole from config import PythonConsoleConfigDialog @@ -33,14 +33,14 @@ from config import PythonConsoleConfig PYTHON_ICON = 'mate-mime-text-x-python' -class PythonConsolePlugin(gedit.Plugin): +class PythonConsolePlugin(pluma.Plugin): def __init__(self): - gedit.Plugin.__init__(self) + pluma.Plugin.__init__(self) self.dlg = None def activate(self, window): console = PythonConsole(namespace = {'__builtins__' : __builtins__, - 'gedit' : gedit, + 'pluma' : pluma, 'window' : window}) console.eval('print "You can access the main window through ' \ '\'window\' :\\n%s" % window', False) @@ -63,14 +63,14 @@ def create_configure_dialog(self): self.dlg = PythonConsoleConfigDialog(self.get_data_dir()) dialog = self.dlg.dialog() - window = gedit.app_get_default().get_active_window() + window = pluma.app_get_default().get_active_window() if window: dialog.set_transient_for(window) return dialog # Here we dynamically insert create_configure_dialog based on if configuration -# is enabled. This has to be done like this because gedit checks if a plugin +# is enabled. This has to be done like this because pluma checks if a plugin # is configurable solely on the fact that it has this member defined or not if PythonConsoleConfig.enabled(): PythonConsolePlugin.create_configure_dialog = create_configure_dialog diff --git a/plugins/pythonconsole/pythonconsole/config.py b/plugins/pythonconsole/pythonconsole/config.py index fed4699b..ac0e599c 100755 --- a/plugins/pythonconsole/pythonconsole/config.py +++ b/plugins/pythonconsole/pythonconsole/config.py @@ -21,7 +21,7 @@ # Parts from "Interactive Python-GTK Console" (stolen from epiphany's console.py) # Copyright (C), 1998 James Henstridge # Copyright (C), 2005 Adam Hooper -# Bits from gedit Python Console Plugin +# Bits from pluma Python Console Plugin # Copyrignt (C), 2005 Raphaël Slinckx import os @@ -29,7 +29,7 @@ import gtk __all__ = ('PythonConsoleConfig', 'PythonConsoleConfigDialog') -MATECONF_KEY_BASE = '/apps/gedit-2/plugins/pythonconsole' +MATECONF_KEY_BASE = '/apps/pluma-2/plugins/pythonconsole' MATECONF_KEY_COMMAND_COLOR = MATECONF_KEY_BASE + '/command-color' MATECONF_KEY_ERROR_COLOR = MATECONF_KEY_BASE + '/error-color' diff --git a/plugins/pythonconsole/pythonconsole/console.py b/plugins/pythonconsole/pythonconsole/console.py index e9d7a331..5e818727 100755 --- a/plugins/pythonconsole/pythonconsole/console.py +++ b/plugins/pythonconsole/pythonconsole/console.py @@ -21,7 +21,7 @@ # Parts from "Interactive Python-GTK Console" (stolen from epiphany's console.py) # Copyright (C), 1998 James Henstridge # Copyright (C), 2005 Adam Hooper -# Bits from gedit Python Console Plugin +# Bits from pluma Python Console Plugin # Copyrignt (C), 2005 Raphaël Slinckx import string diff --git a/plugins/quickopen/Makefile.am b/plugins/quickopen/Makefile.am index 4b5faf00..74cc89a0 100755 --- a/plugins/quickopen/Makefile.am +++ b/plugins/quickopen/Makefile.am @@ -1,11 +1,11 @@ # Quick Open Plugin SUBDIRS = quickopen -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -plugin_in_files = quickopen.gedit-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = quickopen.pluma-plugin.desktop.in +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(plugin_in_files) diff --git a/plugins/quickopen/quickopen.gedit-plugin.desktop.in b/plugins/quickopen/quickopen.gedit-plugin.desktop.in deleted file mode 100755 index 40f7f040..00000000 --- a/plugins/quickopen/quickopen.gedit-plugin.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Gedit Plugin] -Loader=python -Module=quickopen -IAge=2 -_Name=Quick Open -_Description=Quickly open files -Icon=gtk-open -Authors=Jesse van den Kieboom -Copyright=Copyright © 2009 Jesse van den Kieboom -Website=http://www.gedit.org diff --git a/plugins/quickopen/quickopen.pluma-plugin.desktop.in b/plugins/quickopen/quickopen.pluma-plugin.desktop.in new file mode 100755 index 00000000..8f0f4b98 --- /dev/null +++ b/plugins/quickopen/quickopen.pluma-plugin.desktop.in @@ -0,0 +1,10 @@ +[Pluma Plugin] +Loader=python +Module=quickopen +IAge=2 +_Name=Quick Open +_Description=Quickly open files +Icon=gtk-open +Authors=Jesse van den Kieboom +Copyright=Copyright © 2009 Jesse van den Kieboom +Website=http://www.pluma.org diff --git a/plugins/quickopen/quickopen/Makefile.am b/plugins/quickopen/quickopen/Makefile.am index 88882fdf..7d4fa069 100755 --- a/plugins/quickopen/quickopen/Makefile.am +++ b/plugins/quickopen/quickopen/Makefile.am @@ -1,6 +1,6 @@ # Quick Open Plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR)/quickopen +plugindir = $(PLUMA_PLUGINS_LIBS_DIR)/quickopen plugin_PYTHON = \ __init__.py \ popup.py \ diff --git a/plugins/quickopen/quickopen/__init__.py b/plugins/quickopen/quickopen/__init__.py index a41c9400..75623a37 100755 --- a/plugins/quickopen/quickopen/__init__.py +++ b/plugins/quickopen/quickopen/__init__.py @@ -17,12 +17,12 @@ # Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307, USA. -import gedit +import pluma from windowhelper import WindowHelper -class QuickOpenPlugin(gedit.Plugin): +class QuickOpenPlugin(pluma.Plugin): def __init__(self): - gedit.Plugin.__init__(self) + pluma.Plugin.__init__(self) self._popup_size = (450, 300) self._helpers = {} diff --git a/plugins/quickopen/quickopen/popup.py b/plugins/quickopen/quickopen/popup.py index a80caf31..5aa83725 100755 --- a/plugins/quickopen/quickopen/popup.py +++ b/plugins/quickopen/quickopen/popup.py @@ -25,7 +25,7 @@ import gio import pango import glib import fnmatch -import gedit +import pluma import xml.sax.saxutils from virtualdirs import VirtualDirectory @@ -418,7 +418,7 @@ class Popup(gtk.Dialog): uri = self._entry.get_text() gfile = None - if gedit.utils.uri_is_valid(uri): + if pluma.utils.uri_is_valid(uri): gfile = gio.File(uri) elif os.path.isabs(uri): f = gio.File(uri) diff --git a/plugins/quickopen/quickopen/virtualdirs.py b/plugins/quickopen/quickopen/virtualdirs.py index ef0b8dc4..13c5c3a3 100755 --- a/plugins/quickopen/quickopen/virtualdirs.py +++ b/plugins/quickopen/quickopen/virtualdirs.py @@ -65,7 +65,7 @@ class RecentDocumentsDirectory(VirtualDirectory): added = 0 for item in items: - if item.has_group('gedit'): + if item.has_group('pluma'): self.append(gio.File(item.get_uri())) added += 1 diff --git a/plugins/quickopen/quickopen/windowhelper.py b/plugins/quickopen/quickopen/windowhelper.py index 70ea26f0..0d87550e 100755 --- a/plugins/quickopen/quickopen/windowhelper.py +++ b/plugins/quickopen/quickopen/windowhelper.py @@ -17,11 +17,11 @@ # Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307, USA. -import gedit +import pluma import gtk from popup import Popup import os -import gedit.commands +import pluma.commands import gio import glib from virtualdirs import RecentDocumentsDirectory @@ -64,7 +64,7 @@ class WindowHelper: def _install_menu(self): manager = self._window.get_ui_manager() - self._action_group = gtk.ActionGroup("GeditQuickOpenPluginActions") + self._action_group = gtk.ActionGroup("PlumaQuickOpenPluginActions") self._action_group.add_actions([ ("QuickOpen", gtk.STOCK_OPEN, _("Quick open"), 'O', _("Quickly open documents"), @@ -88,7 +88,7 @@ class WindowHelper: paths.append(gfile.get_parent()) # File browser root directory - if gedit.version[0] > 2 or (gedit.version[0] == 2 and (gedit.version[1] > 26 or (gedit.version[1] == 26 and gedit.version[2] >= 2))): + if pluma.version[0] > 2 or (pluma.version[0] == 2 and (pluma.version[1] > 26 or (pluma.version[1] == 26 and pluma.version[2] >= 2))): bus = self._window.get_message_bus() try: @@ -192,7 +192,7 @@ class WindowHelper: self._popup = None def on_activated(self, gfile): - gedit.commands.load_uri(self._window, gfile.get_uri(), None, -1) + pluma.commands.load_uri(self._window, gfile.get_uri(), None, -1) return True # ex:ts=8:et: diff --git a/plugins/snippets/Makefile.am b/plugins/snippets/Makefile.am index 06f0009b..7d536d25 100755 --- a/plugins/snippets/Makefile.am +++ b/plugins/snippets/Makefile.am @@ -1,11 +1,11 @@ # Python snippets plugin SUBDIRS = snippets data -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -plugin_in_files = snippets.gedit-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +plugin_in_files = snippets.pluma-plugin.desktop.in +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(plugin_in_files) diff --git a/plugins/snippets/data/Makefile.am b/plugins/snippets/data/Makefile.am index 8ec40419..0859f602 100755 --- a/plugins/snippets/data/Makefile.am +++ b/plugins/snippets/data/Makefile.am @@ -26,7 +26,7 @@ snippets_DATA = \ xml.xml \ xslt.xml -snippetsdir = $(GEDIT_PLUGINS_DATA_DIR)/snippets +snippetsdir = $(PLUMA_PLUGINS_DATA_DIR)/snippets EXTRA_DIST = $(snippets_DATA) diff --git a/plugins/snippets/data/c.xml b/plugins/snippets/data/c.xml index 61171cb8..60188bd3 100755 --- a/plugins/snippets/data/c.xml +++ b/plugins/snippets/data/c.xml @@ -2,7 +2,7 @@ ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: @@ -34,7 +34,7 @@ $0]]> ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: diff --git a/plugins/snippets/data/chdr.xml b/plugins/snippets/data/chdr.xml index f71ea901..b88f2274 100755 --- a/plugins/snippets/data/chdr.xml +++ b/plugins/snippets/data/chdr.xml @@ -34,7 +34,7 @@ $0]]> ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: @@ -66,7 +66,7 @@ $0]]> ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: diff --git a/plugins/snippets/data/cpp.xml b/plugins/snippets/data/cpp.xml index 7c7ccabd..e514a3e3 100755 --- a/plugins/snippets/data/cpp.xml +++ b/plugins/snippets/data/cpp.xml @@ -105,7 +105,7 @@ $0]]> ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: @@ -137,7 +137,7 @@ except KeyError: ]} + * ${1:[$PLUMA_CURRENT_DOCUMENT_NAME,]} * This file is part of ${2:} * * Copyright (C) $<3: import datetime; return str(datetime.date.today().year)> - $<4: diff --git a/plugins/snippets/data/docbook.xml b/plugins/snippets/data/docbook.xml index 3159b603..8a96a059 100755 --- a/plugins/snippets/data/docbook.xml +++ b/plugins/snippets/data/docbook.xml @@ -34,13 +34,13 @@ - $GEDIT_SELECTED_TEXT]]> + $PLUMA_SELECTED_TEXT]]> application application tag - $GEDIT_SELECTED_TEXT]]> + $PLUMA_SELECTED_TEXT]]> enclose enclose selected text diff --git a/plugins/snippets/data/html.xml b/plugins/snippets/data/html.xml index d294f934..3c35e599 100755 --- a/plugins/snippets/data/html.xml +++ b/plugins/snippets/data/html.xml @@ -54,14 +54,14 @@ $0]]> Date - ${2:$GEDIT_SELECTED_TEXT} + ${2:$PLUMA_SELECTED_TEXT} ]]> l]]> Wrap Selection as Link ref - $GEDIT_SELECTED_TEXT]]> + $PLUMA_SELECTED_TEXT]]> w]]> Wrap Selection in Open/Close Tag @@ -96,7 +96,7 @@ $0]]> - ${0:$GEDIT_SELECTED_TEXT} + ${0:$PLUMA_SELECTED_TEXT} ]]> Div div @@ -117,7 +117,7 @@ $0]]> form - ${3:$GEDIT_SELECTED_TEXT} + ${3:$PLUMA_SELECTED_TEXT} $0]]> Heading h diff --git a/plugins/snippets/data/java.xml b/plugins/snippets/data/java.xml index 043a5dd3..fce31859 100755 --- a/plugins/snippets/data/java.xml +++ b/plugins/snippets/data/java.xml @@ -69,7 +69,7 @@ $0 - + w]]> Wrap Selection in Command diff --git a/plugins/snippets/data/python.xml b/plugins/snippets/data/python.xml index a25617b8..3829c3a0 100755 --- a/plugins/snippets/data/python.xml +++ b/plugins/snippets/data/python.xml @@ -74,12 +74,12 @@ $0]]> while loop - + 2]]> Inside String: Insert "…" - + apostrophe]]> Inside String: Insert '…' diff --git a/plugins/snippets/data/snippets.xml b/plugins/snippets/data/snippets.xml index ee405e6d..2718461b 100755 --- a/plugins/snippets/data/snippets.xml +++ b/plugins/snippets/data/snippets.xml @@ -26,73 +26,73 @@ regex - - Gedit Current Document Path Variable + + Pluma Current Document Path Variable $ - - Gedit Current Document Name Variable + + Pluma Current Document Name Variable $ - - Gedit Current Document Uri Variable + + Pluma Current Document Uri Variable $ - - Gedit Current Document Scheme Variable + + Pluma Current Document Scheme Variable $ - - Gedit Current Document Type Variable + + Pluma Current Document Type Variable $ - - Gedit Documents Uri Variable + + Pluma Documents Uri Variable $ - - Gedit Documents Path Variable + + Pluma Documents Path Variable $ - - Gedit Selected Text Variable + + Pluma Selected Text Variable $ - - Gedit Current Word Variable + + Pluma Current Word Variable $ - - Gedit Current Line Variable + + Pluma Current Line Variable $ - - Gedit Current Line Number Variable + + Pluma Current Line Number Variable $ - - Gedit Drop Filename Variable + + Pluma Drop Filename Variable $ - - Gedit Drop Relative Filename Variable + + Pluma Drop Relative Filename Variable $ - - Gedit Drop Mime Type Variable + + Pluma Drop Mime Type Variable $ diff --git a/plugins/snippets/data/xslt.xml b/plugins/snippets/data/xslt.xml index 0ff5cc15..9a470b18 100755 --- a/plugins/snippets/data/xslt.xml +++ b/plugins/snippets/data/xslt.xml @@ -103,13 +103,13 @@ $0]]> attr - ${1:$GEDIT_SELECTED_TEXT} + ${1:$PLUMA_SELECTED_TEXT} ]]> Text text - ${1:$GEDIT_SELECTED_TEXT} + ${1:$PLUMA_SELECTED_TEXT} ]]> Comment comment diff --git a/plugins/snippets/snippets.gedit-plugin.desktop.in b/plugins/snippets/snippets.gedit-plugin.desktop.in deleted file mode 100755 index dc3c8281..00000000 --- a/plugins/snippets/snippets.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Loader=python -Module=snippets -IAge=2 -_Name=Snippets -_Description=Insert often-used pieces of text in a fast way -Authors=Jesse van den Kieboom -Copyright=Copyright © 2005 Jesse van den Kieboom -Website=http://www.gedit.org diff --git a/plugins/snippets/snippets.pluma-plugin.desktop.in b/plugins/snippets/snippets.pluma-plugin.desktop.in new file mode 100755 index 00000000..4813fe7d --- /dev/null +++ b/plugins/snippets/snippets.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Loader=python +Module=snippets +IAge=2 +_Name=Snippets +_Description=Insert often-used pieces of text in a fast way +Authors=Jesse van den Kieboom +Copyright=Copyright © 2005 Jesse van den Kieboom +Website=http://www.pluma.org diff --git a/plugins/snippets/snippets/Completion.py b/plugins/snippets/snippets/Completion.py index d83915a5..4f24150c 100755 --- a/plugins/snippets/snippets/Completion.py +++ b/plugins/snippets/snippets/Completion.py @@ -1,6 +1,6 @@ import gtksourceview2 as gsv import gobject -import gedit +import pluma import gtk from Library import Library @@ -102,7 +102,7 @@ class Provider(gobject.GObject, gsv.CompletionProvider): def do_get_info_widget(self, proposal): if not self.info_widget: - view = gedit.View(gedit.Document()) + view = pluma.View(pluma.Document()) manager = get_language_manager() lang = manager.get_language('snippets') diff --git a/plugins/snippets/snippets/Document.py b/plugins/snippets/snippets/Document.py index da166668..368e0f5c 100755 --- a/plugins/snippets/snippets/Document.py +++ b/plugins/snippets/snippets/Document.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ import re import gtk from gtk import gdk import gio -import gedit +import pluma import gtksourceview2 as gsv import gobject @@ -433,7 +433,7 @@ class Document: def env_get_documents_uri(self, buf): toplevel = self.view.get_toplevel() - if isinstance(toplevel, gedit.Window): + if isinstance(toplevel, pluma.Window): documents_uri = [doc.get_location().get_uri() for doc in toplevel.get_documents() if doc.get_location() is not None] @@ -445,14 +445,14 @@ class Document: def env_get_documents_path(self, buf): toplevel = self.view.get_toplevel() - if isinstance(toplevel, gedit.Window): + if isinstance(toplevel, pluma.Window): documents_location = [doc.get_location() for doc in toplevel.get_documents() if doc.get_location() is not None] documents_path = [location.get_path() for location in documents_location - if gedit.utils.uri_has_file_scheme(location.get_uri())] + if pluma.utils.uri_has_file_scheme(location.get_uri())] else: documents_path = [] @@ -461,25 +461,25 @@ class Document: def update_environment(self): buf = self.view.get_buffer() - variables = {'GEDIT_SELECTED_TEXT': self.env_get_selected_text, - 'GEDIT_CURRENT_WORD': self.env_get_current_word, - 'GEDIT_CURRENT_LINE': self.env_get_current_line, - 'GEDIT_CURRENT_LINE_NUMBER': self.env_get_current_line_number, - 'GEDIT_CURRENT_DOCUMENT_URI': self.env_get_document_uri, - 'GEDIT_CURRENT_DOCUMENT_NAME': self.env_get_document_name, - 'GEDIT_CURRENT_DOCUMENT_SCHEME': self.env_get_document_scheme, - 'GEDIT_CURRENT_DOCUMENT_PATH': self.env_get_document_path, - 'GEDIT_CURRENT_DOCUMENT_DIR': self.env_get_document_dir, - 'GEDIT_CURRENT_DOCUMENT_TYPE': self.env_get_document_type, - 'GEDIT_DOCUMENTS_URI': self.env_get_documents_uri, - 'GEDIT_DOCUMENTS_PATH': self.env_get_documents_path, + variables = {'PLUMA_SELECTED_TEXT': self.env_get_selected_text, + 'PLUMA_CURRENT_WORD': self.env_get_current_word, + 'PLUMA_CURRENT_LINE': self.env_get_current_line, + 'PLUMA_CURRENT_LINE_NUMBER': self.env_get_current_line_number, + 'PLUMA_CURRENT_DOCUMENT_URI': self.env_get_document_uri, + 'PLUMA_CURRENT_DOCUMENT_NAME': self.env_get_document_name, + 'PLUMA_CURRENT_DOCUMENT_SCHEME': self.env_get_document_scheme, + 'PLUMA_CURRENT_DOCUMENT_PATH': self.env_get_document_path, + 'PLUMA_CURRENT_DOCUMENT_DIR': self.env_get_document_dir, + 'PLUMA_CURRENT_DOCUMENT_TYPE': self.env_get_document_type, + 'PLUMA_DOCUMENTS_URI': self.env_get_documents_uri, + 'PLUMA_DOCUMENTS_PATH': self.env_get_documents_path, } for var in variables: os.environ[var] = variables[var](buf) def uses_current_word(self, snippet): - matches = re.findall('(\\\\*)\\$GEDIT_CURRENT_WORD', snippet['text']) + matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_WORD', snippet['text']) for match in matches: if len(match) % 2 == 0: @@ -488,7 +488,7 @@ class Document: return False def uses_current_line(self, snippet): - matches = re.findall('(\\\\*)\\$GEDIT_CURRENT_LINE', snippet['text']) + matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_LINE', snippet['text']) for match in matches: if len(match) % 2 == 0: @@ -865,19 +865,19 @@ class Document: dirname = '' ruri = '' - if gedit.utils.uri_has_file_scheme(uri): + if pluma.utils.uri_has_file_scheme(uri): pathname = gfile.get_path() dirname = gfile.get_parent().get_path() name = os.path.basename(uri) scheme = gfile.get_uri_scheme() - os.environ['GEDIT_DROP_DOCUMENT_URI'] = uri - os.environ['GEDIT_DROP_DOCUMENT_NAME'] = name - os.environ['GEDIT_DROP_DOCUMENT_SCHEME'] = scheme - os.environ['GEDIT_DROP_DOCUMENT_PATH'] = pathname - os.environ['GEDIT_DROP_DOCUMENT_DIR'] = dirname - os.environ['GEDIT_DROP_DOCUMENT_TYPE'] = mime + os.environ['PLUMA_DROP_DOCUMENT_URI'] = uri + os.environ['PLUMA_DROP_DOCUMENT_NAME'] = name + os.environ['PLUMA_DROP_DOCUMENT_SCHEME'] = scheme + os.environ['PLUMA_DROP_DOCUMENT_PATH'] = pathname + os.environ['PLUMA_DROP_DOCUMENT_DIR'] = dirname + os.environ['PLUMA_DROP_DOCUMENT_TYPE'] = mime buf = self.view.get_buffer() location = buf.get_location() @@ -886,7 +886,7 @@ class Document: relpath = self.relative_path(ruri, uri, mime) - os.environ['GEDIT_DROP_DOCUMENT_RELATIVE_PATH'] = relpath + os.environ['PLUMA_DROP_DOCUMENT_RELATIVE_PATH'] = relpath mark = buf.get_mark('gtk_drag_target') diff --git a/plugins/snippets/snippets/Helper.py b/plugins/snippets/snippets/Helper.py index de363360..60ae1c79 100755 --- a/plugins/snippets/snippets/Helper.py +++ b/plugins/snippets/snippets/Helper.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -62,7 +62,7 @@ def insert_with_indent(view, piter, text, indentfirst = True, context = None): text = spaces_instead_of_tabs(view, text) lines = text.split('\n') - view.get_buffer().set_data('GeditSnippetsPluginContext', context) + view.get_buffer().set_data('PlumaSnippetsPluginContext', context) if len(lines) == 1: view.get_buffer().insert(piter, text) @@ -79,10 +79,10 @@ def insert_with_indent(view, piter, text, indentfirst = True, context = None): view.get_buffer().insert(piter, text[:-1]) - view.get_buffer().set_data('GeditSnippetsPluginContext', None) + view.get_buffer().set_data('PlumaSnippetsPluginContext', None) def get_buffer_context(buf): - return buf.get_data('GeditSnippetsPluginContext') + return buf.get_data('PlumaSnippetsPluginContext') def snippets_debug(*s): return diff --git a/plugins/snippets/snippets/Library.py b/plugins/snippets/snippets/Library.py index 4717280c..792f0f7e 100755 --- a/plugins/snippets/snippets/Library.py +++ b/plugins/snippets/snippets/Library.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify diff --git a/plugins/snippets/snippets/Makefile.am b/plugins/snippets/snippets/Makefile.am index 7a05b562..086b5968 100755 --- a/plugins/snippets/snippets/Makefile.am +++ b/plugins/snippets/snippets/Makefile.am @@ -1,5 +1,5 @@ # Python snippets plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR)/snippets +plugindir = $(PLUMA_PLUGINS_LIBS_DIR)/snippets plugin_PYTHON = \ __init__.py \ @@ -17,7 +17,7 @@ plugin_PYTHON = \ LanguageManager.py \ Completion.py -uidir = $(GEDIT_PLUGINS_DATA_DIR)/snippets/ui +uidir = $(PLUMA_PLUGINS_DATA_DIR)/snippets/ui ui_DATA = snippets.ui EXTRA_DIST = $(ui_DATA) diff --git a/plugins/snippets/snippets/Manager.py b/plugins/snippets/snippets/Manager.py index 16acbdb4..96220c6e 100755 --- a/plugins/snippets/snippets/Manager.py +++ b/plugins/snippets/snippets/Manager.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -24,7 +24,7 @@ import gtk from gtk import gdk import gtksourceview2 as gsv import pango -import gedit +import pluma import gio from Snippet import Snippet @@ -95,7 +95,7 @@ class Manager: self.tree_view.expand_row(path, False) def build_model(self, force_reload = False): - window = gedit.app_get_default().get_active_window() + window = pluma.app_get_default().get_active_window() if window: view = window.get_active_view() @@ -116,7 +116,7 @@ class Manager: self.model = gtk.TreeStore(str, str, object) self.model.set_sort_column_id(self.SORT_COLUMN, gtk.SORT_ASCENDING) manager = get_language_manager() - langs = gedit.language_manager_list_languages_sorted(manager, True) + langs = pluma.language_manager_list_languages_sorted(manager, True) piter = self.model.append(None, (_('Global'), '', None)) # Add dummy node @@ -618,7 +618,7 @@ class Manager: def on_dialog_snippets_response(self, dlg, resp): if resp == gtk.RESPONSE_HELP: - gedit.help_display(self.dlg, 'gedit', 'gedit-snippets-plugin') + pluma.help_display(self.dlg, 'pluma', 'pluma-snippets-plugin') return self.dlg.destroy() @@ -765,7 +765,7 @@ class Manager: success = True for filename in filenames: - if not gedit.utils.uri_has_file_scheme(filename): + if not pluma.utils.uri_has_file_scheme(filename): continue # Remove file:// diff --git a/plugins/snippets/snippets/Parser.py b/plugins/snippets/snippets/Parser.py index 3bbaf6e7..0c638df7 100755 --- a/plugins/snippets/snippets/Parser.py +++ b/plugins/snippets/snippets/Parser.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2006-2007 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify diff --git a/plugins/snippets/snippets/Placeholder.py b/plugins/snippets/snippets/Placeholder.py index c43eecac..45b5b508 100755 --- a/plugins/snippets/snippets/Placeholder.py +++ b/plugins/snippets/snippets/Placeholder.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -524,7 +524,7 @@ class PlaceholderEval(PlaceholderExpand): # SIGALRM is not supported on all platforms (e.g. windows). Timeout # with SIGALRM will not be used on those platforms. This will - # potentially block gedit if you have a placeholder which gets stuck, + # potentially block pluma if you have a placeholder which gets stuck, # but it's better than not supporting them at all. At some point we # might have proper thread support and we can fix this in a better way def timeout_supported(self): @@ -577,9 +577,9 @@ class PlaceholderEval(PlaceholderExpand): if 'process_snippet' in self.namespace: try: # Install a sigalarm signal. This is a HACK to make sure - # gedit doesn't get freezed by someone creating a python + # pluma doesn't get freezed by someone creating a python # placeholder which for instance loops indefinately. Since - # the code is executed synchronously it will hang gedit. With + # the code is executed synchronously it will hang pluma. With # the alarm signal we raise an exception and catch this # (see below). We show an error message and return False. # ___this is a HACK___ and should be fixed properly (I just diff --git a/plugins/snippets/snippets/Snippet.py b/plugins/snippets/snippets/Snippet.py index d7baead5..ae81fcfc 100755 --- a/plugins/snippets/snippets/Snippet.py +++ b/plugins/snippets/snippets/Snippet.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify diff --git a/plugins/snippets/snippets/SubstitutionParser.py b/plugins/snippets/snippets/SubstitutionParser.py index 6522222b..a41f5a6a 100755 --- a/plugins/snippets/snippets/SubstitutionParser.py +++ b/plugins/snippets/snippets/SubstitutionParser.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2006-2007 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify diff --git a/plugins/snippets/snippets/WindowHelper.py b/plugins/snippets/snippets/WindowHelper.py index 29bf3a58..a5f238ae 100755 --- a/plugins/snippets/snippets/WindowHelper.py +++ b/plugins/snippets/snippets/WindowHelper.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ import gettext import gtk from gtk import gdk -import gedit +import pluma from Document import Document from Library import Library @@ -46,7 +46,7 @@ class WindowHelper: # Add controllers to all the current views for view in self.window.get_views(): - if isinstance(view, gedit.View) and not self.has_controller(view): + if isinstance(view, pluma.View) and not self.has_controller(view): view._snippet_controller = Document(self, view) self.update() @@ -61,7 +61,7 @@ class WindowHelper: # Iterate over all the tabs and remove every controller for view in self.window.get_views(): - if isinstance(view, gedit.View) and self.has_controller(view): + if isinstance(view, pluma.View) and self.has_controller(view): view._snippet_controller.stop() view._snippet_controller = None @@ -72,8 +72,8 @@ class WindowHelper: bus = self.window.get_message_bus() self.messages = { - 'activate': bus.register('/plugins/snippets', 'activate', ('view', 'iter'), trigger=str, view=gedit.View, iter=gtk.TextIter), - 'parse-and-activate': bus.register('/plugins/snippets', 'parse-and-activate', ('view', 'iter'), snippet=str, view=gedit.View, iter=gtk.TextIter) + 'activate': bus.register('/plugins/snippets', 'activate', ('view', 'iter'), trigger=str, view=pluma.View, iter=gtk.TextIter), + 'parse-and-activate': bus.register('/plugins/snippets', 'parse-and-activate', ('view', 'iter'), snippet=str, view=pluma.View, iter=gtk.TextIter) } bus.connect('/plugins/snippets', 'activate', self.on_message_activate) @@ -124,8 +124,8 @@ class WindowHelper: def insert_menu(self): manager = self.window.get_ui_manager() - self.action_group = gtk.ActionGroup("GeditSnippetPluginActions") - self.action_group.set_translation_domain('gedit') + self.action_group = gtk.ActionGroup("PlumaSnippetPluginActions") + self.action_group.set_translation_domain('pluma') self.action_group.add_actions([('ManageSnippets', None, _('Manage _Snippets...'), \ None, _('Manage snippets'), \ @@ -192,10 +192,10 @@ class WindowHelper: # Callbacks def on_tab_added(self, window, tab): - # Create a new controller for this tab if it has a standard gedit view + # Create a new controller for this tab if it has a standard pluma view view = tab.get_view() - if isinstance(view, gedit.View) and not self.has_controller(view): + if isinstance(view, pluma.View) and not self.has_controller(view): view._snippet_controller = Document(self, view) self.update() diff --git a/plugins/snippets/snippets/__init__.py b/plugins/snippets/snippets/__init__.py index b21da508..609e3c0c 100755 --- a/plugins/snippets/snippets/__init__.py +++ b/plugins/snippets/snippets/__init__.py @@ -1,4 +1,4 @@ -# Gedit snippets plugin +# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ import shutil import gtk from gtk import gdk -import gedit +import pluma import platform from WindowHelper import WindowHelper @@ -29,9 +29,9 @@ from Library import Library from Manager import Manager from Snippet import Snippet -class SnippetsPlugin(gedit.Plugin): +class SnippetsPlugin(pluma.Plugin): def __init__(self): - gedit.Plugin.__init__(self) + pluma.Plugin.__init__(self) self.dlg = None @@ -39,13 +39,13 @@ class SnippetsPlugin(gedit.Plugin): library.set_accelerator_callback(self.accelerator_activated) if platform.platform() == 'Windows': - snippetsdir = os.path.expanduser('~/gedit/snippets') + snippetsdir = os.path.expanduser('~/pluma/snippets') else: userdir = os.getenv('MATE22_USER_DIR') if userdir: - snippetsdir = os.path.join(userdir, 'gedit/snippets') + snippetsdir = os.path.join(userdir, 'pluma/snippets') else: - snippetsdir = os.path.expanduser('~/.mate2/gedit/snippets') + snippetsdir = os.path.expanduser('~/.mate2/pluma/snippets') library.set_dirs(snippetsdir, self.system_dirs()) @@ -59,7 +59,7 @@ class SnippetsPlugin(gedit.Plugin): dirs = [] for d in datadirs.split(os.pathsep): - d = os.path.join(d, 'gedit-2', 'plugins', 'snippets') + d = os.path.join(d, 'pluma-2', 'plugins', 'snippets') if os.path.isdir(d): dirs.append(d) @@ -85,7 +85,7 @@ class SnippetsPlugin(gedit.Plugin): else: self.dlg.run() - window = gedit.app_get_default().get_active_window() + window = pluma.app_get_default().get_active_window() if window: self.dlg.dlg.set_transient_for(window) diff --git a/plugins/snippets/snippets/snippets.ui b/plugins/snippets/snippets/snippets.ui index 426df886..b90324c2 100755 --- a/plugins/snippets/snippets/snippets.ui +++ b/plugins/snippets/snippets/snippets.ui @@ -32,7 +32,7 @@ - + True @@ -331,7 +331,7 @@ GTK_SHADOW_IN GTK_CORNER_TOP_LEFT - + source_buffer True True diff --git a/plugins/sort/Makefile.am b/plugins/sort/Makefile.am index 8fa39143..52274688 100755 --- a/plugins/sort/Makefile.am +++ b/plugins/sort/Makefile.am @@ -1,29 +1,29 @@ # sort plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) plugin_LTLIBRARIES = libsort.la libsort_la_SOURCES = \ - gedit-sort-plugin.h \ - gedit-sort-plugin.c + pluma-sort-plugin.h \ + pluma-sort-plugin.c libsort_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libsort_la_LIBADD = $(GEDIT_LIBS) +libsort_la_LIBADD = $(PLUMA_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/sort +uidir = $(PLUMA_PLUGINS_DATA_DIR)/sort ui_DATA = sort.ui -plugin_in_files = sort.gedit-plugin.desktop.in +plugin_in_files = sort.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(ui_DATA) $(plugin_in_files) diff --git a/plugins/sort/gedit-sort-plugin.c b/plugins/sort/gedit-sort-plugin.c deleted file mode 100755 index 8fc6c959..00000000 --- a/plugins/sort/gedit-sort-plugin.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * gedit-sort-plugin.c - * - * Original author: Carlo Borreo - * Ported to Gedit2 by Lee Mallabone - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-sort-plugin.h" - -#include -#include -#include - -#include -#include -#include - -#define GEDIT_SORT_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_SORT_PLUGIN, GeditSortPluginPrivate)) - -/* Key in case the plugin ever needs any settings. */ -#define SORT_BASE_KEY "/apps/gedit-2/plugins/sort" - -#define WINDOW_DATA_KEY "GeditSortPluginWindowData" -#define MENU_PATH "/MenuBar/EditMenu/EditOps_6" - -GEDIT_PLUGIN_REGISTER_TYPE(GeditSortPlugin, gedit_sort_plugin) - -typedef struct -{ - GtkWidget *dialog; - GtkWidget *col_num_spinbutton; - GtkWidget *reverse_order_checkbutton; - GtkWidget *ignore_case_checkbutton; - GtkWidget *remove_dups_checkbutton; - - GeditDocument *doc; - - GtkTextIter start, end; /* selection */ -} SortDialog; - -typedef struct -{ - GtkActionGroup *ui_action_group; - guint ui_id; -} WindowData; - -typedef struct -{ - GeditPlugin *plugin; - GeditWindow *window; -} ActionData; - -typedef struct -{ - gboolean ignore_case; - gboolean reverse_order; - gboolean remove_duplicates; - gint starting_column; -} SortInfo; - -static void sort_cb (GtkAction *action, ActionData *action_data); -static void sort_real (SortDialog *dialog); - -static const GtkActionEntry action_entries[] = -{ - { "Sort", - GTK_STOCK_SORT_ASCENDING, - N_("S_ort..."), - NULL, - N_("Sort the current document or selection"), - G_CALLBACK (sort_cb) } -}; - -static void -sort_dialog_destroy (GtkObject *obj, - gpointer dialog_pointer) -{ - gedit_debug (DEBUG_PLUGINS); - - g_slice_free (SortDialog, dialog_pointer); -} - -static void -sort_dialog_response_handler (GtkDialog *widget, - gint res_id, - SortDialog *dialog) -{ - gedit_debug (DEBUG_PLUGINS); - - switch (res_id) - { - case GTK_RESPONSE_OK: - sort_real (dialog); - gtk_widget_destroy (dialog->dialog); - break; - - case GTK_RESPONSE_HELP: - gedit_help_display (GTK_WINDOW (widget), - NULL, - "gedit-sort-plugin"); - break; - - case GTK_RESPONSE_CANCEL: - gtk_widget_destroy (dialog->dialog); - break; - } -} - -/* NOTE: we store the current selection in the dialog since focusing - * the text field (like the combo box) looses the documnent selection. - * Storing the selection ONLY works because the dialog is modal */ -static void -get_current_selection (GeditWindow *window, SortDialog *dialog) -{ - GeditDocument *doc; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (window); - - if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), - &dialog->start, - &dialog->end)) - { - /* No selection, get the whole document. */ - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), - &dialog->start, - &dialog->end); - } -} - -static SortDialog * -get_sort_dialog (ActionData *action_data) -{ - SortDialog *dialog; - GtkWidget *error_widget; - gboolean ret; - gchar *data_dir; - gchar *ui_file; - - gedit_debug (DEBUG_PLUGINS); - - dialog = g_slice_new (SortDialog); - - data_dir = gedit_plugin_get_data_dir (action_data->plugin); - ui_file = g_build_filename (data_dir, "sort.ui", NULL); - g_free (data_dir); - ret = gedit_utils_get_ui_objects (ui_file, - NULL, - &error_widget, - "sort_dialog", &dialog->dialog, - "reverse_order_checkbutton", &dialog->reverse_order_checkbutton, - "col_num_spinbutton", &dialog->col_num_spinbutton, - "ignore_case_checkbutton", &dialog->ignore_case_checkbutton, - "remove_dups_checkbutton", &dialog->remove_dups_checkbutton, - NULL); - g_free (ui_file); - - if (!ret) - { - const gchar *err_message; - - err_message = gtk_label_get_label (GTK_LABEL (error_widget)); - gedit_warning (GTK_WINDOW (action_data->window), - "%s", err_message); - - g_free (dialog); - gtk_widget_destroy (error_widget); - - return NULL; - } - - gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), - GTK_RESPONSE_OK); - - g_signal_connect (dialog->dialog, - "destroy", - G_CALLBACK (sort_dialog_destroy), - dialog); - - g_signal_connect (dialog->dialog, - "response", - G_CALLBACK (sort_dialog_response_handler), - dialog); - - get_current_selection (action_data->window, dialog); - - return dialog; -} - -static void -sort_cb (GtkAction *action, - ActionData *action_data) -{ - GeditDocument *doc; - GtkWindowGroup *wg; - SortDialog *dialog; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (action_data->window); - g_return_if_fail (doc != NULL); - - dialog = get_sort_dialog (action_data); - g_return_if_fail (dialog != NULL); - - wg = gedit_window_get_group (action_data->window); - gtk_window_group_add_window (wg, - GTK_WINDOW (dialog->dialog)); - - dialog->doc = doc; - - gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), - GTK_WINDOW (action_data->window)); - - gtk_window_set_modal (GTK_WINDOW (dialog->dialog), - TRUE); - - gtk_widget_show (GTK_WIDGET (dialog->dialog)); -} - -/* Compares two strings for the sorting algorithm. Uses the UTF-8 processing - * functions in GLib to be as correct as possible.*/ -static gint -compare_algorithm (gconstpointer s1, - gconstpointer s2, - gpointer data) -{ - gint length1, length2; - gint ret; - gchar *string1, *string2; - gchar *substring1, *substring2; - gchar *key1, *key2; - SortInfo *sort_info; - - gedit_debug (DEBUG_PLUGINS); - - sort_info = (SortInfo *) data; - g_return_val_if_fail (sort_info != NULL, -1); - - if (!sort_info->ignore_case) - { - string1 = *((gchar **) s1); - string2 = *((gchar **) s2); - } - else - { - string1 = g_utf8_casefold (*((gchar **) s1), -1); - string2 = g_utf8_casefold (*((gchar **) s2), -1); - } - - length1 = g_utf8_strlen (string1, -1); - length2 = g_utf8_strlen (string2, -1); - - if ((length1 < sort_info->starting_column) && - (length2 < sort_info->starting_column)) - { - ret = 0; - } - else if (length1 < sort_info->starting_column) - { - ret = -1; - } - else if (length2 < sort_info->starting_column) - { - ret = 1; - } - else if (sort_info->starting_column < 1) - { - key1 = g_utf8_collate_key (string1, -1); - key2 = g_utf8_collate_key (string2, -1); - ret = strcmp (key1, key2); - - g_free (key1); - g_free (key2); - } - else - { - /* A character column offset is required, so figure out - * the correct offset into the UTF-8 string. */ - substring1 = g_utf8_offset_to_pointer (string1, sort_info->starting_column); - substring2 = g_utf8_offset_to_pointer (string2, sort_info->starting_column); - - key1 = g_utf8_collate_key (substring1, -1); - key2 = g_utf8_collate_key (substring2, -1); - ret = strcmp (key1, key2); - - g_free (key1); - g_free (key2); - } - - /* Do the necessary cleanup. */ - if (sort_info->ignore_case) - { - g_free (string1); - g_free (string2); - } - - if (sort_info->reverse_order) - { - ret = -1 * ret; - } - - return ret; -} - -static gchar * -get_line_slice (GtkTextBuffer *buf, - gint line) -{ - GtkTextIter start, end; - char *ret; - - gtk_text_buffer_get_iter_at_line (buf, &start, line); - end = start; - - if (!gtk_text_iter_ends_line (&start)) - gtk_text_iter_forward_to_line_end (&end); - - ret= gtk_text_buffer_get_slice (buf, - &start, - &end, - TRUE); - - g_assert (ret != NULL); - - return ret; -} - -static void -sort_real (SortDialog *dialog) -{ - GeditDocument *doc; - GtkTextIter start, end; - gint start_line, end_line; - gint i; - gchar *last_row = NULL; - gint num_lines; - gchar **lines; - SortInfo *sort_info; - - gedit_debug (DEBUG_PLUGINS); - - doc = dialog->doc; - g_return_if_fail (doc != NULL); - - sort_info = g_new0 (SortInfo, 1); - sort_info->ignore_case = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->ignore_case_checkbutton)); - sort_info->reverse_order = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->reverse_order_checkbutton)); - sort_info->remove_duplicates = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->remove_dups_checkbutton)); - sort_info->starting_column = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->col_num_spinbutton)) - 1; - - start = dialog->start; - end = dialog->end; - start_line = gtk_text_iter_get_line (&start); - end_line = gtk_text_iter_get_line (&end); - - /* if we are at line start our last line is the previus one. - * Otherwise the last line is the current one but we try to - * move the iter after the line terminator */ - if (gtk_text_iter_get_line_offset (&end) == 0) - end_line = MAX (start_line, end_line - 1); - else - gtk_text_iter_forward_line (&end); - - num_lines = end_line - start_line + 1; - lines = g_new0 (gchar *, num_lines + 1); - - gedit_debug_message (DEBUG_PLUGINS, "Building list..."); - - for (i = 0; i < num_lines; i++) - { - lines[i] = get_line_slice (GTK_TEXT_BUFFER (doc), start_line + i); - } - - lines[num_lines] = NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Sort list..."); - - g_qsort_with_data (lines, - num_lines, - sizeof (gpointer), - compare_algorithm, - sort_info); - - gedit_debug_message (DEBUG_PLUGINS, "Rebuilding document..."); - - gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (doc)); - - gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), - &start, - &end); - - for (i = 0; i < num_lines; i++) - { - if (sort_info->remove_duplicates && - last_row != NULL && - (strcmp (last_row, lines[i]) == 0)) - continue; - - gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), - &start, - lines[i], - -1); - gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), - &start, - "\n", - -1); - - last_row = lines[i]; - } - - gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (doc)); - - g_strfreev (lines); - g_free (sort_info); - - gedit_debug_message (DEBUG_PLUGINS, "Done."); -} - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - g_object_unref (data->ui_action_group); - g_slice_free (WindowData, data); -} - -static void -free_action_data (ActionData *data) -{ - g_return_if_fail (data != NULL); - - g_slice_free (ActionData, data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GeditView *view; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (window); - - gtk_action_group_set_sensitive (data->ui_action_group, - (view != NULL) && - gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - ActionData *action_data; - - gedit_debug (DEBUG_PLUGINS); - - data = g_slice_new (WindowData); - action_data = g_slice_new (ActionData); - action_data->window = window; - action_data->plugin = plugin; - - manager = gedit_window_get_ui_manager (window); - - data->ui_action_group = gtk_action_group_new ("GeditSortPluginActions"); - gtk_action_group_set_translation_domain (data->ui_action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions_full (data->ui_action_group, - action_entries, - G_N_ELEMENTS (action_entries), - action_data, - (GDestroyNotify) free_action_data); - - gtk_ui_manager_insert_action_group (manager, - data->ui_action_group, - -1); - - data->ui_id = gtk_ui_manager_new_merge_id (manager); - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "Sort", - "Sort", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - update_ui_real (window, - data); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, - data->ui_id); - gtk_ui_manager_remove_action_group (manager, - data->ui_action_group); - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, - data); -} - -static void -gedit_sort_plugin_init (GeditSortPlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin initializing"); -} - -static void -gedit_sort_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin finalizing"); - - G_OBJECT_CLASS (gedit_sort_plugin_parent_class)->finalize (object); -} - -static void -gedit_sort_plugin_class_init (GeditSortPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_sort_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; -} diff --git a/plugins/sort/gedit-sort-plugin.h b/plugins/sort/gedit-sort-plugin.h deleted file mode 100755 index c10280bf..00000000 --- a/plugins/sort/gedit-sort-plugin.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * gedit-sort-plugin.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_SORT_PLUGIN_H__ -#define __GEDIT_SORT_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_SORT_PLUGIN (gedit_sort_plugin_get_type ()) -#define GEDIT_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_SORT_PLUGIN, GeditSortPlugin)) -#define GEDIT_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_SORT_PLUGIN, GeditSortPluginClass)) -#define GEDIT_IS_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_SORT_PLUGIN)) -#define GEDIT_IS_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_SORT_PLUGIN)) -#define GEDIT_SORT_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_SORT_PLUGIN, GeditSortPluginClass)) - -/* Private structure type */ -typedef struct _GeditSortPluginPrivate GeditSortPluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditSortPlugin GeditSortPlugin; - -struct _GeditSortPlugin -{ - GeditPlugin parent_instance; -}; - -/* - * Class definition - */ -typedef struct _GeditSortPluginClass GeditSortPluginClass; - -struct _GeditSortPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_sort_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_SORT_PLUGIN_H__ */ diff --git a/plugins/sort/pluma-sort-plugin.c b/plugins/sort/pluma-sort-plugin.c new file mode 100755 index 00000000..e1e5cf5e --- /dev/null +++ b/plugins/sort/pluma-sort-plugin.c @@ -0,0 +1,588 @@ +/* + * pluma-sort-plugin.c + * + * Original author: Carlo Borreo + * Ported to Pluma2 by Lee Mallabone + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-sort-plugin.h" + +#include +#include +#include + +#include +#include +#include + +#define PLUMA_SORT_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), PLUMA_TYPE_SORT_PLUGIN, PlumaSortPluginPrivate)) + +/* Key in case the plugin ever needs any settings. */ +#define SORT_BASE_KEY "/apps/pluma-2/plugins/sort" + +#define WINDOW_DATA_KEY "PlumaSortPluginWindowData" +#define MENU_PATH "/MenuBar/EditMenu/EditOps_6" + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaSortPlugin, pluma_sort_plugin) + +typedef struct +{ + GtkWidget *dialog; + GtkWidget *col_num_spinbutton; + GtkWidget *reverse_order_checkbutton; + GtkWidget *ignore_case_checkbutton; + GtkWidget *remove_dups_checkbutton; + + PlumaDocument *doc; + + GtkTextIter start, end; /* selection */ +} SortDialog; + +typedef struct +{ + GtkActionGroup *ui_action_group; + guint ui_id; +} WindowData; + +typedef struct +{ + PlumaPlugin *plugin; + PlumaWindow *window; +} ActionData; + +typedef struct +{ + gboolean ignore_case; + gboolean reverse_order; + gboolean remove_duplicates; + gint starting_column; +} SortInfo; + +static void sort_cb (GtkAction *action, ActionData *action_data); +static void sort_real (SortDialog *dialog); + +static const GtkActionEntry action_entries[] = +{ + { "Sort", + GTK_STOCK_SORT_ASCENDING, + N_("S_ort..."), + NULL, + N_("Sort the current document or selection"), + G_CALLBACK (sort_cb) } +}; + +static void +sort_dialog_destroy (GtkObject *obj, + gpointer dialog_pointer) +{ + pluma_debug (DEBUG_PLUGINS); + + g_slice_free (SortDialog, dialog_pointer); +} + +static void +sort_dialog_response_handler (GtkDialog *widget, + gint res_id, + SortDialog *dialog) +{ + pluma_debug (DEBUG_PLUGINS); + + switch (res_id) + { + case GTK_RESPONSE_OK: + sort_real (dialog); + gtk_widget_destroy (dialog->dialog); + break; + + case GTK_RESPONSE_HELP: + pluma_help_display (GTK_WINDOW (widget), + NULL, + "pluma-sort-plugin"); + break; + + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy (dialog->dialog); + break; + } +} + +/* NOTE: we store the current selection in the dialog since focusing + * the text field (like the combo box) looses the documnent selection. + * Storing the selection ONLY works because the dialog is modal */ +static void +get_current_selection (PlumaWindow *window, SortDialog *dialog) +{ + PlumaDocument *doc; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (window); + + if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &dialog->start, + &dialog->end)) + { + /* No selection, get the whole document. */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), + &dialog->start, + &dialog->end); + } +} + +static SortDialog * +get_sort_dialog (ActionData *action_data) +{ + SortDialog *dialog; + GtkWidget *error_widget; + gboolean ret; + gchar *data_dir; + gchar *ui_file; + + pluma_debug (DEBUG_PLUGINS); + + dialog = g_slice_new (SortDialog); + + data_dir = pluma_plugin_get_data_dir (action_data->plugin); + ui_file = g_build_filename (data_dir, "sort.ui", NULL); + g_free (data_dir); + ret = pluma_utils_get_ui_objects (ui_file, + NULL, + &error_widget, + "sort_dialog", &dialog->dialog, + "reverse_order_checkbutton", &dialog->reverse_order_checkbutton, + "col_num_spinbutton", &dialog->col_num_spinbutton, + "ignore_case_checkbutton", &dialog->ignore_case_checkbutton, + "remove_dups_checkbutton", &dialog->remove_dups_checkbutton, + NULL); + g_free (ui_file); + + if (!ret) + { + const gchar *err_message; + + err_message = gtk_label_get_label (GTK_LABEL (error_widget)); + pluma_warning (GTK_WINDOW (action_data->window), + "%s", err_message); + + g_free (dialog); + gtk_widget_destroy (error_widget); + + return NULL; + } + + gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), + GTK_RESPONSE_OK); + + g_signal_connect (dialog->dialog, + "destroy", + G_CALLBACK (sort_dialog_destroy), + dialog); + + g_signal_connect (dialog->dialog, + "response", + G_CALLBACK (sort_dialog_response_handler), + dialog); + + get_current_selection (action_data->window, dialog); + + return dialog; +} + +static void +sort_cb (GtkAction *action, + ActionData *action_data) +{ + PlumaDocument *doc; + GtkWindowGroup *wg; + SortDialog *dialog; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (action_data->window); + g_return_if_fail (doc != NULL); + + dialog = get_sort_dialog (action_data); + g_return_if_fail (dialog != NULL); + + wg = pluma_window_get_group (action_data->window); + gtk_window_group_add_window (wg, + GTK_WINDOW (dialog->dialog)); + + dialog->doc = doc; + + gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), + GTK_WINDOW (action_data->window)); + + gtk_window_set_modal (GTK_WINDOW (dialog->dialog), + TRUE); + + gtk_widget_show (GTK_WIDGET (dialog->dialog)); +} + +/* Compares two strings for the sorting algorithm. Uses the UTF-8 processing + * functions in GLib to be as correct as possible.*/ +static gint +compare_algorithm (gconstpointer s1, + gconstpointer s2, + gpointer data) +{ + gint length1, length2; + gint ret; + gchar *string1, *string2; + gchar *substring1, *substring2; + gchar *key1, *key2; + SortInfo *sort_info; + + pluma_debug (DEBUG_PLUGINS); + + sort_info = (SortInfo *) data; + g_return_val_if_fail (sort_info != NULL, -1); + + if (!sort_info->ignore_case) + { + string1 = *((gchar **) s1); + string2 = *((gchar **) s2); + } + else + { + string1 = g_utf8_casefold (*((gchar **) s1), -1); + string2 = g_utf8_casefold (*((gchar **) s2), -1); + } + + length1 = g_utf8_strlen (string1, -1); + length2 = g_utf8_strlen (string2, -1); + + if ((length1 < sort_info->starting_column) && + (length2 < sort_info->starting_column)) + { + ret = 0; + } + else if (length1 < sort_info->starting_column) + { + ret = -1; + } + else if (length2 < sort_info->starting_column) + { + ret = 1; + } + else if (sort_info->starting_column < 1) + { + key1 = g_utf8_collate_key (string1, -1); + key2 = g_utf8_collate_key (string2, -1); + ret = strcmp (key1, key2); + + g_free (key1); + g_free (key2); + } + else + { + /* A character column offset is required, so figure out + * the correct offset into the UTF-8 string. */ + substring1 = g_utf8_offset_to_pointer (string1, sort_info->starting_column); + substring2 = g_utf8_offset_to_pointer (string2, sort_info->starting_column); + + key1 = g_utf8_collate_key (substring1, -1); + key2 = g_utf8_collate_key (substring2, -1); + ret = strcmp (key1, key2); + + g_free (key1); + g_free (key2); + } + + /* Do the necessary cleanup. */ + if (sort_info->ignore_case) + { + g_free (string1); + g_free (string2); + } + + if (sort_info->reverse_order) + { + ret = -1 * ret; + } + + return ret; +} + +static gchar * +get_line_slice (GtkTextBuffer *buf, + gint line) +{ + GtkTextIter start, end; + char *ret; + + gtk_text_buffer_get_iter_at_line (buf, &start, line); + end = start; + + if (!gtk_text_iter_ends_line (&start)) + gtk_text_iter_forward_to_line_end (&end); + + ret= gtk_text_buffer_get_slice (buf, + &start, + &end, + TRUE); + + g_assert (ret != NULL); + + return ret; +} + +static void +sort_real (SortDialog *dialog) +{ + PlumaDocument *doc; + GtkTextIter start, end; + gint start_line, end_line; + gint i; + gchar *last_row = NULL; + gint num_lines; + gchar **lines; + SortInfo *sort_info; + + pluma_debug (DEBUG_PLUGINS); + + doc = dialog->doc; + g_return_if_fail (doc != NULL); + + sort_info = g_new0 (SortInfo, 1); + sort_info->ignore_case = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->ignore_case_checkbutton)); + sort_info->reverse_order = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->reverse_order_checkbutton)); + sort_info->remove_duplicates = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->remove_dups_checkbutton)); + sort_info->starting_column = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->col_num_spinbutton)) - 1; + + start = dialog->start; + end = dialog->end; + start_line = gtk_text_iter_get_line (&start); + end_line = gtk_text_iter_get_line (&end); + + /* if we are at line start our last line is the previus one. + * Otherwise the last line is the current one but we try to + * move the iter after the line terminator */ + if (gtk_text_iter_get_line_offset (&end) == 0) + end_line = MAX (start_line, end_line - 1); + else + gtk_text_iter_forward_line (&end); + + num_lines = end_line - start_line + 1; + lines = g_new0 (gchar *, num_lines + 1); + + pluma_debug_message (DEBUG_PLUGINS, "Building list..."); + + for (i = 0; i < num_lines; i++) + { + lines[i] = get_line_slice (GTK_TEXT_BUFFER (doc), start_line + i); + } + + lines[num_lines] = NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Sort list..."); + + g_qsort_with_data (lines, + num_lines, + sizeof (gpointer), + compare_algorithm, + sort_info); + + pluma_debug_message (DEBUG_PLUGINS, "Rebuilding document..."); + + gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (doc)); + + gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), + &start, + &end); + + for (i = 0; i < num_lines; i++) + { + if (sort_info->remove_duplicates && + last_row != NULL && + (strcmp (last_row, lines[i]) == 0)) + continue; + + gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), + &start, + lines[i], + -1); + gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), + &start, + "\n", + -1); + + last_row = lines[i]; + } + + gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (doc)); + + g_strfreev (lines); + g_free (sort_info); + + pluma_debug_message (DEBUG_PLUGINS, "Done."); +} + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + g_object_unref (data->ui_action_group); + g_slice_free (WindowData, data); +} + +static void +free_action_data (ActionData *data) +{ + g_return_if_fail (data != NULL); + + g_slice_free (ActionData, data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + PlumaView *view; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (window); + + gtk_action_group_set_sensitive (data->ui_action_group, + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + ActionData *action_data; + + pluma_debug (DEBUG_PLUGINS); + + data = g_slice_new (WindowData); + action_data = g_slice_new (ActionData); + action_data->window = window; + action_data->plugin = plugin; + + manager = pluma_window_get_ui_manager (window); + + data->ui_action_group = gtk_action_group_new ("PlumaSortPluginActions"); + gtk_action_group_set_translation_domain (data->ui_action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions_full (data->ui_action_group, + action_entries, + G_N_ELEMENTS (action_entries), + action_data, + (GDestroyNotify) free_action_data); + + gtk_ui_manager_insert_action_group (manager, + data->ui_action_group, + -1); + + data->ui_id = gtk_ui_manager_new_merge_id (manager); + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "Sort", + "Sort", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + update_ui_real (window, + data); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, + data->ui_id); + gtk_ui_manager_remove_action_group (manager, + data->ui_action_group); + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, + data); +} + +static void +pluma_sort_plugin_init (PlumaSortPlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSortPlugin initializing"); +} + +static void +pluma_sort_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSortPlugin finalizing"); + + G_OBJECT_CLASS (pluma_sort_plugin_parent_class)->finalize (object); +} + +static void +pluma_sort_plugin_class_init (PlumaSortPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_sort_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; +} diff --git a/plugins/sort/pluma-sort-plugin.h b/plugins/sort/pluma-sort-plugin.h new file mode 100755 index 00000000..f359d4f7 --- /dev/null +++ b/plugins/sort/pluma-sort-plugin.h @@ -0,0 +1,73 @@ +/* + * pluma-sort-plugin.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_SORT_PLUGIN_H__ +#define __PLUMA_SORT_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_SORT_PLUGIN (pluma_sort_plugin_get_type ()) +#define PLUMA_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_SORT_PLUGIN, PlumaSortPlugin)) +#define PLUMA_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_SORT_PLUGIN, PlumaSortPluginClass)) +#define PLUMA_IS_SORT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_SORT_PLUGIN)) +#define PLUMA_IS_SORT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_SORT_PLUGIN)) +#define PLUMA_SORT_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_SORT_PLUGIN, PlumaSortPluginClass)) + +/* Private structure type */ +typedef struct _PlumaSortPluginPrivate PlumaSortPluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaSortPlugin PlumaSortPlugin; + +struct _PlumaSortPlugin +{ + PlumaPlugin parent_instance; +}; + +/* + * Class definition + */ +typedef struct _PlumaSortPluginClass PlumaSortPluginClass; + +struct _PlumaSortPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_sort_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_SORT_PLUGIN_H__ */ diff --git a/plugins/sort/sort.gedit-plugin.desktop.in b/plugins/sort/sort.gedit-plugin.desktop.in deleted file mode 100755 index 9ee9634a..00000000 --- a/plugins/sort/sort.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Module=sort -IAge=2 -_Name=Sort -_Description=Sorts a document or selected text. -Icon=gtk-sort-ascending -Authors=Carlo Borreo ;Lee Mallabone ;Paolo Maggi ;Jorge Alberto Torres H. -Copyright=Copyright © 2001 Carlo Borreo\nCopyright © 2002-2003 Lee Mallabone, Paolo Maggi\nCopyright © 2004-2005 Paolo Maggi -Website=http://www.gedit.org diff --git a/plugins/sort/sort.pluma-plugin.desktop.in b/plugins/sort/sort.pluma-plugin.desktop.in new file mode 100755 index 00000000..c312cbaf --- /dev/null +++ b/plugins/sort/sort.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Module=sort +IAge=2 +_Name=Sort +_Description=Sorts a document or selected text. +Icon=gtk-sort-ascending +Authors=Carlo Borreo ;Lee Mallabone ;Paolo Maggi ;Jorge Alberto Torres H. +Copyright=Copyright © 2001 Carlo Borreo\nCopyright © 2002-2003 Lee Mallabone, Paolo Maggi\nCopyright © 2004-2005 Paolo Maggi +Website=http://www.pluma.org diff --git a/plugins/spell/Makefile.am b/plugins/spell/Makefile.am index 9d332f95..24299165 100755 --- a/plugins/spell/Makefile.am +++ b/plugins/spell/Makefile.am @@ -1,59 +1,59 @@ # Spell checker plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(ENCHANT_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) BUILT_SOURCES = \ - gedit-spell-marshal.c \ - gedit-spell-marshal.h + pluma-spell-marshal.c \ + pluma-spell-marshal.h plugin_LTLIBRARIES = libspell.la libspell_la_SOURCES = \ - gedit-spell-plugin.c \ - gedit-spell-plugin.h \ - gedit-spell-checker.c \ - gedit-spell-checker.h \ - gedit-spell-checker-dialog.c \ - gedit-spell-checker-dialog.h \ - gedit-spell-checker-language.c \ - gedit-spell-checker-language.h \ - gedit-spell-language-dialog.c \ - gedit-spell-language-dialog.h \ - gedit-automatic-spell-checker.c \ - gedit-automatic-spell-checker.h \ - gedit-spell-utils.c \ - gedit-spell-utils.h \ + pluma-spell-plugin.c \ + pluma-spell-plugin.h \ + pluma-spell-checker.c \ + pluma-spell-checker.h \ + pluma-spell-checker-dialog.c \ + pluma-spell-checker-dialog.h \ + pluma-spell-checker-language.c \ + pluma-spell-checker-language.h \ + pluma-spell-language-dialog.c \ + pluma-spell-language-dialog.h \ + pluma-automatic-spell-checker.c \ + pluma-automatic-spell-checker.h \ + pluma-spell-utils.c \ + pluma-spell-utils.h \ $(BUILT_SOURCES) libspell_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libspell_la_LIBADD = $(GEDIT_LIBS) $(ENCHANT_LIBS) +libspell_la_LIBADD = $(PLUMA_LIBS) $(ENCHANT_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/spell +uidir = $(PLUMA_PLUGINS_DATA_DIR)/spell ui_DATA = spell-checker.ui languages-dialog.ui -gedit-spell-marshal.h: gedit-spell-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_marshal > $@ +pluma-spell-marshal.h: pluma-spell-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=pluma_marshal > $@ -gedit-spell-marshal.c: gedit-spell-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) echo "#include \"gedit-spell-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=gedit_marshal >> $@ +pluma-spell-marshal.c: pluma-spell-marshal.list $(GLIB_GENMARSHAL) + $(AM_V_GEN) echo "#include \"pluma-spell-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=pluma_marshal >> $@ -plugin_in_files = spell.gedit-plugin.desktop.in +plugin_in_files = spell.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = \ $(ui_DATA) \ $(plugin_in_files) \ - gedit-spell-marshal.list + pluma-spell-marshal.list CLEANFILES = $(BUILT_SOURCES) $(plugin_DATA) diff --git a/plugins/spell/gedit-automatic-spell-checker.c b/plugins/spell/gedit-automatic-spell-checker.c deleted file mode 100755 index 96b2fae9..00000000 --- a/plugins/spell/gedit-automatic-spell-checker.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-automatic-spell-checker.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */ -/* gtkspell - a spell-checking addon for GTK's TextView widget - * Copyright (c) 2002 Evan Martin. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include "gedit-automatic-spell-checker.h" -#include "gedit-spell-utils.h" - -struct _GeditAutomaticSpellChecker { - GeditDocument *doc; - GSList *views; - - GtkTextMark *mark_insert_start; - GtkTextMark *mark_insert_end; - gboolean deferred_check; - - GtkTextTag *tag_highlight; - GtkTextMark *mark_click; - - GeditSpellChecker *spell_checker; -}; - -static GQuark automatic_spell_checker_id = 0; -static GQuark suggestion_id = 0; - -static void gedit_automatic_spell_checker_free_internal (GeditAutomaticSpellChecker *spell); - -static void -view_destroy (GeditView *view, GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_detach_view (spell, view); -} - -static void -check_word (GeditAutomaticSpellChecker *spell, GtkTextIter *start, GtkTextIter *end) -{ - gchar *word; - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE); - - /* - g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start), - gtk_text_iter_get_offset (end)); - */ - - if (!gedit_spell_checker_check_word (spell->spell_checker, word, -1)) - { - /* - g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start), - gtk_text_iter_get_offset (end)); - */ - gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - start, - end); - } - - g_free (word); -} - -static void -check_range (GeditAutomaticSpellChecker *spell, - GtkTextIter start, - GtkTextIter end, - gboolean force_all) -{ - /* we need to "split" on word boundaries. - * luckily, Pango knows what "words" are - * so we don't have to figure it out. */ - - GtkTextIter wstart; - GtkTextIter wend; - GtkTextIter cursor; - GtkTextIter precursor; - gboolean highlight; - - /* - g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start), - gtk_text_iter_get_offset (&end)); - */ - - if (gtk_text_iter_inside_word (&end)) - gtk_text_iter_forward_word_end (&end); - - if (!gtk_text_iter_starts_word (&start)) - { - if (gtk_text_iter_inside_word (&start) || - gtk_text_iter_ends_word (&start)) - { - gtk_text_iter_backward_word_start (&start); - } - else - { - /* if we're neither at the beginning nor inside a word, - * me must be in some spaces. - * skip forward to the beginning of the next word. */ - - if (gtk_text_iter_forward_word_end (&start)) - gtk_text_iter_backward_word_start (&start); - } - } - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &cursor, - gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc))); - - precursor = cursor; - gtk_text_iter_backward_char (&precursor); - - highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) || - gtk_text_iter_has_tag (&precursor, spell->tag_highlight); - - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &start, - &end); - - /* Fix a corner case when replacement occurs at beginning of buffer: - * An iter at offset 0 seems to always be inside a word, - * even if it's not. Possibly a pango bug. - */ - if (gtk_text_iter_get_offset (&start) == 0) - { - gtk_text_iter_forward_word_end(&start); - gtk_text_iter_backward_word_start(&start); - } - - wstart = start; - - while (gedit_spell_utils_skip_no_spell_check (&wstart, &end) && - gtk_text_iter_compare (&wstart, &end) < 0) - { - gboolean inword; - - /* move wend to the end of the current word. */ - wend = wstart; - - gtk_text_iter_forward_word_end (&wend); - - inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && - (gtk_text_iter_compare (&cursor, &wend) <= 0); - - if (inword && !force_all) - { - /* this word is being actively edited, - * only check if it's already highligted, - * otherwise defer this check until later. */ - if (highlight) - check_word (spell, &wstart, &wend); - else - spell->deferred_check = TRUE; - } - else - { - check_word (spell, &wstart, &wend); - spell->deferred_check = FALSE; - } - - /* now move wend to the beginning of the next word, */ - gtk_text_iter_forward_word_end (&wend); - gtk_text_iter_backward_word_start (&wend); - - /* make sure we've actually advanced - * (we don't advance in some corner cases), */ - if (gtk_text_iter_equal (&wstart, &wend)) - break; /* we're done in these cases.. */ - - /* and then pick this as the new next word beginning. */ - wstart = wend; - } -} - -static void -check_deferred_range (GeditAutomaticSpellChecker *spell, - gboolean force_all) -{ - GtkTextIter start, end; - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &start, - spell->mark_insert_start); - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), - &end, - spell->mark_insert_end); - - check_range (spell, start, end, force_all); -} - -/* insertion works like this: - * - before the text is inserted, we mark the position in the buffer. - * - after the text is inserted, we see where our mark is and use that and - * the current position to check the entire range of inserted text. - * - * this may be overkill for the common case (inserting one character). */ - -static void -insert_text_before (GtkTextBuffer *buffer, GtkTextIter *iter, - gchar *text, gint len, GeditAutomaticSpellChecker *spell) -{ - gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter); -} - -static void -insert_text_after (GtkTextBuffer *buffer, GtkTextIter *iter, - gchar *text, gint len, GeditAutomaticSpellChecker *spell) -{ - GtkTextIter start; - - /* we need to check a range of text. */ - gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start); - - check_range (spell, start, *iter, FALSE); - - gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter); -} - -/* deleting is more simple: we're given the range of deleted text. - * after deletion, the start and end iters should be at the same position - * (because all of the text between them was deleted!). - * this means we only really check the words immediately bounding the - * deletion. - */ - -static void -delete_range_after (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, - GeditAutomaticSpellChecker *spell) -{ - check_range (spell, *start, *end, FALSE); -} - -static void -mark_set (GtkTextBuffer *buffer, - GtkTextIter *iter, - GtkTextMark *mark, - GeditAutomaticSpellChecker *spell) -{ - /* if the cursor has moved and there is a deferred check so handle it now */ - if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check) - check_deferred_range (spell, FALSE); -} - -static void -get_word_extents_from_mark (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GtkTextMark *mark) -{ - gtk_text_buffer_get_iter_at_mark(buffer, start, mark); - - if (!gtk_text_iter_starts_word (start)) - gtk_text_iter_backward_word_start (start); - - *end = *start; - - if (gtk_text_iter_inside_word (end)) - gtk_text_iter_forward_word_end (end); -} - -static void -remove_tag_to_word (GeditAutomaticSpellChecker *spell, const gchar *word) -{ - GtkTextIter iter; - GtkTextIter match_start, match_end; - - gboolean found; - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0); - - found = TRUE; - - while (found) - { - found = gtk_text_iter_forward_search (&iter, - word, - GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY, - &match_start, - &match_end, - NULL); - - if (found) - { - if (gtk_text_iter_starts_word (&match_start) && - gtk_text_iter_ends_word (&match_end)) - { - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &match_start, - &match_end); - } - - iter = match_end; - } - } -} - -static void -add_to_dictionary (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *word; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), - &start, - &end, - FALSE); - - gedit_spell_checker_add_word_to_personal (spell->spell_checker, word, -1); - - g_free (word); -} - -static void -ignore_all (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *word; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), - &start, - &end, - FALSE); - - gedit_spell_checker_add_word_to_session (spell->spell_checker, word, -1); - - g_free (word); -} - -static void -replace_word (GtkWidget *menuitem, GeditAutomaticSpellChecker *spell) -{ - gchar *oldword; - const gchar *newword; - - GtkTextIter start, end; - - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); - - newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id); - g_return_if_fail (newword != NULL); - - gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc)); - - gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end); - gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1); - - gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc)); - - gedit_spell_checker_set_correction (spell->spell_checker, - oldword, strlen (oldword), - newword, strlen (newword)); - - g_free (oldword); -} - -static GtkWidget * -build_suggestion_menu (GeditAutomaticSpellChecker *spell, const gchar *word) -{ - GtkWidget *topmenu, *menu; - GtkWidget *mi; - GSList *suggestions; - GSList *list; - gchar *label_text; - - topmenu = menu = gtk_menu_new(); - - suggestions = gedit_spell_checker_get_suggestions (spell->spell_checker, word, -1); - - list = suggestions; - - if (suggestions == NULL) - { - /* no suggestions. put something in the menu anyway... */ - GtkWidget *label; - /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */ - label = gtk_label_new (_("(no suggested words)")); - - mi = gtk_menu_item_new (); - gtk_widget_set_sensitive (mi, FALSE); - gtk_container_add (GTK_CONTAINER(mi), label); - gtk_widget_show_all (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); - } - else - { - gint count = 0; - - /* build a set of menus with suggestions. */ - while (suggestions != NULL) - { - GtkWidget *label; - - if (count == 10) - { - /* Separator */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - mi = gtk_menu_item_new_with_mnemonic (_("_More...")); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - menu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu); - count = 0; - } - - label_text = g_strdup_printf ("%s", (gchar*) suggestions->data); - - label = gtk_label_new (label_text); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - - mi = gtk_menu_item_new (); - gtk_container_add (GTK_CONTAINER(mi), label); - - gtk_widget_show_all (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); - - g_object_set_qdata_full (G_OBJECT (mi), - suggestion_id, - g_strdup (suggestions->data), - (GDestroyNotify)g_free); - - g_free (label_text); - g_signal_connect (mi, - "activate", - G_CALLBACK (replace_word), - spell); - - count++; - - suggestions = g_slist_next (suggestions); - } - } - - /* free the suggestion list */ - suggestions = list; - - while (list) - { - g_free (list->data); - list = g_slist_next (list); - } - - g_slist_free (suggestions); - - /* Separator */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - /* Ignore all */ - mi = gtk_image_menu_item_new_with_mnemonic (_("_Ignore All")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), - gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, - GTK_ICON_SIZE_MENU)); - - g_signal_connect (mi, - "activate", - G_CALLBACK(ignore_all), - spell); - - gtk_widget_show_all (mi); - - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - /* + Add to Dictionary */ - mi = gtk_image_menu_item_new_with_mnemonic (_("_Add")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), - gtk_image_new_from_stock (GTK_STOCK_ADD, - GTK_ICON_SIZE_MENU)); - - g_signal_connect (mi, - "activate", - G_CALLBACK (add_to_dictionary), - spell); - - gtk_widget_show_all (mi); - - gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); - - return topmenu; -} - -static void -populate_popup (GtkTextView *textview, GtkMenu *menu, GeditAutomaticSpellChecker *spell) -{ - GtkWidget *img, *mi; - GtkTextIter start, end; - char *word; - - /* we need to figure out if they picked a misspelled word. */ - get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); - - /* if our highlight algorithm ever messes up, - * this isn't correct, either. */ - if (!gtk_text_iter_has_tag (&start, spell->tag_highlight)) - return; /* word wasn't misspelled. */ - - /* menu separator comes first. */ - mi = gtk_menu_item_new (); - gtk_widget_show (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); - - /* then, on top of it, the suggestions menu. */ - img = gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img); - - word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), - build_suggestion_menu (spell, word)); - g_free(word); - - gtk_widget_show_all (mi); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); -} - -void -gedit_automatic_spell_checker_recheck_all (GeditAutomaticSpellChecker *spell) -{ - GtkTextIter start, end; - - g_return_if_fail (spell != NULL); - - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end); - - check_range (spell, start, end, TRUE); -} - -static void -add_word_signal_cb (GeditSpellChecker *checker, - const gchar *word, - gint len, - GeditAutomaticSpellChecker *spell) -{ - gchar *w; - - if (len < 0) - w = g_strdup (word); - else - w = g_strndup (word, len); - - remove_tag_to_word (spell, w); - - g_free (w); -} - -static void -set_language_cb (GeditSpellChecker *checker, - const GeditSpellCheckerLanguage *lang, - GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_recheck_all (spell); -} - -static void -clear_session_cb (GeditSpellChecker *checker, - GeditAutomaticSpellChecker *spell) -{ - gedit_automatic_spell_checker_recheck_all (spell); -} - -/* When the user right-clicks on a word, they want to check that word. - * Here, we do NOT move the cursor to the location of the clicked-upon word - * since that prevents the use of edit functions on the context menu. - */ -static gboolean -button_press_event (GtkTextView *view, - GdkEventButton *event, - GeditAutomaticSpellChecker *spell) -{ - if (event->button == 3) - { - gint x, y; - GtkTextIter iter; - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (view); - - /* handle deferred check if it exists */ - if (spell->deferred_check) - check_deferred_range (spell, TRUE); - - gtk_text_view_window_to_buffer_coords (view, - GTK_TEXT_WINDOW_TEXT, - event->x, event->y, - &x, &y); - - gtk_text_view_get_iter_at_location (view, &iter, x, y); - - gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); - } - - return FALSE; /* false: let gtk process this event, too. - we don't want to eat any events. */ -} - -/* Move the insert mark before popping up the menu, otherwise it - * will contain the wrong set of suggestions. - */ -static gboolean -popup_menu_event (GtkTextView *view, GeditAutomaticSpellChecker *spell) -{ - GtkTextIter iter; - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (view); - - /* handle deferred check if it exists */ - if (spell->deferred_check) - check_deferred_range (spell, TRUE); - - gtk_text_buffer_get_iter_at_mark (buffer, &iter, - gtk_text_buffer_get_insert (buffer)); - gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); - - return FALSE; -} - -static void -tag_table_changed (GtkTextTagTable *table, - GeditAutomaticSpellChecker *spell) -{ - g_return_if_fail (spell->tag_highlight != NULL); - - gtk_text_tag_set_priority (spell->tag_highlight, - gtk_text_tag_table_get_size (table) - 1); -} - -static void -tag_added_or_removed (GtkTextTagTable *table, - GtkTextTag *tag, - GeditAutomaticSpellChecker *spell) -{ - tag_table_changed (table, spell); -} - -static void -tag_changed (GtkTextTagTable *table, - GtkTextTag *tag, - gboolean size_changed, - GeditAutomaticSpellChecker *spell) -{ - tag_table_changed (table, spell); -} - -static void -highlight_updated (GtkSourceBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GeditAutomaticSpellChecker *spell) -{ - check_range (spell, *start, *end, FALSE); -} - -static void -spell_tag_destroyed (GeditAutomaticSpellChecker *spell, - GObject *where_the_object_was) -{ - spell->tag_highlight = NULL; -} - -GeditAutomaticSpellChecker * -gedit_automatic_spell_checker_new (GeditDocument *doc, - GeditSpellChecker *checker) -{ - GeditAutomaticSpellChecker *spell; - GtkTextTagTable *tag_table; - GtkTextIter start, end; - - g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL); - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (checker), NULL); - g_return_val_if_fail ((spell = gedit_automatic_spell_checker_get_from_document (doc)) == NULL, - spell); - - /* attach to the widget */ - spell = g_new0 (GeditAutomaticSpellChecker, 1); - - spell->doc = doc; - spell->spell_checker = g_object_ref (checker); - - if (automatic_spell_checker_id == 0) - { - automatic_spell_checker_id = - g_quark_from_string ("GeditAutomaticSpellCheckerID"); - } - if (suggestion_id == 0) - { - suggestion_id = g_quark_from_string ("GeditAutoSuggestionID"); - } - - g_object_set_qdata_full (G_OBJECT (doc), - automatic_spell_checker_id, - spell, - (GDestroyNotify)gedit_automatic_spell_checker_free_internal); - - g_signal_connect (doc, - "insert-text", - G_CALLBACK (insert_text_before), - spell); - g_signal_connect_after (doc, - "insert-text", - G_CALLBACK (insert_text_after), - spell); - g_signal_connect_after (doc, - "delete-range", - G_CALLBACK (delete_range_after), - spell); - g_signal_connect (doc, - "mark-set", - G_CALLBACK (mark_set), - spell); - - g_signal_connect (doc, - "highlight-updated", - G_CALLBACK (highlight_updated), - spell); - - g_signal_connect (spell->spell_checker, - "add_word_to_session", - G_CALLBACK (add_word_signal_cb), - spell); - g_signal_connect (spell->spell_checker, - "add_word_to_personal", - G_CALLBACK (add_word_signal_cb), - spell); - g_signal_connect (spell->spell_checker, - "clear_session", - G_CALLBACK (clear_session_cb), - spell); - g_signal_connect (spell->spell_checker, - "set_language", - G_CALLBACK (set_language_cb), - spell); - - spell->tag_highlight = gtk_text_buffer_create_tag ( - GTK_TEXT_BUFFER (doc), - "gtkspell-misspelled", - "underline", PANGO_UNDERLINE_ERROR, - NULL); - - g_object_weak_ref (G_OBJECT (spell->tag_highlight), - (GWeakNotify)spell_tag_destroyed, - spell); - - tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc)); - - gtk_text_tag_set_priority (spell->tag_highlight, - gtk_text_tag_table_get_size (tag_table) - 1); - - g_signal_connect (tag_table, - "tag-added", - G_CALLBACK (tag_added_or_removed), - spell); - g_signal_connect (tag_table, - "tag-removed", - G_CALLBACK (tag_added_or_removed), - spell); - g_signal_connect (tag_table, - "tag-changed", - G_CALLBACK (tag_changed), - spell); - - /* we create the mark here, but we don't use it until text is - * inserted, so we don't really care where iter points. */ - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end); - - spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-start"); - - if (spell->mark_insert_start == NULL) - { - spell->mark_insert_start = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-start", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_insert_start, - &start); - } - - spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-end"); - - if (spell->mark_insert_end == NULL) - { - spell->mark_insert_end = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-insert-end", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_insert_end, - &start); - } - - spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-click"); - - if (spell->mark_click == NULL) - { - spell->mark_click = - gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "gedit-automatic-spell-checker-click", - &start, - TRUE); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - spell->mark_click, - &start); - } - - spell->deferred_check = FALSE; - - return spell; -} - -GeditAutomaticSpellChecker * -gedit_automatic_spell_checker_get_from_document (const GeditDocument *doc) -{ - g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL); - - if (automatic_spell_checker_id == 0) - return NULL; - - return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id); -} - -void -gedit_automatic_spell_checker_free (GeditAutomaticSpellChecker *spell) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (gedit_automatic_spell_checker_get_from_document (spell->doc) == spell); - - if (automatic_spell_checker_id == 0) - return; - - g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL); -} - -static void -gedit_automatic_spell_checker_free_internal (GeditAutomaticSpellChecker *spell) -{ - GtkTextTagTable *table; - GtkTextIter start, end; - GSList *list; - - g_return_if_fail (spell != NULL); - - table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc)); - - if (table != NULL && spell->tag_highlight != NULL) - { - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), - &start, - &end); - gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), - spell->tag_highlight, - &start, - &end); - - g_signal_handlers_disconnect_matched (G_OBJECT (table), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - gtk_text_tag_table_remove (table, spell->tag_highlight); - } - - g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_object_unref (spell->spell_checker); - - list = spell->views; - while (list != NULL) - { - GeditView *view = GEDIT_VIEW (list->data); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - list = g_slist_next (list); - } - - g_slist_free (spell->views); - - g_free (spell); -} - -void -gedit_automatic_spell_checker_attach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (GEDIT_IS_VIEW (view)); - - g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == - GTK_TEXT_BUFFER (spell->doc)); - - g_signal_connect (view, - "button-press-event", - G_CALLBACK (button_press_event), - spell); - g_signal_connect (view, - "popup-menu", - G_CALLBACK (popup_menu_event), - spell); - g_signal_connect (view, - "populate-popup", - G_CALLBACK (populate_popup), - spell); - g_signal_connect (view, - "destroy", - G_CALLBACK (view_destroy), - spell); - - spell->views = g_slist_prepend (spell->views, view); -} - -void -gedit_automatic_spell_checker_detach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view) -{ - g_return_if_fail (spell != NULL); - g_return_if_fail (GEDIT_IS_VIEW (view)); - - g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == - GTK_TEXT_BUFFER (spell->doc)); - g_return_if_fail (spell->views != NULL); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - g_signal_handlers_disconnect_matched (G_OBJECT (view), - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, - spell); - - spell->views = g_slist_remove (spell->views, view); -} - diff --git a/plugins/spell/gedit-automatic-spell-checker.h b/plugins/spell/gedit-automatic-spell-checker.h deleted file mode 100755 index cc634424..00000000 --- a/plugins/spell/gedit-automatic-spell-checker.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-automatic-spell-checker.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */ -/* gtkspell - a spell-checking addon for GTK's TextView widget - * Copyright (c) 2002 Evan Martin. - */ - -#ifndef __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ -#define __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ - -#include -#include - -#include "gedit-spell-checker.h" - -typedef struct _GeditAutomaticSpellChecker GeditAutomaticSpellChecker; - -GeditAutomaticSpellChecker *gedit_automatic_spell_checker_new ( - GeditDocument *doc, - GeditSpellChecker *checker); - -GeditAutomaticSpellChecker *gedit_automatic_spell_checker_get_from_document ( - const GeditDocument *doc); - -void gedit_automatic_spell_checker_free ( - GeditAutomaticSpellChecker *spell); - -void gedit_automatic_spell_checker_attach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view); - -void gedit_automatic_spell_checker_detach_view ( - GeditAutomaticSpellChecker *spell, - GeditView *view); - -void gedit_automatic_spell_checker_recheck_all ( - GeditAutomaticSpellChecker *spell); - -#endif /* __GEDIT_AUTOMATIC_SPELL_CHECKER_H__ */ - diff --git a/plugins/spell/gedit-spell-checker-dialog.c b/plugins/spell/gedit-spell-checker-dialog.c deleted file mode 100755 index 0488d160..00000000 --- a/plugins/spell/gedit-spell-checker-dialog.c +++ /dev/null @@ -1,722 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-dialog.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include "gedit-spell-checker-dialog.h" -#include "gedit-spell-marshal.h" - -struct _GeditSpellCheckerDialog -{ - GtkWindow parent_instance; - - GeditSpellChecker *spell_checker; - - gchar *misspelled_word; - - GtkWidget *misspelled_word_label; - GtkWidget *word_entry; - GtkWidget *check_word_button; - GtkWidget *ignore_button; - GtkWidget *ignore_all_button; - GtkWidget *change_button; - GtkWidget *change_all_button; - GtkWidget *add_word_button; - GtkWidget *close_button; - GtkWidget *suggestions_list; - GtkWidget *language_label; - - GtkTreeModel *suggestions_list_model; -}; - -enum -{ - IGNORE, - IGNORE_ALL, - CHANGE, - CHANGE_ALL, - ADD_WORD_TO_PERSONAL, - LAST_SIGNAL -}; - -enum -{ - COLUMN_SUGGESTIONS, - NUM_COLUMNS -}; - -static void update_suggestions_list_model (GeditSpellCheckerDialog *dlg, - GSList *suggestions); - -static void word_entry_changed_handler (GtkEditable *editable, - GeditSpellCheckerDialog *dlg); -static void close_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection, - GeditSpellCheckerDialog *dlg); -static void check_word_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void add_word_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void ignore_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void ignore_all_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void change_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void change_all_button_clicked_handler (GtkButton *button, - GeditSpellCheckerDialog *dlg); -static void suggestions_list_row_activated_handler (GtkTreeView *view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellCheckerDialog *dlg); - - -static guint signals [LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(GeditSpellCheckerDialog, gedit_spell_checker_dialog, GTK_TYPE_WINDOW) - -static void -gedit_spell_checker_dialog_destroy (GtkObject *object) -{ - GeditSpellCheckerDialog *dlg = GEDIT_SPELL_CHECKER_DIALOG (object); - - if (dlg->spell_checker != NULL) - { - g_object_unref (dlg->spell_checker); - dlg->spell_checker = NULL; - } - - if (dlg->misspelled_word != NULL) - { - g_free (dlg->misspelled_word); - dlg->misspelled_word = NULL; - } - - GTK_OBJECT_CLASS (gedit_spell_checker_dialog_parent_class)->destroy (object); -} - -static void -gedit_spell_checker_dialog_class_init (GeditSpellCheckerDialogClass * klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - GTK_OBJECT_CLASS (object_class)->destroy = gedit_spell_checker_dialog_destroy; - - signals[IGNORE] = - g_signal_new ("ignore", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, ignore), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[IGNORE_ALL] = - g_signal_new ("ignore_all", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, ignore_all), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); - - signals[CHANGE] = - g_signal_new ("change", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, change), - NULL, NULL, - gedit_marshal_VOID__STRING_STRING, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_STRING); - - signals[CHANGE_ALL] = - g_signal_new ("change_all", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, change_all), - NULL, NULL, - gedit_marshal_VOID__STRING_STRING, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_STRING); - - signals[ADD_WORD_TO_PERSONAL] = - g_signal_new ("add_word_to_personal", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerDialogClass, add_word_to_personal), - NULL, NULL, - gedit_marshal_VOID__STRING, - G_TYPE_NONE, - 1, - G_TYPE_STRING); -} - -static void -create_dialog (GeditSpellCheckerDialog *dlg, - const gchar *data_dir) -{ - GtkWidget *error_widget; - GtkWidget *content; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - GtkTreeSelection *selection; - gchar *root_objects[] = { - "content", - "check_word_image", - "add_word_image", - "ignore_image", - "change_image", - "ignore_all_image", - "change_all_image", - NULL - }; - gboolean ret; - gchar *ui_file; - - g_return_if_fail (dlg != NULL); - - dlg->spell_checker = NULL; - dlg->misspelled_word = NULL; - - ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - root_objects, - &error_widget, - - "content", &content, - "misspelled_word_label", &dlg->misspelled_word_label, - "word_entry", &dlg->word_entry, - "check_word_button", &dlg->check_word_button, - "ignore_button", &dlg->ignore_button, - "ignore_all_button", &dlg->ignore_all_button, - "change_button", &dlg->change_button, - "change_all_button", &dlg->change_all_button, - "add_word_button", &dlg->add_word_button, - "close_button", &dlg->close_button, - "suggestions_list", &dlg->suggestions_list, - "language_label", &dlg->language_label, - NULL); - g_free (ui_file); - - if (!ret) - { - gtk_widget_show (error_widget); - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - error_widget, TRUE, TRUE, 0); - - return; - } - - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), ""); - gtk_widget_set_sensitive (dlg->word_entry, FALSE); - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - gtk_widget_set_sensitive (dlg->add_word_button, FALSE); - - gtk_label_set_label (GTK_LABEL (dlg->language_label), ""); - - gtk_container_add (GTK_CONTAINER (dlg), content); - g_object_unref (content); - - gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE); - gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling")); - - /* Suggestion list */ - dlg->suggestions_list_model = GTK_TREE_MODEL ( - gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list), - dlg->suggestions_list_model); - - /* Add the suggestions column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell, - "text", COLUMN_SUGGESTIONS, NULL); - - gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list), - COLUMN_SUGGESTIONS); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); - - gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); - - /* Set default button */ - GTK_WIDGET_SET_FLAGS (dlg->change_button, GTK_CAN_DEFAULT); - gtk_widget_grab_default (dlg->change_button); - - gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE); - - /* Connect signals */ - g_signal_connect (dlg->word_entry, "changed", - G_CALLBACK (word_entry_changed_handler), dlg); - g_signal_connect (dlg->close_button, "clicked", - G_CALLBACK (close_button_clicked_handler), dlg); - g_signal_connect (selection, "changed", - G_CALLBACK (suggestions_list_selection_changed_handler), - dlg); - g_signal_connect (dlg->check_word_button, "clicked", - G_CALLBACK (check_word_button_clicked_handler), dlg); - g_signal_connect (dlg->add_word_button, "clicked", - G_CALLBACK (add_word_button_clicked_handler), dlg); - g_signal_connect (dlg->ignore_button, "clicked", - G_CALLBACK (ignore_button_clicked_handler), dlg); - g_signal_connect (dlg->ignore_all_button, "clicked", - G_CALLBACK (ignore_all_button_clicked_handler), dlg); - g_signal_connect (dlg->change_button, "clicked", - G_CALLBACK (change_button_clicked_handler), dlg); - g_signal_connect (dlg->change_all_button, "clicked", - G_CALLBACK (change_all_button_clicked_handler), dlg); - g_signal_connect (dlg->suggestions_list, "row-activated", - G_CALLBACK (suggestions_list_row_activated_handler), dlg); -} - -static void -gedit_spell_checker_dialog_init (GeditSpellCheckerDialog *dlg) -{ -} - -GtkWidget * -gedit_spell_checker_dialog_new (const gchar *data_dir) -{ - GeditSpellCheckerDialog *dlg; - - dlg = GEDIT_SPELL_CHECKER_DIALOG ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER_DIALOG, NULL)); - - g_return_val_if_fail (dlg != NULL, NULL); - - create_dialog (dlg, data_dir); - - return GTK_WIDGET (dlg); -} - -GtkWidget * -gedit_spell_checker_dialog_new_from_spell_checker (GeditSpellChecker *spell, - const gchar *data_dir) -{ - GeditSpellCheckerDialog *dlg; - - g_return_val_if_fail (spell != NULL, NULL); - - dlg = GEDIT_SPELL_CHECKER_DIALOG ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER_DIALOG, NULL)); - - g_return_val_if_fail (dlg != NULL, NULL); - - create_dialog (dlg, data_dir); - - gedit_spell_checker_dialog_set_spell_checker (dlg, spell); - - return GTK_WIDGET (dlg); -} - -void -gedit_spell_checker_dialog_set_spell_checker (GeditSpellCheckerDialog *dlg, GeditSpellChecker *spell) -{ - const GeditSpellCheckerLanguage* language; - const gchar *lang; - gchar *tmp; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (spell != NULL); - - if (dlg->spell_checker != NULL) - g_object_unref (dlg->spell_checker); - - dlg->spell_checker = spell; - g_object_ref (dlg->spell_checker); - - language = gedit_spell_checker_get_language (dlg->spell_checker); - - lang = gedit_spell_checker_language_to_string (language); - tmp = g_strdup_printf("%s", lang); - - gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp); - g_free (tmp); - - if (dlg->misspelled_word != NULL) - gedit_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1); - else - gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); - - /* TODO: reset all widgets */ -} - -void -gedit_spell_checker_dialog_set_misspelled_word (GeditSpellCheckerDialog *dlg, - const gchar *word, - gint len) -{ - gchar *tmp; - GSList *sug; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (word != NULL); - - g_return_if_fail (dlg->spell_checker != NULL); - g_return_if_fail (!gedit_spell_checker_check_word (dlg->spell_checker, word, -1)); - - /* build_suggestions_list */ - if (dlg->misspelled_word != NULL) - g_free (dlg->misspelled_word); - - dlg->misspelled_word = g_strdup (word); - - tmp = g_strdup_printf("%s", word); - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp); - g_free (tmp); - - sug = gedit_spell_checker_get_suggestions (dlg->spell_checker, - dlg->misspelled_word, - -1); - - update_suggestions_list_model (dlg, sug); - - /* free the suggestion list */ - g_slist_foreach (sug, (GFunc)g_free, NULL); - g_slist_free (sug); - - gtk_widget_set_sensitive (dlg->ignore_button, TRUE); - gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE); - gtk_widget_set_sensitive (dlg->add_word_button, TRUE); -} - -static void -update_suggestions_list_model (GeditSpellCheckerDialog *dlg, GSList *suggestions) -{ - GtkListStore *store; - GtkTreeIter iter; - GtkTreeSelection *sel; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model)); - - store = GTK_LIST_STORE (dlg->suggestions_list_model); - gtk_list_store_clear (store); - - gtk_widget_set_sensitive (dlg->word_entry, TRUE); - - if (suggestions == NULL) - { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions - * for the current misspelled word */ - COLUMN_SUGGESTIONS, _("(no suggested words)"), - -1); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); - - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); - - return; - } - - gtk_widget_set_sensitive (dlg->suggestions_list, TRUE); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data); - - while (suggestions != NULL) - { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_SUGGESTIONS, (gchar*)suggestions->data, - -1); - - suggestions = g_slist_next (suggestions); - } - - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); - gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter); - gtk_tree_selection_select_iter (sel, &iter); -} - -static void -word_entry_changed_handler (GtkEditable *editable, GeditSpellCheckerDialog *dlg) -{ - const gchar *text; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); - - if (g_utf8_strlen (text, -1) > 0) - { - gtk_widget_set_sensitive (dlg->check_word_button, TRUE); - gtk_widget_set_sensitive (dlg->change_button, TRUE); - gtk_widget_set_sensitive (dlg->change_all_button, TRUE); - } - else - { - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - } -} - -static void -close_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - gtk_widget_destroy (GTK_WIDGET (dlg)); -} - -static void -suggestions_list_selection_changed_handler (GtkTreeSelection *selection, - GeditSpellCheckerDialog *dlg) -{ - GtkTreeIter iter; - GValue value = {0, }; - const gchar *text; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) - return; - - gtk_tree_model_get_value (dlg->suggestions_list_model, &iter, - COLUMN_SUGGESTIONS, - &value); - - text = g_value_get_string (&value); - - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text); - - g_value_unset (&value); -} - -static void -check_word_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - const gchar *word; - gssize len; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); - len = strlen (word); - g_return_if_fail (len > 0); - - if (gedit_spell_checker_check_word (dlg->spell_checker, word, len)) - { - GtkListStore *store; - GtkTreeIter iter; - - store = GTK_LIST_STORE (dlg->suggestions_list_model); - gtk_list_store_clear (store); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - /* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */ - COLUMN_SUGGESTIONS, _("(correct spelling)"), - -1); - - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); - } - else - { - GSList *sug; - - sug = gedit_spell_checker_get_suggestions (dlg->spell_checker, - word, - len); - - update_suggestions_list_model (dlg, sug); - - /* free the suggestion list */ - g_slist_foreach (sug, (GFunc)g_free, NULL); - g_slist_free (sug); - } -} - -static void -add_word_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - gedit_spell_checker_add_word_to_personal (dlg->spell_checker, - dlg->misspelled_word, - -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word); - - g_free (word); -} - -static void -ignore_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word); - - g_free (word); -} - -static void -ignore_all_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - gedit_spell_checker_add_word_to_session (dlg->spell_checker, - dlg->misspelled_word, - -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word); - - g_free (word); -} - -static void -change_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - gchar *change; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); - g_return_if_fail (change != NULL); - g_return_if_fail (*change != '\0'); - - gedit_spell_checker_set_correction (dlg->spell_checker, - dlg->misspelled_word, -1, - change, -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change); - - g_free (word); - g_free (change); -} - -/* double click on one of the suggestions is like clicking on "change" */ -static void -suggestions_list_row_activated_handler (GtkTreeView *view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellCheckerDialog *dlg) -{ - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg); -} - -static void -change_all_button_clicked_handler (GtkButton *button, GeditSpellCheckerDialog *dlg) -{ - gchar *word; - gchar *change; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - g_return_if_fail (dlg->misspelled_word != NULL); - - change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); - g_return_if_fail (change != NULL); - g_return_if_fail (*change != '\0'); - - gedit_spell_checker_set_correction (dlg->spell_checker, - dlg->misspelled_word, -1, - change, -1); - - word = g_strdup (dlg->misspelled_word); - - g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change); - - g_free (word); - g_free (change); -} - -void -gedit_spell_checker_dialog_set_completed (GeditSpellCheckerDialog *dlg) -{ - gchar *tmp; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER_DIALOG (dlg)); - - tmp = g_strdup_printf("%s", _("Completed spell checking")); - gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), - tmp); - g_free (tmp); - - gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); - gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); - - gtk_widget_set_sensitive (dlg->word_entry, FALSE); - gtk_widget_set_sensitive (dlg->check_word_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_button, FALSE); - gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); - gtk_widget_set_sensitive (dlg->change_button, FALSE); - gtk_widget_set_sensitive (dlg->change_all_button, FALSE); - gtk_widget_set_sensitive (dlg->add_word_button, FALSE); - gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); -} - diff --git a/plugins/spell/gedit-spell-checker-dialog.h b/plugins/spell/gedit-spell-checker-dialog.h deleted file mode 100755 index 257c2b75..00000000 --- a/plugins/spell/gedit-spell-checker-dialog.h +++ /dev/null @@ -1,92 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-dialog.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_DIALOG_H__ -#define __GEDIT_SPELL_CHECKER_DIALOG_H__ - -#include -#include "gedit-spell-checker.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_CHECKER_DIALOG (gedit_spell_checker_dialog_get_type ()) -#define GEDIT_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) -#define GEDIT_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) -#define GEDIT_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG)) -#define GEDIT_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_CHECKER_DIALOG)) -#define GEDIT_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_SPELL_CHECKER_DIALOG, GeditSpellCheckerDialog)) - - -typedef struct _GeditSpellCheckerDialog GeditSpellCheckerDialog; - -typedef struct _GeditSpellCheckerDialogClass GeditSpellCheckerDialogClass; - -struct _GeditSpellCheckerDialogClass -{ - GtkWindowClass parent_class; - - /* Signals */ - void (*ignore) (GeditSpellCheckerDialog *dlg, - const gchar *word); - void (*ignore_all) (GeditSpellCheckerDialog *dlg, - const gchar *word); - void (*change) (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change_to); - void (*change_all) (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change_to); - void (*add_word_to_personal) (GeditSpellCheckerDialog *dlg, - const gchar *word); - -}; - -GType gedit_spell_checker_dialog_get_type (void) G_GNUC_CONST; - -/* Constructors */ -GtkWidget *gedit_spell_checker_dialog_new (const gchar *data_dir); -GtkWidget *gedit_spell_checker_dialog_new_from_spell_checker - (GeditSpellChecker *spell, - const gchar *data_dir); - -void gedit_spell_checker_dialog_set_spell_checker - (GeditSpellCheckerDialog *dlg, - GeditSpellChecker *spell); -void gedit_spell_checker_dialog_set_misspelled_word - (GeditSpellCheckerDialog *dlg, - const gchar* word, - gint len); - -void gedit_spell_checker_dialog_set_completed - (GeditSpellCheckerDialog *dlg); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_DIALOG_H__ */ - diff --git a/plugins/spell/gedit-spell-checker-language.c b/plugins/spell/gedit-spell-checker-language.c deleted file mode 100755 index ae7e2422..00000000 --- a/plugins/spell/gedit-spell-checker-language.c +++ /dev/null @@ -1,439 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-language.c - * This file is part of gedit - * - * Copyright (C) 2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -/* Part of the code taked from Epiphany. - * - * Copyright (C) 2003, 2004 Christian Persch - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "gedit-spell-checker-language.h" - -#include - -#define ISO_639_DOMAIN "iso_639" -#define ISO_3166_DOMAIN "iso_3166" - -#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale" - -struct _GeditSpellCheckerLanguage -{ - gchar *abrev; - gchar *name; -}; - -static gboolean available_languages_initialized = FALSE; -static GSList *available_languages = NULL; - -static GHashTable *iso_639_table = NULL; -static GHashTable *iso_3166_table = NULL; - -static void -bind_iso_domains (void) -{ - static gboolean bound = FALSE; - - if (bound == FALSE) - { - bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR); - bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8"); - - bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR); - bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8"); - - bound = TRUE; - } -} - -static void -read_iso_639_entry (xmlTextReaderPtr reader, - GHashTable *table) -{ - xmlChar *code, *name; - - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code"); - name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); - - /* Get iso-639-2 code */ - if (code == NULL || code[0] == '\0') - { - xmlFree (code); - /* FIXME: use the 2T or 2B code? */ - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code"); - } - - if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') - { - g_hash_table_insert (table, code, name); - } - else - { - xmlFree (code); - xmlFree (name); - } -} - -static void -read_iso_3166_entry (xmlTextReaderPtr reader, - GHashTable *table) -{ - xmlChar *code, *name; - - code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code"); - name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); - - if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') - { - char *lcode; - - lcode = g_ascii_strdown ((char *) code, -1); - xmlFree (code); - - /* g_print ("%s -> %s\n", lcode, name); */ - - g_hash_table_insert (table, lcode, name); - } - else - { - xmlFree (code); - xmlFree (name); - } -} - -typedef enum -{ - STATE_START, - STATE_STOP, - STATE_ENTRIES, -} ParserState; - -static void -load_iso_entries (int iso, - GFunc read_entry_func, - gpointer user_data) -{ - xmlTextReaderPtr reader; - ParserState state = STATE_START; - xmlChar iso_entries[32], iso_entry[32]; - char *filename; - int ret = -1; - - gedit_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso); - - filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso); - reader = xmlNewTextReaderFilename (filename); - if (reader == NULL) goto out; - - xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso); - xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso); - - ret = xmlTextReaderRead (reader); - - while (ret == 1) - { - const xmlChar *tag; - xmlReaderTypes type; - - tag = xmlTextReaderConstName (reader); - type = xmlTextReaderNodeType (reader); - - if (state == STATE_ENTRIES && - type == XML_READER_TYPE_ELEMENT && - xmlStrEqual (tag, iso_entry)) - { - read_entry_func (reader, user_data); - } - else if (state == STATE_START && - type == XML_READER_TYPE_ELEMENT && - xmlStrEqual (tag, iso_entries)) - { - state = STATE_ENTRIES; - } - else if (state == STATE_ENTRIES && - type == XML_READER_TYPE_END_ELEMENT && - xmlStrEqual (tag, iso_entries)) - { - state = STATE_STOP; - } - else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE || - type == XML_READER_TYPE_WHITESPACE || - type == XML_READER_TYPE_TEXT || - type == XML_READER_TYPE_COMMENT) - { - /* eat it */ - } - else - { - /* ignore it */ - } - - ret = xmlTextReaderRead (reader); - } - - xmlFreeTextReader (reader); - -out: - if (ret < 0 || state != STATE_STOP) - { - g_warning ("Failed to load ISO-%d codes from %s!\n", - iso, filename); - } - - g_free (filename); -} - -static GHashTable * -create_iso_639_table (void) -{ - GHashTable *table; - - bind_iso_domains (); - table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) xmlFree, - (GDestroyNotify) xmlFree); - - load_iso_entries (639, (GFunc) read_iso_639_entry, table); - - return table; -} - -static GHashTable * -create_iso_3166_table (void) -{ - GHashTable *table; - - bind_iso_domains (); - table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) xmlFree); - - load_iso_entries (3166, (GFunc) read_iso_3166_entry, table); - - return table; -} - -static char * -create_name_for_language (const char *code) -{ - char **str; - char *name = NULL; - const char *langname, *localename; - int len; - - g_return_val_if_fail (iso_639_table != NULL, NULL); - g_return_val_if_fail (iso_3166_table != NULL, NULL); - - str = g_strsplit (code, "_", -1); - len = g_strv_length (str); - g_return_val_if_fail (len != 0, NULL); - - langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]); - - if (len == 1 && langname != NULL) - { - name = g_strdup (dgettext (ISO_639_DOMAIN, langname)); - } - else if (len == 2 && langname != NULL) - { - gchar *locale_code = g_ascii_strdown (str[1], -1); - - localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code); - g_free (locale_code); - - if (localename != NULL) - { - /* Translators: the first %s is the language name, and - * the second %s is the locale name. Example: - * "French (France)" - */ - name = g_strdup_printf (C_("language", "%s (%s)"), - dgettext (ISO_639_DOMAIN, langname), - dgettext (ISO_3166_DOMAIN, localename)); - } - else - { - name = g_strdup_printf (C_("language", "%s (%s)"), - dgettext (ISO_639_DOMAIN, langname), str[1]); - } - } - else - { - /* Translators: this refers to an unknown language code - * (one which isn't in our built-in list). - */ - name = g_strdup_printf (C_("language", "Unknown (%s)"), code); - } - - g_strfreev (str); - - return name; -} - -static void -enumerate_dicts (const char * const lang_tag, - const char * const provider_name, - const char * const provider_desc, - const char * const provider_file, - void * user_data) -{ - gchar *lang_name; - - GTree *dicts = (GTree *)user_data; - - lang_name = create_name_for_language (lang_tag); - g_return_if_fail (lang_name != NULL); - - /* g_print ("%s - %s\n", lang_tag, lang_name); */ - - g_tree_replace (dicts, g_strdup (lang_tag), lang_name); -} - -static gint -key_cmp (gconstpointer a, gconstpointer b, gpointer user_data) -{ - return strcmp (a, b); -} - -static gint -lang_cmp (const GeditSpellCheckerLanguage *a, - const GeditSpellCheckerLanguage *b) -{ - return g_utf8_collate (a->name, b->name); -} - -static gboolean -build_langs_list (const gchar *key, - const gchar *value, - gpointer data) -{ - GeditSpellCheckerLanguage *lang = g_new (GeditSpellCheckerLanguage, 1); - - lang->abrev = g_strdup (key); - lang->name = g_strdup (value); - - available_languages = g_slist_insert_sorted (available_languages, - lang, - (GCompareFunc)lang_cmp); - - return FALSE; -} - -const GSList * -gedit_spell_checker_get_available_languages (void) -{ - EnchantBroker *broker; - GTree *dicts; - - if (available_languages_initialized) - return available_languages; - - g_return_val_if_fail (available_languages == NULL, NULL); - - available_languages_initialized = TRUE; - - broker = enchant_broker_init (); - g_return_val_if_fail (broker != NULL, NULL); - - /* Use a GTree to efficiently remove duplicates while building the list */ - dicts = g_tree_new_full (key_cmp, - NULL, - (GDestroyNotify)g_free, - (GDestroyNotify)g_free); - - iso_639_table = create_iso_639_table (); - iso_3166_table = create_iso_3166_table (); - - enchant_broker_list_dicts (broker, enumerate_dicts, dicts); - - enchant_broker_free (broker); - - g_hash_table_destroy (iso_639_table); - g_hash_table_destroy (iso_3166_table); - - iso_639_table = NULL; - iso_3166_table = NULL; - - g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL); - - g_tree_destroy (dicts); - - return available_languages; -} - -const gchar * -gedit_spell_checker_language_to_string (const GeditSpellCheckerLanguage *lang) -{ - if (lang == NULL) - /* Translators: this refers the Default language used by the - * spell checker - */ - return C_("language", "Default"); - - return lang->name; -} - -const gchar * -gedit_spell_checker_language_to_key (const GeditSpellCheckerLanguage *lang) -{ - g_return_val_if_fail (lang != NULL, NULL); - - return lang->abrev; -} - -const GeditSpellCheckerLanguage * -gedit_spell_checker_language_from_key (const gchar *key) -{ - const GSList *langs; - - g_return_val_if_fail (key != NULL, NULL); - - langs = gedit_spell_checker_get_available_languages (); - - while (langs != NULL) - { - const GeditSpellCheckerLanguage *l = (const GeditSpellCheckerLanguage *)langs->data; - - if (g_ascii_strcasecmp (key, l->abrev) == 0) - return l; - - langs = g_slist_next (langs); - } - - return NULL; -} diff --git a/plugins/spell/gedit-spell-checker-language.h b/plugins/spell/gedit-spell-checker-language.h deleted file mode 100755 index 7e62de65..00000000 --- a/plugins/spell/gedit-spell-checker-language.h +++ /dev/null @@ -1,51 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker-language.h - * This file is part of gedit - * - * Copyright (C) 2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_LANGUAGE_H__ -#define __GEDIT_SPELL_CHECKER_LANGUAGE_H__ - -#include - -G_BEGIN_DECLS - -typedef struct _GeditSpellCheckerLanguage GeditSpellCheckerLanguage; - -const gchar *gedit_spell_checker_language_to_string (const GeditSpellCheckerLanguage *lang); - -const gchar *gedit_spell_checker_language_to_key (const GeditSpellCheckerLanguage *lang); - -const GeditSpellCheckerLanguage *gedit_spell_checker_language_from_key (const gchar *key); - -/* GSList contains "GeditSpellCheckerLanguage*" items */ -const GSList *gedit_spell_checker_get_available_languages - (void); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_LANGUAGE_H__ */ diff --git a/plugins/spell/gedit-spell-checker.c b/plugins/spell/gedit-spell-checker.c deleted file mode 100755 index 51b8d8a8..00000000 --- a/plugins/spell/gedit-spell-checker.c +++ /dev/null @@ -1,520 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker.c - * This file is part of gedit - * - * Copyright (C) 2002-2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002-2006. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "gedit-spell-checker.h" -#include "gedit-spell-utils.h" -#include "gedit-spell-marshal.h" - -struct _GeditSpellChecker -{ - GObject parent_instance; - - EnchantDict *dict; - EnchantBroker *broker; - const GeditSpellCheckerLanguage *active_lang; -}; - -/* GObject properties */ -enum { - PROP_0 = 0, - PROP_LANGUAGE, - LAST_PROP -}; - -/* Signals */ -enum { - ADD_WORD_TO_PERSONAL = 0, - ADD_WORD_TO_SESSION, - SET_LANGUAGE, - CLEAR_SESSION, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(GeditSpellChecker, gedit_spell_checker, G_TYPE_OBJECT) - -static void -gedit_spell_checker_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - /* - GeditSpellChecker *spell = GEDIT_SPELL_CHECKER (object); - */ - - switch (prop_id) - { - case PROP_LANGUAGE: - /* TODO */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gedit_spell_checker_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - /* - GeditSpellChecker *spell = GEDIT_SPELL_CHECKER (object); - */ - - switch (prop_id) - { - case PROP_LANGUAGE: - /* TODO */ - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gedit_spell_checker_finalize (GObject *object) -{ - GeditSpellChecker *spell_checker; - - g_return_if_fail (GEDIT_IS_SPELL_CHECKER (object)); - - spell_checker = GEDIT_SPELL_CHECKER (object); - - if (spell_checker->dict != NULL) - enchant_broker_free_dict (spell_checker->broker, spell_checker->dict); - - if (spell_checker->broker != NULL) - enchant_broker_free (spell_checker->broker); - - G_OBJECT_CLASS (gedit_spell_checker_parent_class)->finalize (object); -} - -static void -gedit_spell_checker_class_init (GeditSpellCheckerClass * klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = gedit_spell_checker_set_property; - object_class->get_property = gedit_spell_checker_get_property; - - object_class->finalize = gedit_spell_checker_finalize; - - g_object_class_install_property (object_class, - PROP_LANGUAGE, - g_param_spec_pointer ("language", - "Language", - "The language used by the spell checker", - G_PARAM_READWRITE)); - - signals[ADD_WORD_TO_PERSONAL] = - g_signal_new ("add_word_to_personal", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, add_word_to_personal), - NULL, NULL, - gedit_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - signals[ADD_WORD_TO_SESSION] = - g_signal_new ("add_word_to_session", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, add_word_to_session), - NULL, NULL, - gedit_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - signals[SET_LANGUAGE] = - g_signal_new ("set_language", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, set_language), - NULL, NULL, - gedit_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[CLEAR_SESSION] = - g_signal_new ("clear_session", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GeditSpellCheckerClass, clear_session), - NULL, NULL, - gedit_marshal_VOID__VOID, - G_TYPE_NONE, - 0); -} - -static void -gedit_spell_checker_init (GeditSpellChecker *spell_checker) -{ - spell_checker->broker = enchant_broker_init (); - spell_checker->dict = NULL; - spell_checker->active_lang = NULL; -} - -GeditSpellChecker * -gedit_spell_checker_new (void) -{ - GeditSpellChecker *spell; - - spell = GEDIT_SPELL_CHECKER ( - g_object_new (GEDIT_TYPE_SPELL_CHECKER, NULL)); - - g_return_val_if_fail (spell != NULL, NULL); - - return spell; -} - -static gboolean -lazy_init (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *language) -{ - if (spell->dict != NULL) - return TRUE; - - g_return_val_if_fail (spell->broker != NULL, FALSE); - - spell->active_lang = NULL; - - if (language != NULL) - { - spell->active_lang = language; - } - else - { - /* First try to get a default language */ - const GeditSpellCheckerLanguage *l; - gint i = 0; - const gchar * const *lang_tags = g_get_language_names (); - - while (lang_tags [i]) - { - l = gedit_spell_checker_language_from_key (lang_tags [i]); - - if (l != NULL) - { - spell->active_lang = l; - break; - } - - i++; - } - } - - /* Second try to get a default language */ - if (spell->active_lang == NULL) - spell->active_lang = gedit_spell_checker_language_from_key ("en_US"); - - /* Last try to get a default language */ - if (spell->active_lang == NULL) - { - const GSList *langs; - langs = gedit_spell_checker_get_available_languages (); - if (langs != NULL) - spell->active_lang = (const GeditSpellCheckerLanguage *)langs->data; - } - - if (spell->active_lang != NULL) - { - const gchar *key; - - key = gedit_spell_checker_language_to_key (spell->active_lang); - - spell->dict = enchant_broker_request_dict (spell->broker, - key); - } - - if (spell->dict == NULL) - { - spell->active_lang = NULL; - - if (language != NULL) - g_warning ("Spell checker plugin: cannot select a default language."); - - return FALSE; - } - - return TRUE; -} - -gboolean -gedit_spell_checker_set_language (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *language) -{ - gboolean ret; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - - if (spell->dict != NULL) - { - enchant_broker_free_dict (spell->broker, spell->dict); - spell->dict = NULL; - } - - ret = lazy_init (spell, language); - - if (ret) - g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language); - else - g_warning ("Spell checker plugin: cannot use language %s.", - gedit_spell_checker_language_to_string (language)); - - return ret; -} - -const GeditSpellCheckerLanguage * -gedit_spell_checker_get_language (GeditSpellChecker *spell) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), NULL); - - if (!lazy_init (spell, spell->active_lang)) - return NULL; - - return spell->active_lang; -} - -gboolean -gedit_spell_checker_check_word (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - gint enchant_result; - gboolean res = FALSE; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - if (len < 0) - len = strlen (word); - - if (strcmp (word, "gedit") == 0) - return TRUE; - - if (gedit_spell_utils_is_digit (word, len)) - return TRUE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - enchant_result = enchant_dict_check (spell->dict, word, len); - - switch (enchant_result) - { - case -1: - /* error */ - res = FALSE; - - g_warning ("Spell checker plugin: error checking word '%s' (%s).", - word, enchant_dict_get_error (spell->dict)); - - break; - case 1: - /* it is not in the directory */ - res = FALSE; - break; - case 0: - /* is is in the directory */ - res = TRUE; - break; - default: - g_return_val_if_reached (FALSE); - } - - return res; -} - - -/* return NULL on error or if no suggestions are found */ -GSList * -gedit_spell_checker_get_suggestions (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - gchar **suggestions; - size_t n_suggestions = 0; - GSList *suggestions_list = NULL; - gint i; - - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), NULL); - g_return_val_if_fail (word != NULL, NULL); - - if (!lazy_init (spell, spell->active_lang)) - return NULL; - - g_return_val_if_fail (spell->dict != NULL, NULL); - - if (len < 0) - len = strlen (word); - - suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions); - - if (n_suggestions == 0) - return NULL; - - g_return_val_if_fail (suggestions != NULL, NULL); - - for (i = 0; i < (gint)n_suggestions; i++) - { - suggestions_list = g_slist_prepend (suggestions_list, - suggestions[i]); - } - - /* The single suggestions will be freed by the caller */ - g_free (suggestions); - - suggestions_list = g_slist_reverse (suggestions_list); - - return suggestions_list; -} - -gboolean -gedit_spell_checker_add_word_to_personal (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (len < 0) - len = strlen (word); - - enchant_dict_add_to_pwl (spell->dict, word, len); - - g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len); - - return TRUE; -} - -gboolean -gedit_spell_checker_add_word_to_session (GeditSpellChecker *spell, - const gchar *word, - gssize len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (len < 0) - len = strlen (word); - - enchant_dict_add_to_session (spell->dict, word, len); - - g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len); - - return TRUE; -} - -gboolean -gedit_spell_checker_clear_session (GeditSpellChecker *spell) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - - /* free and re-request dictionary */ - if (spell->dict != NULL) - { - enchant_broker_free_dict (spell->broker, spell->dict); - spell->dict = NULL; - } - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0); - - return TRUE; -} - -/* - * Informs dictionary, that word 'word' will be replaced/corrected by word - * 'replacement' - */ -gboolean -gedit_spell_checker_set_correction (GeditSpellChecker *spell, - const gchar *word, - gssize w_len, - const gchar *replacement, - gssize r_len) -{ - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (spell), FALSE); - g_return_val_if_fail (word != NULL, FALSE); - g_return_val_if_fail (replacement != NULL, FALSE); - - if (!lazy_init (spell, spell->active_lang)) - return FALSE; - - g_return_val_if_fail (spell->dict != NULL, FALSE); - - if (w_len < 0) - w_len = strlen (word); - - if (r_len < 0) - r_len = strlen (replacement); - - enchant_dict_store_replacement (spell->dict, - word, - w_len, - replacement, - r_len); - - return TRUE; -} - diff --git a/plugins/spell/gedit-spell-checker.h b/plugins/spell/gedit-spell-checker.h deleted file mode 100755 index 0cc69d31..00000000 --- a/plugins/spell/gedit-spell-checker.h +++ /dev/null @@ -1,109 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-checker.h - * This file is part of gedit - * - * Copyright (C) 2002-2006 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_CHECKER_H__ -#define __GEDIT_SPELL_CHECKER_H__ - -#include -#include - -#include "gedit-spell-checker-language.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_CHECKER (gedit_spell_checker_get_type ()) -#define GEDIT_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) -#define GEDIT_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) -#define GEDIT_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_SPELL_CHECKER)) -#define GEDIT_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_CHECKER)) -#define GEDIT_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_SPELL_CHECKER, GeditSpellChecker)) - -typedef struct _GeditSpellChecker GeditSpellChecker; - -typedef struct _GeditSpellCheckerClass GeditSpellCheckerClass; - -struct _GeditSpellCheckerClass -{ - GObjectClass parent_class; - - /* Signals */ - void (*add_word_to_personal) (GeditSpellChecker *spell, - const gchar *word, - gint len); - - void (*add_word_to_session) (GeditSpellChecker *spell, - const gchar *word, - gint len); - - void (*set_language) (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang); - - void (*clear_session) (GeditSpellChecker *spell); -}; - - -GType gedit_spell_checker_get_type (void) G_GNUC_CONST; - -/* Constructors */ -GeditSpellChecker *gedit_spell_checker_new (void); - -gboolean gedit_spell_checker_set_language (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang); -const GeditSpellCheckerLanguage - *gedit_spell_checker_get_language (GeditSpellChecker *spell); - -gboolean gedit_spell_checker_check_word (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -GSList *gedit_spell_checker_get_suggestions (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_add_word_to_personal - (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_add_word_to_session - (GeditSpellChecker *spell, - const gchar *word, - gssize len); - -gboolean gedit_spell_checker_clear_session (GeditSpellChecker *spell); - -gboolean gedit_spell_checker_set_correction (GeditSpellChecker *spell, - const gchar *word, - gssize w_len, - const gchar *replacement, - gssize r_len); -G_END_DECLS - -#endif /* __GEDIT_SPELL_CHECKER_H__ */ - diff --git a/plugins/spell/gedit-spell-language-dialog.c b/plugins/spell/gedit-spell-language-dialog.c deleted file mode 100755 index 1abba17f..00000000 --- a/plugins/spell/gedit-spell-language-dialog.c +++ /dev/null @@ -1,309 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-language-dialog.c - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include "gedit-spell-language-dialog.h" -#include "gedit-spell-checker-language.h" - - -enum -{ - COLUMN_LANGUAGE_NAME = 0, - COLUMN_LANGUAGE_POINTER, - ENCODING_NUM_COLS -}; - - -struct _GeditSpellLanguageDialog -{ - GtkDialog dialog; - - GtkWidget *languages_treeview; - GtkTreeModel *model; -}; - -G_DEFINE_TYPE(GeditSpellLanguageDialog, gedit_spell_language_dialog, GTK_TYPE_DIALOG) - - -static void -gedit_spell_language_dialog_class_init (GeditSpellLanguageDialogClass *klass) -{ - /* GObjectClass *object_class = G_OBJECT_CLASS (klass); */ -} - -static void -dialog_response_handler (GtkDialog *dlg, - gint res_id) -{ - if (res_id == GTK_RESPONSE_HELP) - { - gedit_help_display (GTK_WINDOW (dlg), - NULL, - "gedit-spell-checker-plugin"); - - g_signal_stop_emission_by_name (dlg, "response"); - } -} - -static void -scroll_to_selected (GtkTreeView *tree_view) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (tree_view); - g_return_if_fail (model != NULL); - - /* Scroll to selected */ - selection = gtk_tree_view_get_selection (tree_view); - g_return_if_fail (selection != NULL); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - GtkTreePath* path; - - path = gtk_tree_model_get_path (model, &iter); - g_return_if_fail (path != NULL); - - gtk_tree_view_scroll_to_cell (tree_view, - path, NULL, TRUE, 1.0, 0.0); - gtk_tree_path_free (path); - } -} - -static void -language_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditSpellLanguageDialog *dialog) -{ - gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); -} - -static void -create_dialog (GeditSpellLanguageDialog *dlg, - const gchar *data_dir) -{ - GtkWidget *error_widget; - GtkWidget *content; - gboolean ret; - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - gchar *ui_file; - gchar *root_objects[] = { - "content", - NULL - }; - - gtk_dialog_add_buttons (GTK_DIALOG (dlg), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - GTK_STOCK_HELP, - GTK_RESPONSE_HELP, - NULL); - - gtk_window_set_title (GTK_WINDOW (dlg), _("Set language")); - gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE); - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE); - - /* HIG defaults */ - gtk_container_set_border_width (GTK_CONTAINER (dlg), 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - 2); /* 2 * 5 + 2 = 12 */ - gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), - 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), - 6); - - g_signal_connect (dlg, - "response", - G_CALLBACK (dialog_response_handler), - NULL); - - ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - root_objects, - &error_widget, - "content", &content, - "languages_treeview", &dlg->languages_treeview, - NULL); - g_free (ui_file); - - if (!ret) - { - gtk_widget_show (error_widget); - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - error_widget, - TRUE, TRUE, 0); - - return; - } - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - content, TRUE, TRUE, 0); - g_object_unref (content); - gtk_container_set_border_width (GTK_CONTAINER (content), 5); - - dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, - G_TYPE_STRING, - G_TYPE_POINTER)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), - dlg->model); - - g_object_unref (dlg->model); - - /* Add the encoding column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Languages"), - cell, - "text", - COLUMN_LANGUAGE_NAME, - NULL); - - gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), - column); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), - COLUMN_LANGUAGE_NAME); - - g_signal_connect (dlg->languages_treeview, - "realize", - G_CALLBACK (scroll_to_selected), - dlg); - g_signal_connect (dlg->languages_treeview, - "row-activated", - G_CALLBACK (language_row_activated), - dlg); -} - -static void -gedit_spell_language_dialog_init (GeditSpellLanguageDialog *dlg) -{ - -} - -static void -populate_language_list (GeditSpellLanguageDialog *dlg, - const GeditSpellCheckerLanguage *cur_lang) -{ - GtkListStore *store; - GtkTreeIter iter; - - const GSList* langs; - - /* create list store */ - store = GTK_LIST_STORE (dlg->model); - - langs = gedit_spell_checker_get_available_languages (); - - while (langs) - { - const gchar *name; - - name = gedit_spell_checker_language_to_string ((const GeditSpellCheckerLanguage*)langs->data); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_LANGUAGE_NAME, name, - COLUMN_LANGUAGE_POINTER, langs->data, - -1); - - if (langs->data == cur_lang) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); - g_return_if_fail (selection != NULL); - - gtk_tree_selection_select_iter (selection, &iter); - } - - langs = g_slist_next (langs); - } -} - -GtkWidget * -gedit_spell_language_dialog_new (GtkWindow *parent, - const GeditSpellCheckerLanguage *cur_lang, - const gchar *data_dir) -{ - GeditSpellLanguageDialog *dlg; - - g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); - - dlg = g_object_new (GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, NULL); - - create_dialog (dlg, data_dir); - - populate_language_list (dlg, cur_lang); - - gtk_window_set_transient_for (GTK_WINDOW (dlg), parent); - gtk_widget_grab_focus (dlg->languages_treeview); - - return GTK_WIDGET (dlg); -} - -const GeditSpellCheckerLanguage * -gedit_spell_language_get_selected_language (GeditSpellLanguageDialog *dlg) -{ - GValue value = {0, }; - const GeditSpellCheckerLanguage* lang; - - GtkTreeIter iter; - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); - g_return_val_if_fail (selection != NULL, NULL); - - if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) - return NULL; - - gtk_tree_model_get_value (dlg->model, - &iter, - COLUMN_LANGUAGE_POINTER, - &value); - - lang = (const GeditSpellCheckerLanguage* ) g_value_get_pointer (&value); - - return lang; -} - diff --git a/plugins/spell/gedit-spell-language-dialog.h b/plugins/spell/gedit-spell-language-dialog.h deleted file mode 100755 index 4ae9c97d..00000000 --- a/plugins/spell/gedit-spell-language-dialog.h +++ /dev/null @@ -1,67 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * gedit-spell-language-dialog.h - * This file is part of gedit - * - * Copyright (C) 2002 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifndef __GEDIT_SPELL_LANGUAGE_DIALOG_H__ -#define __GEDIT_SPELL_LANGUAGE_DIALOG_H__ - -#include -#include "gedit-spell-checker-language.h" - -G_BEGIN_DECLS - -#define GEDIT_TYPE_SPELL_LANGUAGE_DIALOG (gedit_spell_language_dialog_get_type()) -#define GEDIT_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialog)) -#define GEDIT_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialogClass)) -#define GEDIT_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG)) -#define GEDIT_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG)) -#define GEDIT_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_SPELL_LANGUAGE_DIALOG, GeditSpellLanguageDialogClass)) - - -typedef struct _GeditSpellLanguageDialog GeditSpellLanguageDialog; - -typedef struct _GeditSpellLanguageDialogClass GeditSpellLanguageDialogClass; - -struct _GeditSpellLanguageDialogClass -{ - GtkDialogClass parent_class; -}; - -GType gedit_spell_language_dialog_get_type (void) G_GNUC_CONST; - -GtkWidget *gedit_spell_language_dialog_new (GtkWindow *parent, - const GeditSpellCheckerLanguage *cur_lang, - const gchar *data_dir); - -const GeditSpellCheckerLanguage * - gedit_spell_language_get_selected_language (GeditSpellLanguageDialog *dlg); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_LANGUAGE_DIALOG_H__ */ - diff --git a/plugins/spell/gedit-spell-marshal.list b/plugins/spell/gedit-spell-marshal.list deleted file mode 100755 index 007dcf7d..00000000 --- a/plugins/spell/gedit-spell-marshal.list +++ /dev/null @@ -1,6 +0,0 @@ -VOID:STRING -VOID:STRING,STRING -VOID:STRING,INT -VOID:POINTER -VOID:VOID - diff --git a/plugins/spell/gedit-spell-plugin.c b/plugins/spell/gedit-spell-plugin.c deleted file mode 100755 index 6ef78e75..00000000 --- a/plugins/spell/gedit-spell-plugin.c +++ /dev/null @@ -1,1217 +0,0 @@ -/* - * gedit-spell-plugin.c - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-spell-plugin.h" -#include "gedit-spell-utils.h" - -#include /* For strlen */ - -#include -#include - -#include -#include -#include - -#include "gedit-spell-checker.h" -#include "gedit-spell-checker-dialog.h" -#include "gedit-spell-language-dialog.h" -#include "gedit-automatic-spell-checker.h" - -#ifdef G_OS_WIN32 -#include -#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "spell-language" -#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "spell-enabled" -#else -#define GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::gedit-spell-language" -#define GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::gedit-spell-enabled" -#endif - -#define WINDOW_DATA_KEY "GeditSpellPluginWindowData" -#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1" - -#define GEDIT_SPELL_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GEDIT_TYPE_SPELL_PLUGIN, \ - GeditSpellPluginPrivate)) - -GEDIT_PLUGIN_REGISTER_TYPE(GeditSpellPlugin, gedit_spell_plugin) - -typedef struct -{ - GtkActionGroup *action_group; - guint ui_id; - guint message_cid; - gulong tab_added_id; - gulong tab_removed_id; -} WindowData; - -typedef struct -{ - GeditPlugin *plugin; - GeditWindow *window; -} ActionData; - -static void spell_cb (GtkAction *action, ActionData *action_data); -static void set_language_cb (GtkAction *action, ActionData *action_data); -static void auto_spell_cb (GtkAction *action, GeditWindow *window); - -/* UI actions. */ -static const GtkActionEntry action_entries[] = -{ - { "CheckSpell", - GTK_STOCK_SPELL_CHECK, - N_("_Check Spelling..."), - "F7", - N_("Check the current document for incorrect spelling"), - G_CALLBACK (spell_cb) - }, - - { "ConfigSpell", - NULL, - N_("Set _Language..."), - NULL, - N_("Set the language of the current document"), - G_CALLBACK (set_language_cb) - } -}; - -static const GtkToggleActionEntry toggle_action_entries[] = -{ - { "AutoSpell", - NULL, - N_("_Autocheck Spelling"), - NULL, - N_("Automatically spell-check the current document"), - G_CALLBACK (auto_spell_cb), - FALSE - } -}; - -typedef struct _CheckRange CheckRange; - -struct _CheckRange -{ - GtkTextMark *start_mark; - GtkTextMark *end_mark; - - gint mw_start; /* misspelled word start */ - gint mw_end; /* end */ - - GtkTextMark *current_mark; -}; - -static GQuark spell_checker_id = 0; -static GQuark check_range_id = 0; - -static void -gedit_spell_plugin_init (GeditSpellPlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin initializing"); -} - -static void -gedit_spell_plugin_finalize (GObject *object) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin finalizing"); - - G_OBJECT_CLASS (gedit_spell_plugin_parent_class)->finalize (object); -} - -static void -set_spell_language_cb (GeditSpellChecker *spell, - const GeditSpellCheckerLanguage *lang, - GeditDocument *doc) -{ - const gchar *key; - - g_return_if_fail (GEDIT_IS_DOCUMENT (doc)); - g_return_if_fail (lang != NULL); - - key = gedit_spell_checker_language_to_key (lang); - g_return_if_fail (key != NULL); - - gedit_document_set_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE, - key, NULL); -} - -static void -set_language_from_metadata (GeditSpellChecker *spell, - GeditDocument *doc) -{ - const GeditSpellCheckerLanguage *lang = NULL; - gchar *value = NULL; - - value = gedit_document_get_metadata (doc, GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE); - - if (value != NULL) - { - lang = gedit_spell_checker_language_from_key (value); - g_free (value); - } - - if (lang != NULL) - { - g_signal_handlers_block_by_func (spell, set_spell_language_cb, doc); - gedit_spell_checker_set_language (spell, lang); - g_signal_handlers_unblock_by_func (spell, set_spell_language_cb, doc); - } -} - -static GeditSpellChecker * -get_spell_checker_from_document (GeditDocument *doc) -{ - GeditSpellChecker *spell; - gpointer data; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - - data = g_object_get_qdata (G_OBJECT (doc), spell_checker_id); - - if (data == NULL) - { - spell = gedit_spell_checker_new (); - - set_language_from_metadata (spell, doc); - - g_object_set_qdata_full (G_OBJECT (doc), - spell_checker_id, - spell, - (GDestroyNotify) g_object_unref); - - g_signal_connect (spell, - "set_language", - G_CALLBACK (set_spell_language_cb), - doc); - } - else - { - g_return_val_if_fail (GEDIT_IS_SPELL_CHECKER (data), NULL); - spell = GEDIT_SPELL_CHECKER (data); - } - - return spell; -} - -static CheckRange * -get_check_range (GeditDocument *doc) -{ - CheckRange *range; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - - range = (CheckRange *) g_object_get_qdata (G_OBJECT (doc), check_range_id); - - return range; -} - -static void -update_current (GeditDocument *doc, - gint current) -{ - CheckRange *range; - GtkTextIter iter; - GtkTextIter end_iter; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (doc != NULL); - g_return_if_fail (current >= 0); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), - &iter, current); - - if (!gtk_text_iter_inside_word (&iter)) - { - /* if we're not inside a word, - * we must be in some spaces. - * skip forward to the beginning of the next word. */ - if (!gtk_text_iter_is_end (&iter)) - { - gtk_text_iter_forward_word_end (&iter); - gtk_text_iter_backward_word_start (&iter); - } - } - else - { - if (!gtk_text_iter_starts_word (&iter)) - gtk_text_iter_backward_word_start (&iter); - } - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - &end_iter, - range->end_mark); - - if (gtk_text_iter_compare (&end_iter, &iter) < 0) - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->current_mark, - &end_iter); - } - else - { - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->current_mark, - &iter); - } -} - -static void -set_check_range (GeditDocument *doc, - GtkTextIter *start, - GtkTextIter *end) -{ - CheckRange *range; - GtkTextIter iter; - - gedit_debug (DEBUG_PLUGINS); - - range = get_check_range (doc); - - if (range == NULL) - { - gedit_debug_message (DEBUG_PLUGINS, "There was not a previous check range"); - - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter); - - range = g_new0 (CheckRange, 1); - - range->start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_start_mark", &iter, TRUE); - - range->end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_end_mark", &iter, FALSE); - - range->current_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), - "check_range_current_mark", &iter, TRUE); - - g_object_set_qdata_full (G_OBJECT (doc), - check_range_id, - range, - (GDestroyNotify)g_free); - } - - if (gedit_spell_utils_skip_no_spell_check (start, end)) - { - if (!gtk_text_iter_inside_word (end)) - { - /* if we're neither inside a word, - * we must be in some spaces. - * skip backward to the end of the previous word. */ - if (!gtk_text_iter_is_end (end)) - { - gtk_text_iter_backward_word_start (end); - gtk_text_iter_forward_word_end (end); - } - } - else - { - if (!gtk_text_iter_ends_word (end)) - gtk_text_iter_forward_word_end (end); - } - } - else - { - /* no spell checking in the specified range */ - start = end; - } - - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->start_mark, - start); - gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), - range->end_mark, - end); - - range->mw_start = -1; - range->mw_end = -1; - - update_current (doc, gtk_text_iter_get_offset (start)); -} - -static gchar * -get_current_word (GeditDocument *doc, gint *start, gint *end) -{ - const CheckRange *range; - GtkTextIter end_iter; - GtkTextIter current_iter; - gint range_end; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, NULL); - g_return_val_if_fail (start != NULL, NULL); - g_return_val_if_fail (end != NULL, NULL); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, NULL); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - &end_iter, range->end_mark); - - range_end = gtk_text_iter_get_offset (&end_iter); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - ¤t_iter, range->current_mark); - - end_iter = current_iter; - - if (!gtk_text_iter_is_end (&end_iter)) - { - gedit_debug_message (DEBUG_PLUGINS, "Current is not end"); - - gtk_text_iter_forward_word_end (&end_iter); - } - - *start = gtk_text_iter_get_offset (¤t_iter); - *end = MIN (gtk_text_iter_get_offset (&end_iter), range_end); - - gedit_debug_message (DEBUG_PLUGINS, "Current word extends [%d, %d]", *start, *end); - - if (!(*start < *end)) - return NULL; - - return gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), - ¤t_iter, - &end_iter, - TRUE); -} - -static gboolean -goto_next_word (GeditDocument *doc) -{ - CheckRange *range; - GtkTextIter current_iter; - GtkTextIter old_current_iter; - GtkTextIter end_iter; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (doc != NULL, FALSE); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, FALSE); - - gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), - ¤t_iter, - range->current_mark); - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end_iter); - - old_current_iter = current_iter; - - gtk_text_iter_forward_word_ends (¤t_iter, 2); - gtk_text_iter_backward_word_start (¤t_iter); - - if (gedit_spell_utils_skip_no_spell_check (¤t_iter, &end_iter) && - (gtk_text_iter_compare (&old_current_iter, ¤t_iter) < 0) && - (gtk_text_iter_compare (¤t_iter, &end_iter) < 0)) - { - update_current (doc, gtk_text_iter_get_offset (¤t_iter)); - return TRUE; - } - - return FALSE; -} - -static gchar * -get_next_misspelled_word (GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gint start, end; - gchar *word; - GeditSpellChecker *spell; - - g_return_val_if_fail (view != NULL, NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_val_if_fail (doc != NULL, NULL); - - range = get_check_range (doc); - g_return_val_if_fail (range != NULL, NULL); - - spell = get_spell_checker_from_document (doc); - g_return_val_if_fail (spell != NULL, NULL); - - word = get_current_word (doc, &start, &end); - if (word == NULL) - return NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); - - while (gedit_spell_checker_check_word (spell, word, -1)) - { - g_free (word); - - if (!goto_next_word (doc)) - return NULL; - - /* may return null if we reached the end of the selection */ - word = get_current_word (doc, &start, &end); - if (word == NULL) - return NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); - } - - if (!goto_next_word (doc)) - update_current (doc, gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc))); - - if (word != NULL) - { - GtkTextIter s, e; - - range->mw_start = start; - range->mw_end = end; - - gedit_debug_message (DEBUG_PLUGINS, "Select [%d, %d]", start, end); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &s, start); - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &e, end); - - gtk_text_buffer_select_range (GTK_TEXT_BUFFER (doc), &s, &e); - - gedit_view_scroll_to_cursor (view); - } - else - { - range->mw_start = -1; - range->mw_end = -1; - } - - return word; -} - -static void -ignore_cb (GeditSpellCheckerDialog *dlg, - const gchar *w, - GeditView *view) -{ - gchar *word = NULL; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (w != NULL); - g_return_if_fail (view != NULL); - - word = get_next_misspelled_word (view); - if (word == NULL) - { - gedit_spell_checker_dialog_set_completed (dlg); - - return; - } - - gedit_spell_checker_dialog_set_misspelled_word (GEDIT_SPELL_CHECKER_DIALOG (dlg), - word, - -1); - - g_free (word); -} - -static void -change_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change, - GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gchar *w = NULL; - GtkTextIter start, end; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - g_return_if_fail (change != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); - if (range->mw_end < 0) - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); - else - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); - - w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); - g_return_if_fail (w != NULL); - - if (strcmp (w, word) != 0) - { - g_free (w); - return; - } - - g_free (w); - - gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER(doc)); - - gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), &start, &end); - gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &start, change, -1); - - gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER(doc)); - - update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -change_all_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - const gchar *change, - GeditView *view) -{ - GeditDocument *doc; - CheckRange *range; - gchar *w = NULL; - GtkTextIter start, end; - gint flags = 0; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - g_return_if_fail (change != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - range = get_check_range (doc); - g_return_if_fail (range != NULL); - - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); - if (range->mw_end < 0) - gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); - else - gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); - - w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); - g_return_if_fail (w != NULL); - - if (strcmp (w, word) != 0) - { - g_free (w); - return; - } - - g_free (w); - - GEDIT_SEARCH_SET_CASE_SENSITIVE (flags, TRUE); - GEDIT_SEARCH_SET_ENTIRE_WORD (flags, TRUE); - - /* CHECK: currently this function does escaping etc */ - gedit_document_replace_all (doc, word, change, flags); - - update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -add_word_cb (GeditSpellCheckerDialog *dlg, - const gchar *word, - GeditView *view) -{ - g_return_if_fail (view != NULL); - g_return_if_fail (word != NULL); - - /* go to next misspelled word */ - ignore_cb (dlg, word, view); -} - -static void -language_dialog_response (GtkDialog *dlg, - gint res_id, - GeditSpellChecker *spell) -{ - if (res_id == GTK_RESPONSE_OK) - { - const GeditSpellCheckerLanguage *lang; - - lang = gedit_spell_language_get_selected_language (GEDIT_SPELL_LANGUAGE_DIALOG (dlg)); - if (lang != NULL) - gedit_spell_checker_set_language (spell, lang); - } - - gtk_widget_destroy (GTK_WIDGET (dlg)); -} - -static void -set_language_cb (GtkAction *action, - ActionData *action_data) -{ - GeditDocument *doc; - GeditSpellChecker *spell; - const GeditSpellCheckerLanguage *lang; - GtkWidget *dlg; - GtkWindowGroup *wg; - gchar *data_dir; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (action_data->window); - g_return_if_fail (doc != NULL); - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - lang = gedit_spell_checker_get_language (spell); - - data_dir = gedit_plugin_get_data_dir (action_data->plugin); - dlg = gedit_spell_language_dialog_new (GTK_WINDOW (action_data->window), - lang, - data_dir); - g_free (data_dir); - - wg = gedit_window_get_group (action_data->window); - - gtk_window_group_add_window (wg, GTK_WINDOW (dlg)); - - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - - g_signal_connect (dlg, - "response", - G_CALLBACK (language_dialog_response), - spell); - - gtk_widget_show (dlg); -} - -static void -spell_cb (GtkAction *action, - ActionData *action_data) -{ - GeditView *view; - GeditDocument *doc; - GeditSpellChecker *spell; - GtkWidget *dlg; - GtkTextIter start, end; - gchar *word; - gchar *data_dir; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (action_data->window); - g_return_if_fail (view != NULL); - - doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - g_return_if_fail (doc != NULL); - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - if (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)) <= 0) - { - WindowData *data; - GtkWidget *statusbar; - - data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - statusbar = gedit_window_get_statusbar (action_data->window); - gedit_statusbar_flash_message (GEDIT_STATUSBAR (statusbar), - data->message_cid, - _("The document is empty.")); - - return; - } - - if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end)) - { - /* no selection, get the whole doc */ - gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), - &start, - &end); - } - - set_check_range (doc, &start, &end); - - word = get_next_misspelled_word (view); - if (word == NULL) - { - WindowData *data; - GtkWidget *statusbar; - - data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), - WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - statusbar = gedit_window_get_statusbar (action_data->window); - gedit_statusbar_flash_message (GEDIT_STATUSBAR (statusbar), - data->message_cid, - _("No misspelled words")); - - return; - } - - data_dir = gedit_plugin_get_data_dir (action_data->plugin); - dlg = gedit_spell_checker_dialog_new_from_spell_checker (spell, data_dir); - g_free (data_dir); - gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); - gtk_window_set_transient_for (GTK_WINDOW (dlg), - GTK_WINDOW (action_data->window)); - - g_signal_connect (dlg, "ignore", G_CALLBACK (ignore_cb), view); - g_signal_connect (dlg, "ignore_all", G_CALLBACK (ignore_cb), view); - - g_signal_connect (dlg, "change", G_CALLBACK (change_cb), view); - g_signal_connect (dlg, "change_all", G_CALLBACK (change_all_cb), view); - - g_signal_connect (dlg, "add_word_to_personal", G_CALLBACK (add_word_cb), view); - - gedit_spell_checker_dialog_set_misspelled_word (GEDIT_SPELL_CHECKER_DIALOG (dlg), - word, - -1); - - g_free (word); - - gtk_widget_show (dlg); -} - -static void -set_auto_spell (GeditWindow *window, - GeditDocument *doc, - gboolean active) -{ - GeditAutomaticSpellChecker *autospell; - GeditSpellChecker *spell; - - spell = get_spell_checker_from_document (doc); - g_return_if_fail (spell != NULL); - - autospell = gedit_automatic_spell_checker_get_from_document (doc); - - if (active) - { - if (autospell == NULL) - { - GeditView *active_view; - - active_view = gedit_window_get_active_view (window); - g_return_if_fail (active_view != NULL); - - autospell = gedit_automatic_spell_checker_new (doc, spell); - gedit_automatic_spell_checker_attach_view (autospell, active_view); - gedit_automatic_spell_checker_recheck_all (autospell); - } - } - else - { - if (autospell != NULL) - gedit_automatic_spell_checker_free (autospell); - } -} - -static void -auto_spell_cb (GtkAction *action, - GeditWindow *window) -{ - - GeditDocument *doc; - gboolean active; - - gedit_debug (DEBUG_PLUGINS); - - active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); - - gedit_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated"); - - doc = gedit_window_get_active_document (window); - if (doc == NULL) - return; - - gedit_document_set_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED, - active ? "1" : NULL, NULL); - - set_auto_spell (window, doc, active); -} - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - g_object_unref (data->action_group); - g_slice_free (WindowData, data); -} - -static void -free_action_data (gpointer data) -{ - g_return_if_fail (data != NULL); - - g_slice_free (ActionData, data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GeditDocument *doc; - GeditView *view; - gboolean autospell; - GtkAction *action; - - gedit_debug (DEBUG_PLUGINS); - - doc = gedit_window_get_active_document (window); - view = gedit_window_get_active_view (window); - - autospell = (doc != NULL && - gedit_automatic_spell_checker_get_from_document (doc) != NULL); - - if (doc != NULL) - { - GeditTab *tab; - GeditTabState state; - - tab = gedit_window_get_active_tab (window); - state = gedit_tab_get_state (tab); - - /* If the document is loading we can't get the metadata so we - endup with an useless speller */ - if (state == GEDIT_TAB_STATE_NORMAL) - { - action = gtk_action_group_get_action (data->action_group, - "AutoSpell"); - - g_signal_handlers_block_by_func (action, auto_spell_cb, - window); - set_auto_spell (window, doc, autospell); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - autospell); - g_signal_handlers_unblock_by_func (action, auto_spell_cb, - window); - } - } - - gtk_action_group_set_sensitive (data->action_group, - (view != NULL) && - gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); -} - -static void -set_auto_spell_from_metadata (GeditWindow *window, - GeditDocument *doc, - GtkActionGroup *action_group) -{ - gboolean active = FALSE; - gchar *active_str; - GeditDocument *active_doc; - - active_str = gedit_document_get_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED); - - if (active_str) - { - active = *active_str == '1'; - - g_free (active_str); - } - - set_auto_spell (window, doc, active); - - /* In case that the doc is the active one we mark the spell action */ - active_doc = gedit_window_get_active_document (window); - - if (active_doc == doc && action_group != NULL) - { - GtkAction *action; - - action = gtk_action_group_get_action (action_group, - "AutoSpell"); - - g_signal_handlers_block_by_func (action, auto_spell_cb, - window); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), - active); - g_signal_handlers_unblock_by_func (action, auto_spell_cb, - window); - } -} - -static void -on_document_loaded (GeditDocument *doc, - const GError *error, - GeditWindow *window) -{ - if (error == NULL) - { - WindowData *data; - GeditSpellChecker *spell; - - spell = GEDIT_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), - spell_checker_id)); - if (spell != NULL) - { - set_language_from_metadata (spell, doc); - } - - data = g_object_get_data (G_OBJECT (window), - WINDOW_DATA_KEY); - - set_auto_spell_from_metadata (window, doc, data->action_group); - } -} - -static void -on_document_saved (GeditDocument *doc, - const GError *error, - GeditWindow *window) -{ - GeditAutomaticSpellChecker *autospell; - GeditSpellChecker *spell; - const gchar *key; - - if (error != NULL) - { - return; - } - - /* Make sure to save the metadata here too */ - autospell = gedit_automatic_spell_checker_get_from_document (doc); - spell = GEDIT_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id)); - - if (spell != NULL) - { - key = gedit_spell_checker_language_to_key (gedit_spell_checker_get_language (spell)); - } - else - { - key = NULL; - } - - gedit_document_set_metadata (doc, - GEDIT_METADATA_ATTRIBUTE_SPELL_ENABLED, - autospell != NULL ? "1" : NULL, - GEDIT_METADATA_ATTRIBUTE_SPELL_LANGUAGE, - key, - NULL); -} - -static void -tab_added_cb (GeditWindow *window, - GeditTab *tab, - gpointer useless) -{ - GeditDocument *doc; - GeditView *view; - - doc = gedit_tab_get_document (tab); - view = gedit_tab_get_view (tab); - - g_signal_connect (doc, "loaded", - G_CALLBACK (on_document_loaded), - window); - - g_signal_connect (doc, "saved", - G_CALLBACK (on_document_saved), - window); -} - -static void -tab_removed_cb (GeditWindow *window, - GeditTab *tab, - gpointer useless) -{ - GeditDocument *doc; - GeditView *view; - - doc = gedit_tab_get_document (tab); - view = gedit_tab_get_view (tab); - - g_signal_handlers_disconnect_by_func (doc, on_document_loaded, window); - g_signal_handlers_disconnect_by_func (doc, on_document_saved, window); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - ActionData *action_data; - GList *docs, *l; - - gedit_debug (DEBUG_PLUGINS); - - data = g_slice_new (WindowData); - action_data = g_slice_new (ActionData); - action_data->plugin = plugin; - action_data->window = window; - - manager = gedit_window_get_ui_manager (window); - - data->action_group = gtk_action_group_new ("GeditSpellPluginActions"); - gtk_action_group_set_translation_domain (data->action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions_full (data->action_group, - action_entries, - G_N_ELEMENTS (action_entries), - action_data, - (GDestroyNotify) free_action_data); - gtk_action_group_add_toggle_actions (data->action_group, - toggle_action_entries, - G_N_ELEMENTS (toggle_action_entries), - window); - - gtk_ui_manager_insert_action_group (manager, data->action_group, -1); - - data->ui_id = gtk_ui_manager_new_merge_id (manager); - - data->message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (gedit_window_get_statusbar (window)), - "spell_plugin_message"); - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "CheckSpell", - "CheckSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "AutoSpell", - "AutoSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "ConfigSpell", - "ConfigSpell", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - update_ui_real (window, data); - - docs = gedit_window_get_documents (window); - for (l = docs; l != NULL; l = g_list_next (l)) - { - GeditDocument *doc = GEDIT_DOCUMENT (l->data); - - set_auto_spell_from_metadata (window, doc, - data->action_group); - - g_signal_handlers_disconnect_by_func (doc, - on_document_loaded, - window); - - g_signal_handlers_disconnect_by_func (doc, - on_document_saved, - window); - } - - data->tab_added_id = - g_signal_connect (window, "tab-added", - G_CALLBACK (tab_added_cb), NULL); - data->tab_removed_id = - g_signal_connect (window, "tab-removed", - G_CALLBACK (tab_removed_cb), NULL); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, data->ui_id); - gtk_ui_manager_remove_action_group (manager, data->action_group); - - g_signal_handler_disconnect (window, data->tab_added_id); - g_signal_handler_disconnect (window, data->tab_removed_id); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, data); -} - -static void -gedit_spell_plugin_class_init (GeditSpellPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_spell_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; - - if (spell_checker_id == 0) - spell_checker_id = g_quark_from_string ("GeditSpellCheckerID"); - - if (check_range_id == 0) - check_range_id = g_quark_from_string ("CheckRangeID"); -} diff --git a/plugins/spell/gedit-spell-plugin.h b/plugins/spell/gedit-spell-plugin.h deleted file mode 100755 index 7de5807a..00000000 --- a/plugins/spell/gedit-spell-plugin.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * gedit-spell-plugin.h - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_SPELL_PLUGIN_H__ -#define __GEDIT_SPELL_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_SPELL_PLUGIN (gedit_spell_plugin_get_type ()) -#define GEDIT_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPlugin)) -#define GEDIT_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPluginClass)) -#define GEDIT_IS_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_SPELL_PLUGIN)) -#define GEDIT_IS_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_SPELL_PLUGIN)) -#define GEDIT_SPELL_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_SPELL_PLUGIN, GeditSpellPluginClass)) - -/* Private structure type */ -typedef struct _GeditSpellPluginPrivate GeditSpellPluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditSpellPlugin GeditSpellPlugin; - -struct _GeditSpellPlugin -{ - GeditPlugin parent_instance; -}; - -/* - * Class definition - */ -typedef struct _GeditSpellPluginClass GeditSpellPluginClass; - -struct _GeditSpellPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_spell_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_PLUGIN_H__ */ diff --git a/plugins/spell/gedit-spell-utils.c b/plugins/spell/gedit-spell-utils.c deleted file mode 100755 index 0782d37a..00000000 --- a/plugins/spell/gedit-spell-utils.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * gedit-spell-utils.c - * This file is part of gedit - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include - -#include "gedit-spell-utils.h" -#include - -gboolean -gedit_spell_utils_is_digit (const char *text, gssize length) -{ - gunichar c; - const gchar *p; - const gchar *end; - - g_return_val_if_fail (text != NULL, FALSE); - - if (length < 0) - length = strlen (text); - - p = text; - end = text + length; - - while (p != end) { - const gchar *next; - next = g_utf8_next_char (p); - - c = g_utf8_get_char (p); - - if (!g_unichar_isdigit (c) && c != '.' && c != ',') - return FALSE; - - p = next; - } - - return TRUE; -} - -gboolean -gedit_spell_utils_skip_no_spell_check (GtkTextIter *start, - GtkTextIter *end) -{ - GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start)); - - while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check")) - { - GtkTextIter last = *start; - - if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check")) - { - return FALSE; - } - - if (gtk_text_iter_compare (start, &last) <= 0) - { - return FALSE; - } - - gtk_text_iter_forward_word_end (start); - gtk_text_iter_backward_word_start (start); - - if (gtk_text_iter_compare (start, &last) <= 0) - { - return FALSE; - } - - if (gtk_text_iter_compare (start, end) >= 0) - { - return FALSE; - } - } - - return TRUE; -} - diff --git a/plugins/spell/gedit-spell-utils.h b/plugins/spell/gedit-spell-utils.h deleted file mode 100755 index fbfe4b1b..00000000 --- a/plugins/spell/gedit-spell-utils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * gedit-spell-utils.h - * This file is part of gedit - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GEDIT_SPELL_UTILS_H__ -#define __GEDIT_SPELL_UTILS_H__ - -#include - -G_BEGIN_DECLS - -gboolean gedit_spell_utils_is_digit (const char *text, gssize length); - -gboolean gedit_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end); - -G_END_DECLS - -#endif /* __GEDIT_SPELL_UTILS_H__ */ - diff --git a/plugins/spell/pluma-automatic-spell-checker.c b/plugins/spell/pluma-automatic-spell-checker.c new file mode 100755 index 00000000..88393379 --- /dev/null +++ b/plugins/spell/pluma-automatic-spell-checker.c @@ -0,0 +1,1015 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-automatic-spell-checker.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* This is a modified version of gtkspell 2.0.5 (gtkspell.sf.net) */ +/* gtkspell - a spell-checking addon for GTK's TextView widget + * Copyright (c) 2002 Evan Martin. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include "pluma-automatic-spell-checker.h" +#include "pluma-spell-utils.h" + +struct _PlumaAutomaticSpellChecker { + PlumaDocument *doc; + GSList *views; + + GtkTextMark *mark_insert_start; + GtkTextMark *mark_insert_end; + gboolean deferred_check; + + GtkTextTag *tag_highlight; + GtkTextMark *mark_click; + + PlumaSpellChecker *spell_checker; +}; + +static GQuark automatic_spell_checker_id = 0; +static GQuark suggestion_id = 0; + +static void pluma_automatic_spell_checker_free_internal (PlumaAutomaticSpellChecker *spell); + +static void +view_destroy (PlumaView *view, PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_detach_view (spell, view); +} + +static void +check_word (PlumaAutomaticSpellChecker *spell, GtkTextIter *start, GtkTextIter *end) +{ + gchar *word; + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), start, end, FALSE); + + /* + g_print ("Check word: %s [%d - %d]\n", word, gtk_text_iter_get_offset (start), + gtk_text_iter_get_offset (end)); + */ + + if (!pluma_spell_checker_check_word (spell->spell_checker, word, -1)) + { + /* + g_print ("Apply tag: [%d - %d]\n", gtk_text_iter_get_offset (start), + gtk_text_iter_get_offset (end)); + */ + gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + start, + end); + } + + g_free (word); +} + +static void +check_range (PlumaAutomaticSpellChecker *spell, + GtkTextIter start, + GtkTextIter end, + gboolean force_all) +{ + /* we need to "split" on word boundaries. + * luckily, Pango knows what "words" are + * so we don't have to figure it out. */ + + GtkTextIter wstart; + GtkTextIter wend; + GtkTextIter cursor; + GtkTextIter precursor; + gboolean highlight; + + /* + g_print ("Check range: [%d - %d]\n", gtk_text_iter_get_offset (&start), + gtk_text_iter_get_offset (&end)); + */ + + if (gtk_text_iter_inside_word (&end)) + gtk_text_iter_forward_word_end (&end); + + if (!gtk_text_iter_starts_word (&start)) + { + if (gtk_text_iter_inside_word (&start) || + gtk_text_iter_ends_word (&start)) + { + gtk_text_iter_backward_word_start (&start); + } + else + { + /* if we're neither at the beginning nor inside a word, + * me must be in some spaces. + * skip forward to the beginning of the next word. */ + + if (gtk_text_iter_forward_word_end (&start)) + gtk_text_iter_backward_word_start (&start); + } + } + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &cursor, + gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (spell->doc))); + + precursor = cursor; + gtk_text_iter_backward_char (&precursor); + + highlight = gtk_text_iter_has_tag (&cursor, spell->tag_highlight) || + gtk_text_iter_has_tag (&precursor, spell->tag_highlight); + + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &start, + &end); + + /* Fix a corner case when replacement occurs at beginning of buffer: + * An iter at offset 0 seems to always be inside a word, + * even if it's not. Possibly a pango bug. + */ + if (gtk_text_iter_get_offset (&start) == 0) + { + gtk_text_iter_forward_word_end(&start); + gtk_text_iter_backward_word_start(&start); + } + + wstart = start; + + while (pluma_spell_utils_skip_no_spell_check (&wstart, &end) && + gtk_text_iter_compare (&wstart, &end) < 0) + { + gboolean inword; + + /* move wend to the end of the current word. */ + wend = wstart; + + gtk_text_iter_forward_word_end (&wend); + + inword = (gtk_text_iter_compare (&wstart, &cursor) < 0) && + (gtk_text_iter_compare (&cursor, &wend) <= 0); + + if (inword && !force_all) + { + /* this word is being actively edited, + * only check if it's already highligted, + * otherwise defer this check until later. */ + if (highlight) + check_word (spell, &wstart, &wend); + else + spell->deferred_check = TRUE; + } + else + { + check_word (spell, &wstart, &wend); + spell->deferred_check = FALSE; + } + + /* now move wend to the beginning of the next word, */ + gtk_text_iter_forward_word_end (&wend); + gtk_text_iter_backward_word_start (&wend); + + /* make sure we've actually advanced + * (we don't advance in some corner cases), */ + if (gtk_text_iter_equal (&wstart, &wend)) + break; /* we're done in these cases.. */ + + /* and then pick this as the new next word beginning. */ + wstart = wend; + } +} + +static void +check_deferred_range (PlumaAutomaticSpellChecker *spell, + gboolean force_all) +{ + GtkTextIter start, end; + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &start, + spell->mark_insert_start); + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (spell->doc), + &end, + spell->mark_insert_end); + + check_range (spell, start, end, force_all); +} + +/* insertion works like this: + * - before the text is inserted, we mark the position in the buffer. + * - after the text is inserted, we see where our mark is and use that and + * the current position to check the entire range of inserted text. + * + * this may be overkill for the common case (inserting one character). */ + +static void +insert_text_before (GtkTextBuffer *buffer, GtkTextIter *iter, + gchar *text, gint len, PlumaAutomaticSpellChecker *spell) +{ + gtk_text_buffer_move_mark (buffer, spell->mark_insert_start, iter); +} + +static void +insert_text_after (GtkTextBuffer *buffer, GtkTextIter *iter, + gchar *text, gint len, PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter start; + + /* we need to check a range of text. */ + gtk_text_buffer_get_iter_at_mark (buffer, &start, spell->mark_insert_start); + + check_range (spell, start, *iter, FALSE); + + gtk_text_buffer_move_mark (buffer, spell->mark_insert_end, iter); +} + +/* deleting is more simple: we're given the range of deleted text. + * after deletion, the start and end iters should be at the same position + * (because all of the text between them was deleted!). + * this means we only really check the words immediately bounding the + * deletion. + */ + +static void +delete_range_after (GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, + PlumaAutomaticSpellChecker *spell) +{ + check_range (spell, *start, *end, FALSE); +} + +static void +mark_set (GtkTextBuffer *buffer, + GtkTextIter *iter, + GtkTextMark *mark, + PlumaAutomaticSpellChecker *spell) +{ + /* if the cursor has moved and there is a deferred check so handle it now */ + if ((mark == gtk_text_buffer_get_insert (buffer)) && spell->deferred_check) + check_deferred_range (spell, FALSE); +} + +static void +get_word_extents_from_mark (GtkTextBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end, + GtkTextMark *mark) +{ + gtk_text_buffer_get_iter_at_mark(buffer, start, mark); + + if (!gtk_text_iter_starts_word (start)) + gtk_text_iter_backward_word_start (start); + + *end = *start; + + if (gtk_text_iter_inside_word (end)) + gtk_text_iter_forward_word_end (end); +} + +static void +remove_tag_to_word (PlumaAutomaticSpellChecker *spell, const gchar *word) +{ + GtkTextIter iter; + GtkTextIter match_start, match_end; + + gboolean found; + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (spell->doc), &iter, 0); + + found = TRUE; + + while (found) + { + found = gtk_text_iter_forward_search (&iter, + word, + GTK_TEXT_SEARCH_VISIBLE_ONLY | GTK_TEXT_SEARCH_TEXT_ONLY, + &match_start, + &match_end, + NULL); + + if (found) + { + if (gtk_text_iter_starts_word (&match_start) && + gtk_text_iter_ends_word (&match_end)) + { + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &match_start, + &match_end); + } + + iter = match_end; + } + } +} + +static void +add_to_dictionary (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *word; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), + &start, + &end, + FALSE); + + pluma_spell_checker_add_word_to_personal (spell->spell_checker, word, -1); + + g_free (word); +} + +static void +ignore_all (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *word; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), + &start, + &end, + FALSE); + + pluma_spell_checker_add_word_to_session (spell->spell_checker, word, -1); + + g_free (word); +} + +static void +replace_word (GtkWidget *menuitem, PlumaAutomaticSpellChecker *spell) +{ + gchar *oldword; + const gchar *newword; + + GtkTextIter start, end; + + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + oldword = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); + + newword = g_object_get_qdata (G_OBJECT (menuitem), suggestion_id); + g_return_if_fail (newword != NULL); + + gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER (spell->doc)); + + gtk_text_buffer_delete (GTK_TEXT_BUFFER (spell->doc), &start, &end); + gtk_text_buffer_insert (GTK_TEXT_BUFFER (spell->doc), &start, newword, -1); + + gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER (spell->doc)); + + pluma_spell_checker_set_correction (spell->spell_checker, + oldword, strlen (oldword), + newword, strlen (newword)); + + g_free (oldword); +} + +static GtkWidget * +build_suggestion_menu (PlumaAutomaticSpellChecker *spell, const gchar *word) +{ + GtkWidget *topmenu, *menu; + GtkWidget *mi; + GSList *suggestions; + GSList *list; + gchar *label_text; + + topmenu = menu = gtk_menu_new(); + + suggestions = pluma_spell_checker_get_suggestions (spell->spell_checker, word, -1); + + list = suggestions; + + if (suggestions == NULL) + { + /* no suggestions. put something in the menu anyway... */ + GtkWidget *label; + /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions for the current misspelled word */ + label = gtk_label_new (_("(no suggested words)")); + + mi = gtk_menu_item_new (); + gtk_widget_set_sensitive (mi, FALSE); + gtk_container_add (GTK_CONTAINER(mi), label); + gtk_widget_show_all (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); + } + else + { + gint count = 0; + + /* build a set of menus with suggestions. */ + while (suggestions != NULL) + { + GtkWidget *label; + + if (count == 10) + { + /* Separator */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + mi = gtk_menu_item_new_with_mnemonic (_("_More...")); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu); + count = 0; + } + + label_text = g_strdup_printf ("%s", (gchar*) suggestions->data); + + label = gtk_label_new (label_text); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + mi = gtk_menu_item_new (); + gtk_container_add (GTK_CONTAINER(mi), label); + + gtk_widget_show_all (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); + + g_object_set_qdata_full (G_OBJECT (mi), + suggestion_id, + g_strdup (suggestions->data), + (GDestroyNotify)g_free); + + g_free (label_text); + g_signal_connect (mi, + "activate", + G_CALLBACK (replace_word), + spell); + + count++; + + suggestions = g_slist_next (suggestions); + } + } + + /* free the suggestion list */ + suggestions = list; + + while (list) + { + g_free (list->data); + list = g_slist_next (list); + } + + g_slist_free (suggestions); + + /* Separator */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + /* Ignore all */ + mi = gtk_image_menu_item_new_with_mnemonic (_("_Ignore All")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), + gtk_image_new_from_stock (GTK_STOCK_GOTO_BOTTOM, + GTK_ICON_SIZE_MENU)); + + g_signal_connect (mi, + "activate", + G_CALLBACK(ignore_all), + spell); + + gtk_widget_show_all (mi); + + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + /* + Add to Dictionary */ + mi = gtk_image_menu_item_new_with_mnemonic (_("_Add")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), + gtk_image_new_from_stock (GTK_STOCK_ADD, + GTK_ICON_SIZE_MENU)); + + g_signal_connect (mi, + "activate", + G_CALLBACK (add_to_dictionary), + spell); + + gtk_widget_show_all (mi); + + gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi); + + return topmenu; +} + +static void +populate_popup (GtkTextView *textview, GtkMenu *menu, PlumaAutomaticSpellChecker *spell) +{ + GtkWidget *img, *mi; + GtkTextIter start, end; + char *word; + + /* we need to figure out if they picked a misspelled word. */ + get_word_extents_from_mark (GTK_TEXT_BUFFER (spell->doc), &start, &end, spell->mark_click); + + /* if our highlight algorithm ever messes up, + * this isn't correct, either. */ + if (!gtk_text_iter_has_tag (&start, spell->tag_highlight)) + return; /* word wasn't misspelled. */ + + /* menu separator comes first. */ + mi = gtk_menu_item_new (); + gtk_widget_show (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); + + /* then, on top of it, the suggestions menu. */ + img = gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); + mi = gtk_image_menu_item_new_with_mnemonic (_("_Spelling Suggestions...")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), img); + + word = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (spell->doc), &start, &end, FALSE); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), + build_suggestion_menu (spell, word)); + g_free(word); + + gtk_widget_show_all (mi); + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); +} + +void +pluma_automatic_spell_checker_recheck_all (PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter start, end; + + g_return_if_fail (spell != NULL); + + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), &start, &end); + + check_range (spell, start, end, TRUE); +} + +static void +add_word_signal_cb (PlumaSpellChecker *checker, + const gchar *word, + gint len, + PlumaAutomaticSpellChecker *spell) +{ + gchar *w; + + if (len < 0) + w = g_strdup (word); + else + w = g_strndup (word, len); + + remove_tag_to_word (spell, w); + + g_free (w); +} + +static void +set_language_cb (PlumaSpellChecker *checker, + const PlumaSpellCheckerLanguage *lang, + PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_recheck_all (spell); +} + +static void +clear_session_cb (PlumaSpellChecker *checker, + PlumaAutomaticSpellChecker *spell) +{ + pluma_automatic_spell_checker_recheck_all (spell); +} + +/* When the user right-clicks on a word, they want to check that word. + * Here, we do NOT move the cursor to the location of the clicked-upon word + * since that prevents the use of edit functions on the context menu. + */ +static gboolean +button_press_event (GtkTextView *view, + GdkEventButton *event, + PlumaAutomaticSpellChecker *spell) +{ + if (event->button == 3) + { + gint x, y; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer (view); + + /* handle deferred check if it exists */ + if (spell->deferred_check) + check_deferred_range (spell, TRUE); + + gtk_text_view_window_to_buffer_coords (view, + GTK_TEXT_WINDOW_TEXT, + event->x, event->y, + &x, &y); + + gtk_text_view_get_iter_at_location (view, &iter, x, y); + + gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); + } + + return FALSE; /* false: let gtk process this event, too. + we don't want to eat any events. */ +} + +/* Move the insert mark before popping up the menu, otherwise it + * will contain the wrong set of suggestions. + */ +static gboolean +popup_menu_event (GtkTextView *view, PlumaAutomaticSpellChecker *spell) +{ + GtkTextIter iter; + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer (view); + + /* handle deferred check if it exists */ + if (spell->deferred_check) + check_deferred_range (spell, TRUE); + + gtk_text_buffer_get_iter_at_mark (buffer, &iter, + gtk_text_buffer_get_insert (buffer)); + gtk_text_buffer_move_mark (buffer, spell->mark_click, &iter); + + return FALSE; +} + +static void +tag_table_changed (GtkTextTagTable *table, + PlumaAutomaticSpellChecker *spell) +{ + g_return_if_fail (spell->tag_highlight != NULL); + + gtk_text_tag_set_priority (spell->tag_highlight, + gtk_text_tag_table_get_size (table) - 1); +} + +static void +tag_added_or_removed (GtkTextTagTable *table, + GtkTextTag *tag, + PlumaAutomaticSpellChecker *spell) +{ + tag_table_changed (table, spell); +} + +static void +tag_changed (GtkTextTagTable *table, + GtkTextTag *tag, + gboolean size_changed, + PlumaAutomaticSpellChecker *spell) +{ + tag_table_changed (table, spell); +} + +static void +highlight_updated (GtkSourceBuffer *buffer, + GtkTextIter *start, + GtkTextIter *end, + PlumaAutomaticSpellChecker *spell) +{ + check_range (spell, *start, *end, FALSE); +} + +static void +spell_tag_destroyed (PlumaAutomaticSpellChecker *spell, + GObject *where_the_object_was) +{ + spell->tag_highlight = NULL; +} + +PlumaAutomaticSpellChecker * +pluma_automatic_spell_checker_new (PlumaDocument *doc, + PlumaSpellChecker *checker) +{ + PlumaAutomaticSpellChecker *spell; + GtkTextTagTable *tag_table; + GtkTextIter start, end; + + g_return_val_if_fail (PLUMA_IS_DOCUMENT (doc), NULL); + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (checker), NULL); + g_return_val_if_fail ((spell = pluma_automatic_spell_checker_get_from_document (doc)) == NULL, + spell); + + /* attach to the widget */ + spell = g_new0 (PlumaAutomaticSpellChecker, 1); + + spell->doc = doc; + spell->spell_checker = g_object_ref (checker); + + if (automatic_spell_checker_id == 0) + { + automatic_spell_checker_id = + g_quark_from_string ("PlumaAutomaticSpellCheckerID"); + } + if (suggestion_id == 0) + { + suggestion_id = g_quark_from_string ("PlumaAutoSuggestionID"); + } + + g_object_set_qdata_full (G_OBJECT (doc), + automatic_spell_checker_id, + spell, + (GDestroyNotify)pluma_automatic_spell_checker_free_internal); + + g_signal_connect (doc, + "insert-text", + G_CALLBACK (insert_text_before), + spell); + g_signal_connect_after (doc, + "insert-text", + G_CALLBACK (insert_text_after), + spell); + g_signal_connect_after (doc, + "delete-range", + G_CALLBACK (delete_range_after), + spell); + g_signal_connect (doc, + "mark-set", + G_CALLBACK (mark_set), + spell); + + g_signal_connect (doc, + "highlight-updated", + G_CALLBACK (highlight_updated), + spell); + + g_signal_connect (spell->spell_checker, + "add_word_to_session", + G_CALLBACK (add_word_signal_cb), + spell); + g_signal_connect (spell->spell_checker, + "add_word_to_personal", + G_CALLBACK (add_word_signal_cb), + spell); + g_signal_connect (spell->spell_checker, + "clear_session", + G_CALLBACK (clear_session_cb), + spell); + g_signal_connect (spell->spell_checker, + "set_language", + G_CALLBACK (set_language_cb), + spell); + + spell->tag_highlight = gtk_text_buffer_create_tag ( + GTK_TEXT_BUFFER (doc), + "gtkspell-misspelled", + "underline", PANGO_UNDERLINE_ERROR, + NULL); + + g_object_weak_ref (G_OBJECT (spell->tag_highlight), + (GWeakNotify)spell_tag_destroyed, + spell); + + tag_table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (doc)); + + gtk_text_tag_set_priority (spell->tag_highlight, + gtk_text_tag_table_get_size (tag_table) - 1); + + g_signal_connect (tag_table, + "tag-added", + G_CALLBACK (tag_added_or_removed), + spell); + g_signal_connect (tag_table, + "tag-removed", + G_CALLBACK (tag_added_or_removed), + spell); + g_signal_connect (tag_table, + "tag-changed", + G_CALLBACK (tag_changed), + spell); + + /* we create the mark here, but we don't use it until text is + * inserted, so we don't really care where iter points. */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), &start, &end); + + spell->mark_insert_start = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-start"); + + if (spell->mark_insert_start == NULL) + { + spell->mark_insert_start = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-start", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_insert_start, + &start); + } + + spell->mark_insert_end = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-end"); + + if (spell->mark_insert_end == NULL) + { + spell->mark_insert_end = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-insert-end", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_insert_end, + &start); + } + + spell->mark_click = gtk_text_buffer_get_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-click"); + + if (spell->mark_click == NULL) + { + spell->mark_click = + gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "pluma-automatic-spell-checker-click", + &start, + TRUE); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + spell->mark_click, + &start); + } + + spell->deferred_check = FALSE; + + return spell; +} + +PlumaAutomaticSpellChecker * +pluma_automatic_spell_checker_get_from_document (const PlumaDocument *doc) +{ + g_return_val_if_fail (PLUMA_IS_DOCUMENT (doc), NULL); + + if (automatic_spell_checker_id == 0) + return NULL; + + return g_object_get_qdata (G_OBJECT (doc), automatic_spell_checker_id); +} + +void +pluma_automatic_spell_checker_free (PlumaAutomaticSpellChecker *spell) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (pluma_automatic_spell_checker_get_from_document (spell->doc) == spell); + + if (automatic_spell_checker_id == 0) + return; + + g_object_set_qdata (G_OBJECT (spell->doc), automatic_spell_checker_id, NULL); +} + +static void +pluma_automatic_spell_checker_free_internal (PlumaAutomaticSpellChecker *spell) +{ + GtkTextTagTable *table; + GtkTextIter start, end; + GSList *list; + + g_return_if_fail (spell != NULL); + + table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (spell->doc)); + + if (table != NULL && spell->tag_highlight != NULL) + { + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (spell->doc), + &start, + &end); + gtk_text_buffer_remove_tag (GTK_TEXT_BUFFER (spell->doc), + spell->tag_highlight, + &start, + &end); + + g_signal_handlers_disconnect_matched (G_OBJECT (table), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + gtk_text_tag_table_remove (table, spell->tag_highlight); + } + + g_signal_handlers_disconnect_matched (G_OBJECT (spell->doc), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (spell->spell_checker), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_object_unref (spell->spell_checker); + + list = spell->views; + while (list != NULL) + { + PlumaView *view = PLUMA_VIEW (list->data); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + list = g_slist_next (list); + } + + g_slist_free (spell->views); + + g_free (spell); +} + +void +pluma_automatic_spell_checker_attach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (PLUMA_IS_VIEW (view)); + + g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == + GTK_TEXT_BUFFER (spell->doc)); + + g_signal_connect (view, + "button-press-event", + G_CALLBACK (button_press_event), + spell); + g_signal_connect (view, + "popup-menu", + G_CALLBACK (popup_menu_event), + spell); + g_signal_connect (view, + "populate-popup", + G_CALLBACK (populate_popup), + spell); + g_signal_connect (view, + "destroy", + G_CALLBACK (view_destroy), + spell); + + spell->views = g_slist_prepend (spell->views, view); +} + +void +pluma_automatic_spell_checker_detach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view) +{ + g_return_if_fail (spell != NULL); + g_return_if_fail (PLUMA_IS_VIEW (view)); + + g_return_if_fail (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)) == + GTK_TEXT_BUFFER (spell->doc)); + g_return_if_fail (spell->views != NULL); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + g_signal_handlers_disconnect_matched (G_OBJECT (view), + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + spell); + + spell->views = g_slist_remove (spell->views, view); +} + diff --git a/plugins/spell/pluma-automatic-spell-checker.h b/plugins/spell/pluma-automatic-spell-checker.h new file mode 100755 index 00000000..3a5f2487 --- /dev/null +++ b/plugins/spell/pluma-automatic-spell-checker.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-automatic-spell-checker.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* This is a modified version of gtkspell 2.0.2 (gtkspell.sf.net) */ +/* gtkspell - a spell-checking addon for GTK's TextView widget + * Copyright (c) 2002 Evan Martin. + */ + +#ifndef __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ +#define __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ + +#include +#include + +#include "pluma-spell-checker.h" + +typedef struct _PlumaAutomaticSpellChecker PlumaAutomaticSpellChecker; + +PlumaAutomaticSpellChecker *pluma_automatic_spell_checker_new ( + PlumaDocument *doc, + PlumaSpellChecker *checker); + +PlumaAutomaticSpellChecker *pluma_automatic_spell_checker_get_from_document ( + const PlumaDocument *doc); + +void pluma_automatic_spell_checker_free ( + PlumaAutomaticSpellChecker *spell); + +void pluma_automatic_spell_checker_attach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view); + +void pluma_automatic_spell_checker_detach_view ( + PlumaAutomaticSpellChecker *spell, + PlumaView *view); + +void pluma_automatic_spell_checker_recheck_all ( + PlumaAutomaticSpellChecker *spell); + +#endif /* __PLUMA_AUTOMATIC_SPELL_CHECKER_H__ */ + diff --git a/plugins/spell/pluma-spell-checker-dialog.c b/plugins/spell/pluma-spell-checker-dialog.c new file mode 100755 index 00000000..067e79e7 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-dialog.c @@ -0,0 +1,722 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-dialog.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "pluma-spell-checker-dialog.h" +#include "pluma-spell-marshal.h" + +struct _PlumaSpellCheckerDialog +{ + GtkWindow parent_instance; + + PlumaSpellChecker *spell_checker; + + gchar *misspelled_word; + + GtkWidget *misspelled_word_label; + GtkWidget *word_entry; + GtkWidget *check_word_button; + GtkWidget *ignore_button; + GtkWidget *ignore_all_button; + GtkWidget *change_button; + GtkWidget *change_all_button; + GtkWidget *add_word_button; + GtkWidget *close_button; + GtkWidget *suggestions_list; + GtkWidget *language_label; + + GtkTreeModel *suggestions_list_model; +}; + +enum +{ + IGNORE, + IGNORE_ALL, + CHANGE, + CHANGE_ALL, + ADD_WORD_TO_PERSONAL, + LAST_SIGNAL +}; + +enum +{ + COLUMN_SUGGESTIONS, + NUM_COLUMNS +}; + +static void update_suggestions_list_model (PlumaSpellCheckerDialog *dlg, + GSList *suggestions); + +static void word_entry_changed_handler (GtkEditable *editable, + PlumaSpellCheckerDialog *dlg); +static void close_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void suggestions_list_selection_changed_handler (GtkTreeSelection *selection, + PlumaSpellCheckerDialog *dlg); +static void check_word_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void add_word_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void ignore_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void ignore_all_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void change_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void change_all_button_clicked_handler (GtkButton *button, + PlumaSpellCheckerDialog *dlg); +static void suggestions_list_row_activated_handler (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellCheckerDialog *dlg); + + +static guint signals [LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(PlumaSpellCheckerDialog, pluma_spell_checker_dialog, GTK_TYPE_WINDOW) + +static void +pluma_spell_checker_dialog_destroy (GtkObject *object) +{ + PlumaSpellCheckerDialog *dlg = PLUMA_SPELL_CHECKER_DIALOG (object); + + if (dlg->spell_checker != NULL) + { + g_object_unref (dlg->spell_checker); + dlg->spell_checker = NULL; + } + + if (dlg->misspelled_word != NULL) + { + g_free (dlg->misspelled_word); + dlg->misspelled_word = NULL; + } + + GTK_OBJECT_CLASS (pluma_spell_checker_dialog_parent_class)->destroy (object); +} + +static void +pluma_spell_checker_dialog_class_init (PlumaSpellCheckerDialogClass * klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + GTK_OBJECT_CLASS (object_class)->destroy = pluma_spell_checker_dialog_destroy; + + signals[IGNORE] = + g_signal_new ("ignore", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + signals[IGNORE_ALL] = + g_signal_new ("ignore_all", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, ignore_all), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + signals[CHANGE] = + g_signal_new ("change", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change), + NULL, NULL, + pluma_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[CHANGE_ALL] = + g_signal_new ("change_all", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, change_all), + NULL, NULL, + pluma_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + signals[ADD_WORD_TO_PERSONAL] = + g_signal_new ("add_word_to_personal", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerDialogClass, add_word_to_personal), + NULL, NULL, + pluma_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + +static void +create_dialog (PlumaSpellCheckerDialog *dlg, + const gchar *data_dir) +{ + GtkWidget *error_widget; + GtkWidget *content; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkTreeSelection *selection; + gchar *root_objects[] = { + "content", + "check_word_image", + "add_word_image", + "ignore_image", + "change_image", + "ignore_all_image", + "change_all_image", + NULL + }; + gboolean ret; + gchar *ui_file; + + g_return_if_fail (dlg != NULL); + + dlg->spell_checker = NULL; + dlg->misspelled_word = NULL; + + ui_file = g_build_filename (data_dir, "spell-checker.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + root_objects, + &error_widget, + + "content", &content, + "misspelled_word_label", &dlg->misspelled_word_label, + "word_entry", &dlg->word_entry, + "check_word_button", &dlg->check_word_button, + "ignore_button", &dlg->ignore_button, + "ignore_all_button", &dlg->ignore_all_button, + "change_button", &dlg->change_button, + "change_all_button", &dlg->change_all_button, + "add_word_button", &dlg->add_word_button, + "close_button", &dlg->close_button, + "suggestions_list", &dlg->suggestions_list, + "language_label", &dlg->language_label, + NULL); + g_free (ui_file); + + if (!ret) + { + gtk_widget_show (error_widget); + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + error_widget, TRUE, TRUE, 0); + + return; + } + + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), ""); + gtk_widget_set_sensitive (dlg->word_entry, FALSE); + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + gtk_widget_set_sensitive (dlg->add_word_button, FALSE); + + gtk_label_set_label (GTK_LABEL (dlg->language_label), ""); + + gtk_container_add (GTK_CONTAINER (dlg), content); + g_object_unref (content); + + gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE); + gtk_window_set_title (GTK_WINDOW (dlg), _("Check Spelling")); + + /* Suggestion list */ + dlg->suggestions_list_model = GTK_TREE_MODEL ( + gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING)); + + gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->suggestions_list), + dlg->suggestions_list_model); + + /* Add the suggestions column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Suggestions"), cell, + "text", COLUMN_SUGGESTIONS, NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->suggestions_list), column); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->suggestions_list), + COLUMN_SUGGESTIONS); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + /* Set default button */ + GTK_WIDGET_SET_FLAGS (dlg->change_button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (dlg->change_button); + + gtk_entry_set_activates_default (GTK_ENTRY (dlg->word_entry), TRUE); + + /* Connect signals */ + g_signal_connect (dlg->word_entry, "changed", + G_CALLBACK (word_entry_changed_handler), dlg); + g_signal_connect (dlg->close_button, "clicked", + G_CALLBACK (close_button_clicked_handler), dlg); + g_signal_connect (selection, "changed", + G_CALLBACK (suggestions_list_selection_changed_handler), + dlg); + g_signal_connect (dlg->check_word_button, "clicked", + G_CALLBACK (check_word_button_clicked_handler), dlg); + g_signal_connect (dlg->add_word_button, "clicked", + G_CALLBACK (add_word_button_clicked_handler), dlg); + g_signal_connect (dlg->ignore_button, "clicked", + G_CALLBACK (ignore_button_clicked_handler), dlg); + g_signal_connect (dlg->ignore_all_button, "clicked", + G_CALLBACK (ignore_all_button_clicked_handler), dlg); + g_signal_connect (dlg->change_button, "clicked", + G_CALLBACK (change_button_clicked_handler), dlg); + g_signal_connect (dlg->change_all_button, "clicked", + G_CALLBACK (change_all_button_clicked_handler), dlg); + g_signal_connect (dlg->suggestions_list, "row-activated", + G_CALLBACK (suggestions_list_row_activated_handler), dlg); +} + +static void +pluma_spell_checker_dialog_init (PlumaSpellCheckerDialog *dlg) +{ +} + +GtkWidget * +pluma_spell_checker_dialog_new (const gchar *data_dir) +{ + PlumaSpellCheckerDialog *dlg; + + dlg = PLUMA_SPELL_CHECKER_DIALOG ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL)); + + g_return_val_if_fail (dlg != NULL, NULL); + + create_dialog (dlg, data_dir); + + return GTK_WIDGET (dlg); +} + +GtkWidget * +pluma_spell_checker_dialog_new_from_spell_checker (PlumaSpellChecker *spell, + const gchar *data_dir) +{ + PlumaSpellCheckerDialog *dlg; + + g_return_val_if_fail (spell != NULL, NULL); + + dlg = PLUMA_SPELL_CHECKER_DIALOG ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER_DIALOG, NULL)); + + g_return_val_if_fail (dlg != NULL, NULL); + + create_dialog (dlg, data_dir); + + pluma_spell_checker_dialog_set_spell_checker (dlg, spell); + + return GTK_WIDGET (dlg); +} + +void +pluma_spell_checker_dialog_set_spell_checker (PlumaSpellCheckerDialog *dlg, PlumaSpellChecker *spell) +{ + const PlumaSpellCheckerLanguage* language; + const gchar *lang; + gchar *tmp; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (spell != NULL); + + if (dlg->spell_checker != NULL) + g_object_unref (dlg->spell_checker); + + dlg->spell_checker = spell; + g_object_ref (dlg->spell_checker); + + language = pluma_spell_checker_get_language (dlg->spell_checker); + + lang = pluma_spell_checker_language_to_string (language); + tmp = g_strdup_printf("%s", lang); + + gtk_label_set_label (GTK_LABEL (dlg->language_label), tmp); + g_free (tmp); + + if (dlg->misspelled_word != NULL) + pluma_spell_checker_dialog_set_misspelled_word (dlg, dlg->misspelled_word, -1); + else + gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); + + /* TODO: reset all widgets */ +} + +void +pluma_spell_checker_dialog_set_misspelled_word (PlumaSpellCheckerDialog *dlg, + const gchar *word, + gint len) +{ + gchar *tmp; + GSList *sug; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (word != NULL); + + g_return_if_fail (dlg->spell_checker != NULL); + g_return_if_fail (!pluma_spell_checker_check_word (dlg->spell_checker, word, -1)); + + /* build_suggestions_list */ + if (dlg->misspelled_word != NULL) + g_free (dlg->misspelled_word); + + dlg->misspelled_word = g_strdup (word); + + tmp = g_strdup_printf("%s", word); + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), tmp); + g_free (tmp); + + sug = pluma_spell_checker_get_suggestions (dlg->spell_checker, + dlg->misspelled_word, + -1); + + update_suggestions_list_model (dlg, sug); + + /* free the suggestion list */ + g_slist_foreach (sug, (GFunc)g_free, NULL); + g_slist_free (sug); + + gtk_widget_set_sensitive (dlg->ignore_button, TRUE); + gtk_widget_set_sensitive (dlg->ignore_all_button, TRUE); + gtk_widget_set_sensitive (dlg->add_word_button, TRUE); +} + +static void +update_suggestions_list_model (PlumaSpellCheckerDialog *dlg, GSList *suggestions) +{ + GtkListStore *store; + GtkTreeIter iter; + GtkTreeSelection *sel; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (GTK_IS_LIST_STORE (dlg->suggestions_list_model)); + + store = GTK_LIST_STORE (dlg->suggestions_list_model); + gtk_list_store_clear (store); + + gtk_widget_set_sensitive (dlg->word_entry, TRUE); + + if (suggestions == NULL) + { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + /* Translators: Displayed in the "Check Spelling" dialog if there are no suggestions + * for the current misspelled word */ + COLUMN_SUGGESTIONS, _("(no suggested words)"), + -1); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); + + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); + + return; + } + + gtk_widget_set_sensitive (dlg->suggestions_list, TRUE); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), (gchar*)suggestions->data); + + while (suggestions != NULL) + { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_SUGGESTIONS, (gchar*)suggestions->data, + -1); + + suggestions = g_slist_next (suggestions); + } + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->suggestions_list)); + gtk_tree_model_get_iter_first (dlg->suggestions_list_model, &iter); + gtk_tree_selection_select_iter (sel, &iter); +} + +static void +word_entry_changed_handler (GtkEditable *editable, PlumaSpellCheckerDialog *dlg) +{ + const gchar *text; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + text = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); + + if (g_utf8_strlen (text, -1) > 0) + { + gtk_widget_set_sensitive (dlg->check_word_button, TRUE); + gtk_widget_set_sensitive (dlg->change_button, TRUE); + gtk_widget_set_sensitive (dlg->change_all_button, TRUE); + } + else + { + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + } +} + +static void +close_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +static void +suggestions_list_selection_changed_handler (GtkTreeSelection *selection, + PlumaSpellCheckerDialog *dlg) +{ + GtkTreeIter iter; + GValue value = {0, }; + const gchar *text; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) + return; + + gtk_tree_model_get_value (dlg->suggestions_list_model, &iter, + COLUMN_SUGGESTIONS, + &value); + + text = g_value_get_string (&value); + + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), text); + + g_value_unset (&value); +} + +static void +check_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + const gchar *word; + gssize len; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + word = gtk_entry_get_text (GTK_ENTRY (dlg->word_entry)); + len = strlen (word); + g_return_if_fail (len > 0); + + if (pluma_spell_checker_check_word (dlg->spell_checker, word, len)) + { + GtkListStore *store; + GtkTreeIter iter; + + store = GTK_LIST_STORE (dlg->suggestions_list_model); + gtk_list_store_clear (store); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + /* Translators: Displayed in the "Check Spelling" dialog if the current word isn't misspelled */ + COLUMN_SUGGESTIONS, _("(correct spelling)"), + -1); + + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); + } + else + { + GSList *sug; + + sug = pluma_spell_checker_get_suggestions (dlg->spell_checker, + word, + len); + + update_suggestions_list_model (dlg, sug); + + /* free the suggestion list */ + g_slist_foreach (sug, (GFunc)g_free, NULL); + g_slist_free (sug); + } +} + +static void +add_word_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + pluma_spell_checker_add_word_to_personal (dlg->spell_checker, + dlg->misspelled_word, + -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [ADD_WORD_TO_PERSONAL], 0, word); + + g_free (word); +} + +static void +ignore_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [IGNORE], 0, word); + + g_free (word); +} + +static void +ignore_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + pluma_spell_checker_add_word_to_session (dlg->spell_checker, + dlg->misspelled_word, + -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [IGNORE_ALL], 0, word); + + g_free (word); +} + +static void +change_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + gchar *change; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); + g_return_if_fail (change != NULL); + g_return_if_fail (*change != '\0'); + + pluma_spell_checker_set_correction (dlg->spell_checker, + dlg->misspelled_word, -1, + change, -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [CHANGE], 0, word, change); + + g_free (word); + g_free (change); +} + +/* double click on one of the suggestions is like clicking on "change" */ +static void +suggestions_list_row_activated_handler (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellCheckerDialog *dlg) +{ + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + change_button_clicked_handler (GTK_BUTTON (dlg->change_button), dlg); +} + +static void +change_all_button_clicked_handler (GtkButton *button, PlumaSpellCheckerDialog *dlg) +{ + gchar *word; + gchar *change; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + g_return_if_fail (dlg->misspelled_word != NULL); + + change = g_strdup (gtk_entry_get_text (GTK_ENTRY (dlg->word_entry))); + g_return_if_fail (change != NULL); + g_return_if_fail (*change != '\0'); + + pluma_spell_checker_set_correction (dlg->spell_checker, + dlg->misspelled_word, -1, + change, -1); + + word = g_strdup (dlg->misspelled_word); + + g_signal_emit (G_OBJECT (dlg), signals [CHANGE_ALL], 0, word, change); + + g_free (word); + g_free (change); +} + +void +pluma_spell_checker_dialog_set_completed (PlumaSpellCheckerDialog *dlg) +{ + gchar *tmp; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER_DIALOG (dlg)); + + tmp = g_strdup_printf("%s", _("Completed spell checking")); + gtk_label_set_label (GTK_LABEL (dlg->misspelled_word_label), + tmp); + g_free (tmp); + + gtk_list_store_clear (GTK_LIST_STORE (dlg->suggestions_list_model)); + gtk_entry_set_text (GTK_ENTRY (dlg->word_entry), ""); + + gtk_widget_set_sensitive (dlg->word_entry, FALSE); + gtk_widget_set_sensitive (dlg->check_word_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_button, FALSE); + gtk_widget_set_sensitive (dlg->ignore_all_button, FALSE); + gtk_widget_set_sensitive (dlg->change_button, FALSE); + gtk_widget_set_sensitive (dlg->change_all_button, FALSE); + gtk_widget_set_sensitive (dlg->add_word_button, FALSE); + gtk_widget_set_sensitive (dlg->suggestions_list, FALSE); +} + diff --git a/plugins/spell/pluma-spell-checker-dialog.h b/plugins/spell/pluma-spell-checker-dialog.h new file mode 100755 index 00000000..5a4082e3 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-dialog.h @@ -0,0 +1,92 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-dialog.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_DIALOG_H__ +#define __PLUMA_SPELL_CHECKER_DIALOG_H__ + +#include +#include "pluma-spell-checker.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_CHECKER_DIALOG (pluma_spell_checker_dialog_get_type ()) +#define PLUMA_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) +#define PLUMA_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) +#define PLUMA_IS_SPELL_CHECKER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG)) +#define PLUMA_IS_SPELL_CHECKER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_CHECKER_DIALOG)) +#define PLUMA_SPELL_CHECKER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_SPELL_CHECKER_DIALOG, PlumaSpellCheckerDialog)) + + +typedef struct _PlumaSpellCheckerDialog PlumaSpellCheckerDialog; + +typedef struct _PlumaSpellCheckerDialogClass PlumaSpellCheckerDialogClass; + +struct _PlumaSpellCheckerDialogClass +{ + GtkWindowClass parent_class; + + /* Signals */ + void (*ignore) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + void (*ignore_all) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + void (*change) (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change_to); + void (*change_all) (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change_to); + void (*add_word_to_personal) (PlumaSpellCheckerDialog *dlg, + const gchar *word); + +}; + +GType pluma_spell_checker_dialog_get_type (void) G_GNUC_CONST; + +/* Constructors */ +GtkWidget *pluma_spell_checker_dialog_new (const gchar *data_dir); +GtkWidget *pluma_spell_checker_dialog_new_from_spell_checker + (PlumaSpellChecker *spell, + const gchar *data_dir); + +void pluma_spell_checker_dialog_set_spell_checker + (PlumaSpellCheckerDialog *dlg, + PlumaSpellChecker *spell); +void pluma_spell_checker_dialog_set_misspelled_word + (PlumaSpellCheckerDialog *dlg, + const gchar* word, + gint len); + +void pluma_spell_checker_dialog_set_completed + (PlumaSpellCheckerDialog *dlg); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_DIALOG_H__ */ + diff --git a/plugins/spell/pluma-spell-checker-language.c b/plugins/spell/pluma-spell-checker-language.c new file mode 100755 index 00000000..042e7706 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-language.c @@ -0,0 +1,439 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-language.c + * This file is part of pluma + * + * Copyright (C) 2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +/* Part of the code taked from Epiphany. + * + * Copyright (C) 2003, 2004 Christian Persch + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "pluma-spell-checker-language.h" + +#include + +#define ISO_639_DOMAIN "iso_639" +#define ISO_3166_DOMAIN "iso_3166" + +#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale" + +struct _PlumaSpellCheckerLanguage +{ + gchar *abrev; + gchar *name; +}; + +static gboolean available_languages_initialized = FALSE; +static GSList *available_languages = NULL; + +static GHashTable *iso_639_table = NULL; +static GHashTable *iso_3166_table = NULL; + +static void +bind_iso_domains (void) +{ + static gboolean bound = FALSE; + + if (bound == FALSE) + { + bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR); + bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8"); + + bindtextdomain(ISO_3166_DOMAIN, ISOCODESLOCALEDIR); + bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8"); + + bound = TRUE; + } +} + +static void +read_iso_639_entry (xmlTextReaderPtr reader, + GHashTable *table) +{ + xmlChar *code, *name; + + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code"); + name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); + + /* Get iso-639-2 code */ + if (code == NULL || code[0] == '\0') + { + xmlFree (code); + /* FIXME: use the 2T or 2B code? */ + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code"); + } + + if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') + { + g_hash_table_insert (table, code, name); + } + else + { + xmlFree (code); + xmlFree (name); + } +} + +static void +read_iso_3166_entry (xmlTextReaderPtr reader, + GHashTable *table) +{ + xmlChar *code, *name; + + code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code"); + name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name"); + + if (code != NULL && code[0] != '\0' && name != NULL && name[0] != '\0') + { + char *lcode; + + lcode = g_ascii_strdown ((char *) code, -1); + xmlFree (code); + + /* g_print ("%s -> %s\n", lcode, name); */ + + g_hash_table_insert (table, lcode, name); + } + else + { + xmlFree (code); + xmlFree (name); + } +} + +typedef enum +{ + STATE_START, + STATE_STOP, + STATE_ENTRIES, +} ParserState; + +static void +load_iso_entries (int iso, + GFunc read_entry_func, + gpointer user_data) +{ + xmlTextReaderPtr reader; + ParserState state = STATE_START; + xmlChar iso_entries[32], iso_entry[32]; + char *filename; + int ret = -1; + + pluma_debug_message (DEBUG_PLUGINS, "Loading ISO-%d codes", iso); + + filename = g_strdup_printf (ISO_CODES_PREFIX "/share/xml/iso-codes/iso_%d.xml", iso); + reader = xmlNewTextReaderFilename (filename); + if (reader == NULL) goto out; + + xmlStrPrintf (iso_entries, sizeof (iso_entries), (const xmlChar *)"iso_%d_entries", iso); + xmlStrPrintf (iso_entry, sizeof (iso_entry), (const xmlChar *)"iso_%d_entry", iso); + + ret = xmlTextReaderRead (reader); + + while (ret == 1) + { + const xmlChar *tag; + xmlReaderTypes type; + + tag = xmlTextReaderConstName (reader); + type = xmlTextReaderNodeType (reader); + + if (state == STATE_ENTRIES && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, iso_entry)) + { + read_entry_func (reader, user_data); + } + else if (state == STATE_START && + type == XML_READER_TYPE_ELEMENT && + xmlStrEqual (tag, iso_entries)) + { + state = STATE_ENTRIES; + } + else if (state == STATE_ENTRIES && + type == XML_READER_TYPE_END_ELEMENT && + xmlStrEqual (tag, iso_entries)) + { + state = STATE_STOP; + } + else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE || + type == XML_READER_TYPE_WHITESPACE || + type == XML_READER_TYPE_TEXT || + type == XML_READER_TYPE_COMMENT) + { + /* eat it */ + } + else + { + /* ignore it */ + } + + ret = xmlTextReaderRead (reader); + } + + xmlFreeTextReader (reader); + +out: + if (ret < 0 || state != STATE_STOP) + { + g_warning ("Failed to load ISO-%d codes from %s!\n", + iso, filename); + } + + g_free (filename); +} + +static GHashTable * +create_iso_639_table (void) +{ + GHashTable *table; + + bind_iso_domains (); + table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) xmlFree, + (GDestroyNotify) xmlFree); + + load_iso_entries (639, (GFunc) read_iso_639_entry, table); + + return table; +} + +static GHashTable * +create_iso_3166_table (void) +{ + GHashTable *table; + + bind_iso_domains (); + table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) xmlFree); + + load_iso_entries (3166, (GFunc) read_iso_3166_entry, table); + + return table; +} + +static char * +create_name_for_language (const char *code) +{ + char **str; + char *name = NULL; + const char *langname, *localename; + int len; + + g_return_val_if_fail (iso_639_table != NULL, NULL); + g_return_val_if_fail (iso_3166_table != NULL, NULL); + + str = g_strsplit (code, "_", -1); + len = g_strv_length (str); + g_return_val_if_fail (len != 0, NULL); + + langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]); + + if (len == 1 && langname != NULL) + { + name = g_strdup (dgettext (ISO_639_DOMAIN, langname)); + } + else if (len == 2 && langname != NULL) + { + gchar *locale_code = g_ascii_strdown (str[1], -1); + + localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code); + g_free (locale_code); + + if (localename != NULL) + { + /* Translators: the first %s is the language name, and + * the second %s is the locale name. Example: + * "French (France)" + */ + name = g_strdup_printf (C_("language", "%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), + dgettext (ISO_3166_DOMAIN, localename)); + } + else + { + name = g_strdup_printf (C_("language", "%s (%s)"), + dgettext (ISO_639_DOMAIN, langname), str[1]); + } + } + else + { + /* Translators: this refers to an unknown language code + * (one which isn't in our built-in list). + */ + name = g_strdup_printf (C_("language", "Unknown (%s)"), code); + } + + g_strfreev (str); + + return name; +} + +static void +enumerate_dicts (const char * const lang_tag, + const char * const provider_name, + const char * const provider_desc, + const char * const provider_file, + void * user_data) +{ + gchar *lang_name; + + GTree *dicts = (GTree *)user_data; + + lang_name = create_name_for_language (lang_tag); + g_return_if_fail (lang_name != NULL); + + /* g_print ("%s - %s\n", lang_tag, lang_name); */ + + g_tree_replace (dicts, g_strdup (lang_tag), lang_name); +} + +static gint +key_cmp (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return strcmp (a, b); +} + +static gint +lang_cmp (const PlumaSpellCheckerLanguage *a, + const PlumaSpellCheckerLanguage *b) +{ + return g_utf8_collate (a->name, b->name); +} + +static gboolean +build_langs_list (const gchar *key, + const gchar *value, + gpointer data) +{ + PlumaSpellCheckerLanguage *lang = g_new (PlumaSpellCheckerLanguage, 1); + + lang->abrev = g_strdup (key); + lang->name = g_strdup (value); + + available_languages = g_slist_insert_sorted (available_languages, + lang, + (GCompareFunc)lang_cmp); + + return FALSE; +} + +const GSList * +pluma_spell_checker_get_available_languages (void) +{ + EnchantBroker *broker; + GTree *dicts; + + if (available_languages_initialized) + return available_languages; + + g_return_val_if_fail (available_languages == NULL, NULL); + + available_languages_initialized = TRUE; + + broker = enchant_broker_init (); + g_return_val_if_fail (broker != NULL, NULL); + + /* Use a GTree to efficiently remove duplicates while building the list */ + dicts = g_tree_new_full (key_cmp, + NULL, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + + iso_639_table = create_iso_639_table (); + iso_3166_table = create_iso_3166_table (); + + enchant_broker_list_dicts (broker, enumerate_dicts, dicts); + + enchant_broker_free (broker); + + g_hash_table_destroy (iso_639_table); + g_hash_table_destroy (iso_3166_table); + + iso_639_table = NULL; + iso_3166_table = NULL; + + g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL); + + g_tree_destroy (dicts); + + return available_languages; +} + +const gchar * +pluma_spell_checker_language_to_string (const PlumaSpellCheckerLanguage *lang) +{ + if (lang == NULL) + /* Translators: this refers the Default language used by the + * spell checker + */ + return C_("language", "Default"); + + return lang->name; +} + +const gchar * +pluma_spell_checker_language_to_key (const PlumaSpellCheckerLanguage *lang) +{ + g_return_val_if_fail (lang != NULL, NULL); + + return lang->abrev; +} + +const PlumaSpellCheckerLanguage * +pluma_spell_checker_language_from_key (const gchar *key) +{ + const GSList *langs; + + g_return_val_if_fail (key != NULL, NULL); + + langs = pluma_spell_checker_get_available_languages (); + + while (langs != NULL) + { + const PlumaSpellCheckerLanguage *l = (const PlumaSpellCheckerLanguage *)langs->data; + + if (g_ascii_strcasecmp (key, l->abrev) == 0) + return l; + + langs = g_slist_next (langs); + } + + return NULL; +} diff --git a/plugins/spell/pluma-spell-checker-language.h b/plugins/spell/pluma-spell-checker-language.h new file mode 100755 index 00000000..8bae47a4 --- /dev/null +++ b/plugins/spell/pluma-spell-checker-language.h @@ -0,0 +1,51 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker-language.h + * This file is part of pluma + * + * Copyright (C) 2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_LANGUAGE_H__ +#define __PLUMA_SPELL_CHECKER_LANGUAGE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _PlumaSpellCheckerLanguage PlumaSpellCheckerLanguage; + +const gchar *pluma_spell_checker_language_to_string (const PlumaSpellCheckerLanguage *lang); + +const gchar *pluma_spell_checker_language_to_key (const PlumaSpellCheckerLanguage *lang); + +const PlumaSpellCheckerLanguage *pluma_spell_checker_language_from_key (const gchar *key); + +/* GSList contains "PlumaSpellCheckerLanguage*" items */ +const GSList *pluma_spell_checker_get_available_languages + (void); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_LANGUAGE_H__ */ diff --git a/plugins/spell/pluma-spell-checker.c b/plugins/spell/pluma-spell-checker.c new file mode 100755 index 00000000..24cfcdd5 --- /dev/null +++ b/plugins/spell/pluma-spell-checker.c @@ -0,0 +1,520 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker.c + * This file is part of pluma + * + * Copyright (C) 2002-2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002-2006. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "pluma-spell-checker.h" +#include "pluma-spell-utils.h" +#include "pluma-spell-marshal.h" + +struct _PlumaSpellChecker +{ + GObject parent_instance; + + EnchantDict *dict; + EnchantBroker *broker; + const PlumaSpellCheckerLanguage *active_lang; +}; + +/* GObject properties */ +enum { + PROP_0 = 0, + PROP_LANGUAGE, + LAST_PROP +}; + +/* Signals */ +enum { + ADD_WORD_TO_PERSONAL = 0, + ADD_WORD_TO_SESSION, + SET_LANGUAGE, + CLEAR_SESSION, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(PlumaSpellChecker, pluma_spell_checker, G_TYPE_OBJECT) + +static void +pluma_spell_checker_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + /* + PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object); + */ + + switch (prop_id) + { + case PROP_LANGUAGE: + /* TODO */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pluma_spell_checker_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + /* + PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object); + */ + + switch (prop_id) + { + case PROP_LANGUAGE: + /* TODO */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +pluma_spell_checker_finalize (GObject *object) +{ + PlumaSpellChecker *spell_checker; + + g_return_if_fail (PLUMA_IS_SPELL_CHECKER (object)); + + spell_checker = PLUMA_SPELL_CHECKER (object); + + if (spell_checker->dict != NULL) + enchant_broker_free_dict (spell_checker->broker, spell_checker->dict); + + if (spell_checker->broker != NULL) + enchant_broker_free (spell_checker->broker); + + G_OBJECT_CLASS (pluma_spell_checker_parent_class)->finalize (object); +} + +static void +pluma_spell_checker_class_init (PlumaSpellCheckerClass * klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = pluma_spell_checker_set_property; + object_class->get_property = pluma_spell_checker_get_property; + + object_class->finalize = pluma_spell_checker_finalize; + + g_object_class_install_property (object_class, + PROP_LANGUAGE, + g_param_spec_pointer ("language", + "Language", + "The language used by the spell checker", + G_PARAM_READWRITE)); + + signals[ADD_WORD_TO_PERSONAL] = + g_signal_new ("add_word_to_personal", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_personal), + NULL, NULL, + pluma_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + + signals[ADD_WORD_TO_SESSION] = + g_signal_new ("add_word_to_session", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_session), + NULL, NULL, + pluma_marshal_VOID__STRING_INT, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_INT); + + signals[SET_LANGUAGE] = + g_signal_new ("set_language", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, set_language), + NULL, NULL, + pluma_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + signals[CLEAR_SESSION] = + g_signal_new ("clear_session", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (PlumaSpellCheckerClass, clear_session), + NULL, NULL, + pluma_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +pluma_spell_checker_init (PlumaSpellChecker *spell_checker) +{ + spell_checker->broker = enchant_broker_init (); + spell_checker->dict = NULL; + spell_checker->active_lang = NULL; +} + +PlumaSpellChecker * +pluma_spell_checker_new (void) +{ + PlumaSpellChecker *spell; + + spell = PLUMA_SPELL_CHECKER ( + g_object_new (PLUMA_TYPE_SPELL_CHECKER, NULL)); + + g_return_val_if_fail (spell != NULL, NULL); + + return spell; +} + +static gboolean +lazy_init (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *language) +{ + if (spell->dict != NULL) + return TRUE; + + g_return_val_if_fail (spell->broker != NULL, FALSE); + + spell->active_lang = NULL; + + if (language != NULL) + { + spell->active_lang = language; + } + else + { + /* First try to get a default language */ + const PlumaSpellCheckerLanguage *l; + gint i = 0; + const gchar * const *lang_tags = g_get_language_names (); + + while (lang_tags [i]) + { + l = pluma_spell_checker_language_from_key (lang_tags [i]); + + if (l != NULL) + { + spell->active_lang = l; + break; + } + + i++; + } + } + + /* Second try to get a default language */ + if (spell->active_lang == NULL) + spell->active_lang = pluma_spell_checker_language_from_key ("en_US"); + + /* Last try to get a default language */ + if (spell->active_lang == NULL) + { + const GSList *langs; + langs = pluma_spell_checker_get_available_languages (); + if (langs != NULL) + spell->active_lang = (const PlumaSpellCheckerLanguage *)langs->data; + } + + if (spell->active_lang != NULL) + { + const gchar *key; + + key = pluma_spell_checker_language_to_key (spell->active_lang); + + spell->dict = enchant_broker_request_dict (spell->broker, + key); + } + + if (spell->dict == NULL) + { + spell->active_lang = NULL; + + if (language != NULL) + g_warning ("Spell checker plugin: cannot select a default language."); + + return FALSE; + } + + return TRUE; +} + +gboolean +pluma_spell_checker_set_language (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *language) +{ + gboolean ret; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + + if (spell->dict != NULL) + { + enchant_broker_free_dict (spell->broker, spell->dict); + spell->dict = NULL; + } + + ret = lazy_init (spell, language); + + if (ret) + g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language); + else + g_warning ("Spell checker plugin: cannot use language %s.", + pluma_spell_checker_language_to_string (language)); + + return ret; +} + +const PlumaSpellCheckerLanguage * +pluma_spell_checker_get_language (PlumaSpellChecker *spell) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL); + + if (!lazy_init (spell, spell->active_lang)) + return NULL; + + return spell->active_lang; +} + +gboolean +pluma_spell_checker_check_word (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + gint enchant_result; + gboolean res = FALSE; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + if (len < 0) + len = strlen (word); + + if (strcmp (word, "pluma") == 0) + return TRUE; + + if (pluma_spell_utils_is_digit (word, len)) + return TRUE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + enchant_result = enchant_dict_check (spell->dict, word, len); + + switch (enchant_result) + { + case -1: + /* error */ + res = FALSE; + + g_warning ("Spell checker plugin: error checking word '%s' (%s).", + word, enchant_dict_get_error (spell->dict)); + + break; + case 1: + /* it is not in the directory */ + res = FALSE; + break; + case 0: + /* is is in the directory */ + res = TRUE; + break; + default: + g_return_val_if_reached (FALSE); + } + + return res; +} + + +/* return NULL on error or if no suggestions are found */ +GSList * +pluma_spell_checker_get_suggestions (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + gchar **suggestions; + size_t n_suggestions = 0; + GSList *suggestions_list = NULL; + gint i; + + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL); + g_return_val_if_fail (word != NULL, NULL); + + if (!lazy_init (spell, spell->active_lang)) + return NULL; + + g_return_val_if_fail (spell->dict != NULL, NULL); + + if (len < 0) + len = strlen (word); + + suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions); + + if (n_suggestions == 0) + return NULL; + + g_return_val_if_fail (suggestions != NULL, NULL); + + for (i = 0; i < (gint)n_suggestions; i++) + { + suggestions_list = g_slist_prepend (suggestions_list, + suggestions[i]); + } + + /* The single suggestions will be freed by the caller */ + g_free (suggestions); + + suggestions_list = g_slist_reverse (suggestions_list); + + return suggestions_list; +} + +gboolean +pluma_spell_checker_add_word_to_personal (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (len < 0) + len = strlen (word); + + enchant_dict_add_to_pwl (spell->dict, word, len); + + g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len); + + return TRUE; +} + +gboolean +pluma_spell_checker_add_word_to_session (PlumaSpellChecker *spell, + const gchar *word, + gssize len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (len < 0) + len = strlen (word); + + enchant_dict_add_to_session (spell->dict, word, len); + + g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len); + + return TRUE; +} + +gboolean +pluma_spell_checker_clear_session (PlumaSpellChecker *spell) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + + /* free and re-request dictionary */ + if (spell->dict != NULL) + { + enchant_broker_free_dict (spell->broker, spell->dict); + spell->dict = NULL; + } + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0); + + return TRUE; +} + +/* + * Informs dictionary, that word 'word' will be replaced/corrected by word + * 'replacement' + */ +gboolean +pluma_spell_checker_set_correction (PlumaSpellChecker *spell, + const gchar *word, + gssize w_len, + const gchar *replacement, + gssize r_len) +{ + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE); + g_return_val_if_fail (word != NULL, FALSE); + g_return_val_if_fail (replacement != NULL, FALSE); + + if (!lazy_init (spell, spell->active_lang)) + return FALSE; + + g_return_val_if_fail (spell->dict != NULL, FALSE); + + if (w_len < 0) + w_len = strlen (word); + + if (r_len < 0) + r_len = strlen (replacement); + + enchant_dict_store_replacement (spell->dict, + word, + w_len, + replacement, + r_len); + + return TRUE; +} + diff --git a/plugins/spell/pluma-spell-checker.h b/plugins/spell/pluma-spell-checker.h new file mode 100755 index 00000000..ed8c1756 --- /dev/null +++ b/plugins/spell/pluma-spell-checker.h @@ -0,0 +1,109 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-checker.h + * This file is part of pluma + * + * Copyright (C) 2002-2006 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_CHECKER_H__ +#define __PLUMA_SPELL_CHECKER_H__ + +#include +#include + +#include "pluma-spell-checker-language.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_CHECKER (pluma_spell_checker_get_type ()) +#define PLUMA_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) +#define PLUMA_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) +#define PLUMA_IS_SPELL_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_SPELL_CHECKER)) +#define PLUMA_IS_SPELL_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_CHECKER)) +#define PLUMA_SPELL_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUMA_TYPE_SPELL_CHECKER, PlumaSpellChecker)) + +typedef struct _PlumaSpellChecker PlumaSpellChecker; + +typedef struct _PlumaSpellCheckerClass PlumaSpellCheckerClass; + +struct _PlumaSpellCheckerClass +{ + GObjectClass parent_class; + + /* Signals */ + void (*add_word_to_personal) (PlumaSpellChecker *spell, + const gchar *word, + gint len); + + void (*add_word_to_session) (PlumaSpellChecker *spell, + const gchar *word, + gint len); + + void (*set_language) (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang); + + void (*clear_session) (PlumaSpellChecker *spell); +}; + + +GType pluma_spell_checker_get_type (void) G_GNUC_CONST; + +/* Constructors */ +PlumaSpellChecker *pluma_spell_checker_new (void); + +gboolean pluma_spell_checker_set_language (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang); +const PlumaSpellCheckerLanguage + *pluma_spell_checker_get_language (PlumaSpellChecker *spell); + +gboolean pluma_spell_checker_check_word (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +GSList *pluma_spell_checker_get_suggestions (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_add_word_to_personal + (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_add_word_to_session + (PlumaSpellChecker *spell, + const gchar *word, + gssize len); + +gboolean pluma_spell_checker_clear_session (PlumaSpellChecker *spell); + +gboolean pluma_spell_checker_set_correction (PlumaSpellChecker *spell, + const gchar *word, + gssize w_len, + const gchar *replacement, + gssize r_len); +G_END_DECLS + +#endif /* __PLUMA_SPELL_CHECKER_H__ */ + diff --git a/plugins/spell/pluma-spell-language-dialog.c b/plugins/spell/pluma-spell-language-dialog.c new file mode 100755 index 00000000..22a14373 --- /dev/null +++ b/plugins/spell/pluma-spell-language-dialog.c @@ -0,0 +1,309 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-language-dialog.c + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "pluma-spell-language-dialog.h" +#include "pluma-spell-checker-language.h" + + +enum +{ + COLUMN_LANGUAGE_NAME = 0, + COLUMN_LANGUAGE_POINTER, + ENCODING_NUM_COLS +}; + + +struct _PlumaSpellLanguageDialog +{ + GtkDialog dialog; + + GtkWidget *languages_treeview; + GtkTreeModel *model; +}; + +G_DEFINE_TYPE(PlumaSpellLanguageDialog, pluma_spell_language_dialog, GTK_TYPE_DIALOG) + + +static void +pluma_spell_language_dialog_class_init (PlumaSpellLanguageDialogClass *klass) +{ + /* GObjectClass *object_class = G_OBJECT_CLASS (klass); */ +} + +static void +dialog_response_handler (GtkDialog *dlg, + gint res_id) +{ + if (res_id == GTK_RESPONSE_HELP) + { + pluma_help_display (GTK_WINDOW (dlg), + NULL, + "pluma-spell-checker-plugin"); + + g_signal_stop_emission_by_name (dlg, "response"); + } +} + +static void +scroll_to_selected (GtkTreeView *tree_view) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (tree_view); + g_return_if_fail (model != NULL); + + /* Scroll to selected */ + selection = gtk_tree_view_get_selection (tree_view); + g_return_if_fail (selection != NULL); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GtkTreePath* path; + + path = gtk_tree_model_get_path (model, &iter); + g_return_if_fail (path != NULL); + + gtk_tree_view_scroll_to_cell (tree_view, + path, NULL, TRUE, 1.0, 0.0); + gtk_tree_path_free (path); + } +} + +static void +language_row_activated (GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaSpellLanguageDialog *dialog) +{ + gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); +} + +static void +create_dialog (PlumaSpellLanguageDialog *dlg, + const gchar *data_dir) +{ + GtkWidget *error_widget; + GtkWidget *content; + gboolean ret; + GtkCellRenderer *cell; + GtkTreeViewColumn *column; + gchar *ui_file; + gchar *root_objects[] = { + "content", + NULL + }; + + gtk_dialog_add_buttons (GTK_DIALOG (dlg), + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + GTK_STOCK_HELP, + GTK_RESPONSE_HELP, + NULL); + + gtk_window_set_title (GTK_WINDOW (dlg), _("Set language")); + gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE); + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE); + + /* HIG defaults */ + gtk_container_set_border_width (GTK_CONTAINER (dlg), 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), + 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), + 6); + + g_signal_connect (dlg, + "response", + G_CALLBACK (dialog_response_handler), + NULL); + + ui_file = g_build_filename (data_dir, "languages-dialog.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + root_objects, + &error_widget, + "content", &content, + "languages_treeview", &dlg->languages_treeview, + NULL); + g_free (ui_file); + + if (!ret) + { + gtk_widget_show (error_widget); + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + error_widget, + TRUE, TRUE, 0); + + return; + } + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), + content, TRUE, TRUE, 0); + g_object_unref (content); + gtk_container_set_border_width (GTK_CONTAINER (content), 5); + + dlg->model = GTK_TREE_MODEL (gtk_list_store_new (ENCODING_NUM_COLS, + G_TYPE_STRING, + G_TYPE_POINTER)); + + gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->languages_treeview), + dlg->model); + + g_object_unref (dlg->model); + + /* Add the encoding column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Languages"), + cell, + "text", + COLUMN_LANGUAGE_NAME, + NULL); + + gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->languages_treeview), + column); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (dlg->languages_treeview), + COLUMN_LANGUAGE_NAME); + + g_signal_connect (dlg->languages_treeview, + "realize", + G_CALLBACK (scroll_to_selected), + dlg); + g_signal_connect (dlg->languages_treeview, + "row-activated", + G_CALLBACK (language_row_activated), + dlg); +} + +static void +pluma_spell_language_dialog_init (PlumaSpellLanguageDialog *dlg) +{ + +} + +static void +populate_language_list (PlumaSpellLanguageDialog *dlg, + const PlumaSpellCheckerLanguage *cur_lang) +{ + GtkListStore *store; + GtkTreeIter iter; + + const GSList* langs; + + /* create list store */ + store = GTK_LIST_STORE (dlg->model); + + langs = pluma_spell_checker_get_available_languages (); + + while (langs) + { + const gchar *name; + + name = pluma_spell_checker_language_to_string ((const PlumaSpellCheckerLanguage*)langs->data); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_LANGUAGE_NAME, name, + COLUMN_LANGUAGE_POINTER, langs->data, + -1); + + if (langs->data == cur_lang) + { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); + g_return_if_fail (selection != NULL); + + gtk_tree_selection_select_iter (selection, &iter); + } + + langs = g_slist_next (langs); + } +} + +GtkWidget * +pluma_spell_language_dialog_new (GtkWindow *parent, + const PlumaSpellCheckerLanguage *cur_lang, + const gchar *data_dir) +{ + PlumaSpellLanguageDialog *dlg; + + g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); + + dlg = g_object_new (PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, NULL); + + create_dialog (dlg, data_dir); + + populate_language_list (dlg, cur_lang); + + gtk_window_set_transient_for (GTK_WINDOW (dlg), parent); + gtk_widget_grab_focus (dlg->languages_treeview); + + return GTK_WIDGET (dlg); +} + +const PlumaSpellCheckerLanguage * +pluma_spell_language_get_selected_language (PlumaSpellLanguageDialog *dlg) +{ + GValue value = {0, }; + const PlumaSpellCheckerLanguage* lang; + + GtkTreeIter iter; + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->languages_treeview)); + g_return_val_if_fail (selection != NULL, NULL); + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + return NULL; + + gtk_tree_model_get_value (dlg->model, + &iter, + COLUMN_LANGUAGE_POINTER, + &value); + + lang = (const PlumaSpellCheckerLanguage* ) g_value_get_pointer (&value); + + return lang; +} + diff --git a/plugins/spell/pluma-spell-language-dialog.h b/plugins/spell/pluma-spell-language-dialog.h new file mode 100755 index 00000000..3fc32a0b --- /dev/null +++ b/plugins/spell/pluma-spell-language-dialog.h @@ -0,0 +1,67 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * pluma-spell-language-dialog.h + * This file is part of pluma + * + * Copyright (C) 2002 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifndef __PLUMA_SPELL_LANGUAGE_DIALOG_H__ +#define __PLUMA_SPELL_LANGUAGE_DIALOG_H__ + +#include +#include "pluma-spell-checker-language.h" + +G_BEGIN_DECLS + +#define PLUMA_TYPE_SPELL_LANGUAGE_DIALOG (pluma_spell_language_dialog_get_type()) +#define PLUMA_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialog)) +#define PLUMA_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialogClass)) +#define PLUMA_IS_SPELL_LANGUAGE_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG)) +#define PLUMA_IS_SPELL_LANGUAGE_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG)) +#define PLUMA_SPELL_LANGUAGE_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PLUMA_TYPE_SPELL_LANGUAGE_DIALOG, PlumaSpellLanguageDialogClass)) + + +typedef struct _PlumaSpellLanguageDialog PlumaSpellLanguageDialog; + +typedef struct _PlumaSpellLanguageDialogClass PlumaSpellLanguageDialogClass; + +struct _PlumaSpellLanguageDialogClass +{ + GtkDialogClass parent_class; +}; + +GType pluma_spell_language_dialog_get_type (void) G_GNUC_CONST; + +GtkWidget *pluma_spell_language_dialog_new (GtkWindow *parent, + const PlumaSpellCheckerLanguage *cur_lang, + const gchar *data_dir); + +const PlumaSpellCheckerLanguage * + pluma_spell_language_get_selected_language (PlumaSpellLanguageDialog *dlg); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_LANGUAGE_DIALOG_H__ */ + diff --git a/plugins/spell/pluma-spell-marshal.list b/plugins/spell/pluma-spell-marshal.list new file mode 100755 index 00000000..007dcf7d --- /dev/null +++ b/plugins/spell/pluma-spell-marshal.list @@ -0,0 +1,6 @@ +VOID:STRING +VOID:STRING,STRING +VOID:STRING,INT +VOID:POINTER +VOID:VOID + diff --git a/plugins/spell/pluma-spell-plugin.c b/plugins/spell/pluma-spell-plugin.c new file mode 100755 index 00000000..e7dab44a --- /dev/null +++ b/plugins/spell/pluma-spell-plugin.c @@ -0,0 +1,1217 @@ +/* + * pluma-spell-plugin.c + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-spell-plugin.h" +#include "pluma-spell-utils.h" + +#include /* For strlen */ + +#include +#include + +#include +#include +#include + +#include "pluma-spell-checker.h" +#include "pluma-spell-checker-dialog.h" +#include "pluma-spell-language-dialog.h" +#include "pluma-automatic-spell-checker.h" + +#ifdef G_OS_WIN32 +#include +#define PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE "spell-language" +#define PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED "spell-enabled" +#else +#define PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE "metadata::pluma-spell-language" +#define PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED "metadata::pluma-spell-enabled" +#endif + +#define WINDOW_DATA_KEY "PlumaSpellPluginWindowData" +#define MENU_PATH "/MenuBar/ToolsMenu/ToolsOps_1" + +#define PLUMA_SPELL_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + PLUMA_TYPE_SPELL_PLUGIN, \ + PlumaSpellPluginPrivate)) + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaSpellPlugin, pluma_spell_plugin) + +typedef struct +{ + GtkActionGroup *action_group; + guint ui_id; + guint message_cid; + gulong tab_added_id; + gulong tab_removed_id; +} WindowData; + +typedef struct +{ + PlumaPlugin *plugin; + PlumaWindow *window; +} ActionData; + +static void spell_cb (GtkAction *action, ActionData *action_data); +static void set_language_cb (GtkAction *action, ActionData *action_data); +static void auto_spell_cb (GtkAction *action, PlumaWindow *window); + +/* UI actions. */ +static const GtkActionEntry action_entries[] = +{ + { "CheckSpell", + GTK_STOCK_SPELL_CHECK, + N_("_Check Spelling..."), + "F7", + N_("Check the current document for incorrect spelling"), + G_CALLBACK (spell_cb) + }, + + { "ConfigSpell", + NULL, + N_("Set _Language..."), + NULL, + N_("Set the language of the current document"), + G_CALLBACK (set_language_cb) + } +}; + +static const GtkToggleActionEntry toggle_action_entries[] = +{ + { "AutoSpell", + NULL, + N_("_Autocheck Spelling"), + NULL, + N_("Automatically spell-check the current document"), + G_CALLBACK (auto_spell_cb), + FALSE + } +}; + +typedef struct _CheckRange CheckRange; + +struct _CheckRange +{ + GtkTextMark *start_mark; + GtkTextMark *end_mark; + + gint mw_start; /* misspelled word start */ + gint mw_end; /* end */ + + GtkTextMark *current_mark; +}; + +static GQuark spell_checker_id = 0; +static GQuark check_range_id = 0; + +static void +pluma_spell_plugin_init (PlumaSpellPlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin initializing"); +} + +static void +pluma_spell_plugin_finalize (GObject *object) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaSpellPlugin finalizing"); + + G_OBJECT_CLASS (pluma_spell_plugin_parent_class)->finalize (object); +} + +static void +set_spell_language_cb (PlumaSpellChecker *spell, + const PlumaSpellCheckerLanguage *lang, + PlumaDocument *doc) +{ + const gchar *key; + + g_return_if_fail (PLUMA_IS_DOCUMENT (doc)); + g_return_if_fail (lang != NULL); + + key = pluma_spell_checker_language_to_key (lang); + g_return_if_fail (key != NULL); + + pluma_document_set_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE, + key, NULL); +} + +static void +set_language_from_metadata (PlumaSpellChecker *spell, + PlumaDocument *doc) +{ + const PlumaSpellCheckerLanguage *lang = NULL; + gchar *value = NULL; + + value = pluma_document_get_metadata (doc, PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE); + + if (value != NULL) + { + lang = pluma_spell_checker_language_from_key (value); + g_free (value); + } + + if (lang != NULL) + { + g_signal_handlers_block_by_func (spell, set_spell_language_cb, doc); + pluma_spell_checker_set_language (spell, lang); + g_signal_handlers_unblock_by_func (spell, set_spell_language_cb, doc); + } +} + +static PlumaSpellChecker * +get_spell_checker_from_document (PlumaDocument *doc) +{ + PlumaSpellChecker *spell; + gpointer data; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + + data = g_object_get_qdata (G_OBJECT (doc), spell_checker_id); + + if (data == NULL) + { + spell = pluma_spell_checker_new (); + + set_language_from_metadata (spell, doc); + + g_object_set_qdata_full (G_OBJECT (doc), + spell_checker_id, + spell, + (GDestroyNotify) g_object_unref); + + g_signal_connect (spell, + "set_language", + G_CALLBACK (set_spell_language_cb), + doc); + } + else + { + g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (data), NULL); + spell = PLUMA_SPELL_CHECKER (data); + } + + return spell; +} + +static CheckRange * +get_check_range (PlumaDocument *doc) +{ + CheckRange *range; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + + range = (CheckRange *) g_object_get_qdata (G_OBJECT (doc), check_range_id); + + return range; +} + +static void +update_current (PlumaDocument *doc, + gint current) +{ + CheckRange *range; + GtkTextIter iter; + GtkTextIter end_iter; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (doc != NULL); + g_return_if_fail (current >= 0); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), + &iter, current); + + if (!gtk_text_iter_inside_word (&iter)) + { + /* if we're not inside a word, + * we must be in some spaces. + * skip forward to the beginning of the next word. */ + if (!gtk_text_iter_is_end (&iter)) + { + gtk_text_iter_forward_word_end (&iter); + gtk_text_iter_backward_word_start (&iter); + } + } + else + { + if (!gtk_text_iter_starts_word (&iter)) + gtk_text_iter_backward_word_start (&iter); + } + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + &end_iter, + range->end_mark); + + if (gtk_text_iter_compare (&end_iter, &iter) < 0) + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->current_mark, + &end_iter); + } + else + { + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->current_mark, + &iter); + } +} + +static void +set_check_range (PlumaDocument *doc, + GtkTextIter *start, + GtkTextIter *end) +{ + CheckRange *range; + GtkTextIter iter; + + pluma_debug (DEBUG_PLUGINS); + + range = get_check_range (doc); + + if (range == NULL) + { + pluma_debug_message (DEBUG_PLUGINS, "There was not a previous check range"); + + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &iter); + + range = g_new0 (CheckRange, 1); + + range->start_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_start_mark", &iter, TRUE); + + range->end_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_end_mark", &iter, FALSE); + + range->current_mark = gtk_text_buffer_create_mark (GTK_TEXT_BUFFER (doc), + "check_range_current_mark", &iter, TRUE); + + g_object_set_qdata_full (G_OBJECT (doc), + check_range_id, + range, + (GDestroyNotify)g_free); + } + + if (pluma_spell_utils_skip_no_spell_check (start, end)) + { + if (!gtk_text_iter_inside_word (end)) + { + /* if we're neither inside a word, + * we must be in some spaces. + * skip backward to the end of the previous word. */ + if (!gtk_text_iter_is_end (end)) + { + gtk_text_iter_backward_word_start (end); + gtk_text_iter_forward_word_end (end); + } + } + else + { + if (!gtk_text_iter_ends_word (end)) + gtk_text_iter_forward_word_end (end); + } + } + else + { + /* no spell checking in the specified range */ + start = end; + } + + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->start_mark, + start); + gtk_text_buffer_move_mark (GTK_TEXT_BUFFER (doc), + range->end_mark, + end); + + range->mw_start = -1; + range->mw_end = -1; + + update_current (doc, gtk_text_iter_get_offset (start)); +} + +static gchar * +get_current_word (PlumaDocument *doc, gint *start, gint *end) +{ + const CheckRange *range; + GtkTextIter end_iter; + GtkTextIter current_iter; + gint range_end; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, NULL); + g_return_val_if_fail (start != NULL, NULL); + g_return_val_if_fail (end != NULL, NULL); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, NULL); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + &end_iter, range->end_mark); + + range_end = gtk_text_iter_get_offset (&end_iter); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + ¤t_iter, range->current_mark); + + end_iter = current_iter; + + if (!gtk_text_iter_is_end (&end_iter)) + { + pluma_debug_message (DEBUG_PLUGINS, "Current is not end"); + + gtk_text_iter_forward_word_end (&end_iter); + } + + *start = gtk_text_iter_get_offset (¤t_iter); + *end = MIN (gtk_text_iter_get_offset (&end_iter), range_end); + + pluma_debug_message (DEBUG_PLUGINS, "Current word extends [%d, %d]", *start, *end); + + if (!(*start < *end)) + return NULL; + + return gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), + ¤t_iter, + &end_iter, + TRUE); +} + +static gboolean +goto_next_word (PlumaDocument *doc) +{ + CheckRange *range; + GtkTextIter current_iter; + GtkTextIter old_current_iter; + GtkTextIter end_iter; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (doc != NULL, FALSE); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, FALSE); + + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), + ¤t_iter, + range->current_mark); + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end_iter); + + old_current_iter = current_iter; + + gtk_text_iter_forward_word_ends (¤t_iter, 2); + gtk_text_iter_backward_word_start (¤t_iter); + + if (pluma_spell_utils_skip_no_spell_check (¤t_iter, &end_iter) && + (gtk_text_iter_compare (&old_current_iter, ¤t_iter) < 0) && + (gtk_text_iter_compare (¤t_iter, &end_iter) < 0)) + { + update_current (doc, gtk_text_iter_get_offset (¤t_iter)); + return TRUE; + } + + return FALSE; +} + +static gchar * +get_next_misspelled_word (PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gint start, end; + gchar *word; + PlumaSpellChecker *spell; + + g_return_val_if_fail (view != NULL, NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_val_if_fail (doc != NULL, NULL); + + range = get_check_range (doc); + g_return_val_if_fail (range != NULL, NULL); + + spell = get_spell_checker_from_document (doc); + g_return_val_if_fail (spell != NULL, NULL); + + word = get_current_word (doc, &start, &end); + if (word == NULL) + return NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); + + while (pluma_spell_checker_check_word (spell, word, -1)) + { + g_free (word); + + if (!goto_next_word (doc)) + return NULL; + + /* may return null if we reached the end of the selection */ + word = get_current_word (doc, &start, &end); + if (word == NULL) + return NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Word to check: %s", word); + } + + if (!goto_next_word (doc)) + update_current (doc, gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc))); + + if (word != NULL) + { + GtkTextIter s, e; + + range->mw_start = start; + range->mw_end = end; + + pluma_debug_message (DEBUG_PLUGINS, "Select [%d, %d]", start, end); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &s, start); + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &e, end); + + gtk_text_buffer_select_range (GTK_TEXT_BUFFER (doc), &s, &e); + + pluma_view_scroll_to_cursor (view); + } + else + { + range->mw_start = -1; + range->mw_end = -1; + } + + return word; +} + +static void +ignore_cb (PlumaSpellCheckerDialog *dlg, + const gchar *w, + PlumaView *view) +{ + gchar *word = NULL; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (w != NULL); + g_return_if_fail (view != NULL); + + word = get_next_misspelled_word (view); + if (word == NULL) + { + pluma_spell_checker_dialog_set_completed (dlg); + + return; + } + + pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg), + word, + -1); + + g_free (word); +} + +static void +change_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change, + PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gchar *w = NULL; + GtkTextIter start, end; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + g_return_if_fail (change != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); + if (range->mw_end < 0) + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); + else + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); + + w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); + g_return_if_fail (w != NULL); + + if (strcmp (w, word) != 0) + { + g_free (w); + return; + } + + g_free (w); + + gtk_text_buffer_begin_user_action (GTK_TEXT_BUFFER(doc)); + + gtk_text_buffer_delete (GTK_TEXT_BUFFER (doc), &start, &end); + gtk_text_buffer_insert (GTK_TEXT_BUFFER (doc), &start, change, -1); + + gtk_text_buffer_end_user_action (GTK_TEXT_BUFFER(doc)); + + update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +change_all_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + const gchar *change, + PlumaView *view) +{ + PlumaDocument *doc; + CheckRange *range; + gchar *w = NULL; + GtkTextIter start, end; + gint flags = 0; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + g_return_if_fail (change != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + range = get_check_range (doc); + g_return_if_fail (range != NULL); + + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &start, range->mw_start); + if (range->mw_end < 0) + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (doc), &end); + else + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (doc), &end, range->mw_end); + + w = gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (doc), &start, &end, TRUE); + g_return_if_fail (w != NULL); + + if (strcmp (w, word) != 0) + { + g_free (w); + return; + } + + g_free (w); + + PLUMA_SEARCH_SET_CASE_SENSITIVE (flags, TRUE); + PLUMA_SEARCH_SET_ENTIRE_WORD (flags, TRUE); + + /* CHECK: currently this function does escaping etc */ + pluma_document_replace_all (doc, word, change, flags); + + update_current (doc, range->mw_start + g_utf8_strlen (change, -1)); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +add_word_cb (PlumaSpellCheckerDialog *dlg, + const gchar *word, + PlumaView *view) +{ + g_return_if_fail (view != NULL); + g_return_if_fail (word != NULL); + + /* go to next misspelled word */ + ignore_cb (dlg, word, view); +} + +static void +language_dialog_response (GtkDialog *dlg, + gint res_id, + PlumaSpellChecker *spell) +{ + if (res_id == GTK_RESPONSE_OK) + { + const PlumaSpellCheckerLanguage *lang; + + lang = pluma_spell_language_get_selected_language (PLUMA_SPELL_LANGUAGE_DIALOG (dlg)); + if (lang != NULL) + pluma_spell_checker_set_language (spell, lang); + } + + gtk_widget_destroy (GTK_WIDGET (dlg)); +} + +static void +set_language_cb (GtkAction *action, + ActionData *action_data) +{ + PlumaDocument *doc; + PlumaSpellChecker *spell; + const PlumaSpellCheckerLanguage *lang; + GtkWidget *dlg; + GtkWindowGroup *wg; + gchar *data_dir; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (action_data->window); + g_return_if_fail (doc != NULL); + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + lang = pluma_spell_checker_get_language (spell); + + data_dir = pluma_plugin_get_data_dir (action_data->plugin); + dlg = pluma_spell_language_dialog_new (GTK_WINDOW (action_data->window), + lang, + data_dir); + g_free (data_dir); + + wg = pluma_window_get_group (action_data->window); + + gtk_window_group_add_window (wg, GTK_WINDOW (dlg)); + + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + + g_signal_connect (dlg, + "response", + G_CALLBACK (language_dialog_response), + spell); + + gtk_widget_show (dlg); +} + +static void +spell_cb (GtkAction *action, + ActionData *action_data) +{ + PlumaView *view; + PlumaDocument *doc; + PlumaSpellChecker *spell; + GtkWidget *dlg; + GtkTextIter start, end; + gchar *word; + gchar *data_dir; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (action_data->window); + g_return_if_fail (view != NULL); + + doc = PLUMA_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + g_return_if_fail (doc != NULL); + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + if (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (doc)) <= 0) + { + WindowData *data; + GtkWidget *statusbar; + + data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + statusbar = pluma_window_get_statusbar (action_data->window); + pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar), + data->message_cid, + _("The document is empty.")); + + return; + } + + if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end)) + { + /* no selection, get the whole doc */ + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (doc), + &start, + &end); + } + + set_check_range (doc, &start, &end); + + word = get_next_misspelled_word (view); + if (word == NULL) + { + WindowData *data; + GtkWidget *statusbar; + + data = (WindowData *) g_object_get_data (G_OBJECT (action_data->window), + WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + statusbar = pluma_window_get_statusbar (action_data->window); + pluma_statusbar_flash_message (PLUMA_STATUSBAR (statusbar), + data->message_cid, + _("No misspelled words")); + + return; + } + + data_dir = pluma_plugin_get_data_dir (action_data->plugin); + dlg = pluma_spell_checker_dialog_new_from_spell_checker (spell, data_dir); + g_free (data_dir); + gtk_window_set_modal (GTK_WINDOW (dlg), TRUE); + gtk_window_set_transient_for (GTK_WINDOW (dlg), + GTK_WINDOW (action_data->window)); + + g_signal_connect (dlg, "ignore", G_CALLBACK (ignore_cb), view); + g_signal_connect (dlg, "ignore_all", G_CALLBACK (ignore_cb), view); + + g_signal_connect (dlg, "change", G_CALLBACK (change_cb), view); + g_signal_connect (dlg, "change_all", G_CALLBACK (change_all_cb), view); + + g_signal_connect (dlg, "add_word_to_personal", G_CALLBACK (add_word_cb), view); + + pluma_spell_checker_dialog_set_misspelled_word (PLUMA_SPELL_CHECKER_DIALOG (dlg), + word, + -1); + + g_free (word); + + gtk_widget_show (dlg); +} + +static void +set_auto_spell (PlumaWindow *window, + PlumaDocument *doc, + gboolean active) +{ + PlumaAutomaticSpellChecker *autospell; + PlumaSpellChecker *spell; + + spell = get_spell_checker_from_document (doc); + g_return_if_fail (spell != NULL); + + autospell = pluma_automatic_spell_checker_get_from_document (doc); + + if (active) + { + if (autospell == NULL) + { + PlumaView *active_view; + + active_view = pluma_window_get_active_view (window); + g_return_if_fail (active_view != NULL); + + autospell = pluma_automatic_spell_checker_new (doc, spell); + pluma_automatic_spell_checker_attach_view (autospell, active_view); + pluma_automatic_spell_checker_recheck_all (autospell); + } + } + else + { + if (autospell != NULL) + pluma_automatic_spell_checker_free (autospell); + } +} + +static void +auto_spell_cb (GtkAction *action, + PlumaWindow *window) +{ + + PlumaDocument *doc; + gboolean active; + + pluma_debug (DEBUG_PLUGINS); + + active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + + pluma_debug_message (DEBUG_PLUGINS, active ? "Auto Spell activated" : "Auto Spell deactivated"); + + doc = pluma_window_get_active_document (window); + if (doc == NULL) + return; + + pluma_document_set_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED, + active ? "1" : NULL, NULL); + + set_auto_spell (window, doc, active); +} + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + g_object_unref (data->action_group); + g_slice_free (WindowData, data); +} + +static void +free_action_data (gpointer data) +{ + g_return_if_fail (data != NULL); + + g_slice_free (ActionData, data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + PlumaDocument *doc; + PlumaView *view; + gboolean autospell; + GtkAction *action; + + pluma_debug (DEBUG_PLUGINS); + + doc = pluma_window_get_active_document (window); + view = pluma_window_get_active_view (window); + + autospell = (doc != NULL && + pluma_automatic_spell_checker_get_from_document (doc) != NULL); + + if (doc != NULL) + { + PlumaTab *tab; + PlumaTabState state; + + tab = pluma_window_get_active_tab (window); + state = pluma_tab_get_state (tab); + + /* If the document is loading we can't get the metadata so we + endup with an useless speller */ + if (state == PLUMA_TAB_STATE_NORMAL) + { + action = gtk_action_group_get_action (data->action_group, + "AutoSpell"); + + g_signal_handlers_block_by_func (action, auto_spell_cb, + window); + set_auto_spell (window, doc, autospell); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + autospell); + g_signal_handlers_unblock_by_func (action, auto_spell_cb, + window); + } + } + + gtk_action_group_set_sensitive (data->action_group, + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +set_auto_spell_from_metadata (PlumaWindow *window, + PlumaDocument *doc, + GtkActionGroup *action_group) +{ + gboolean active = FALSE; + gchar *active_str; + PlumaDocument *active_doc; + + active_str = pluma_document_get_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED); + + if (active_str) + { + active = *active_str == '1'; + + g_free (active_str); + } + + set_auto_spell (window, doc, active); + + /* In case that the doc is the active one we mark the spell action */ + active_doc = pluma_window_get_active_document (window); + + if (active_doc == doc && action_group != NULL) + { + GtkAction *action; + + action = gtk_action_group_get_action (action_group, + "AutoSpell"); + + g_signal_handlers_block_by_func (action, auto_spell_cb, + window); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + active); + g_signal_handlers_unblock_by_func (action, auto_spell_cb, + window); + } +} + +static void +on_document_loaded (PlumaDocument *doc, + const GError *error, + PlumaWindow *window) +{ + if (error == NULL) + { + WindowData *data; + PlumaSpellChecker *spell; + + spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), + spell_checker_id)); + if (spell != NULL) + { + set_language_from_metadata (spell, doc); + } + + data = g_object_get_data (G_OBJECT (window), + WINDOW_DATA_KEY); + + set_auto_spell_from_metadata (window, doc, data->action_group); + } +} + +static void +on_document_saved (PlumaDocument *doc, + const GError *error, + PlumaWindow *window) +{ + PlumaAutomaticSpellChecker *autospell; + PlumaSpellChecker *spell; + const gchar *key; + + if (error != NULL) + { + return; + } + + /* Make sure to save the metadata here too */ + autospell = pluma_automatic_spell_checker_get_from_document (doc); + spell = PLUMA_SPELL_CHECKER (g_object_get_qdata (G_OBJECT (doc), spell_checker_id)); + + if (spell != NULL) + { + key = pluma_spell_checker_language_to_key (pluma_spell_checker_get_language (spell)); + } + else + { + key = NULL; + } + + pluma_document_set_metadata (doc, + PLUMA_METADATA_ATTRIBUTE_SPELL_ENABLED, + autospell != NULL ? "1" : NULL, + PLUMA_METADATA_ATTRIBUTE_SPELL_LANGUAGE, + key, + NULL); +} + +static void +tab_added_cb (PlumaWindow *window, + PlumaTab *tab, + gpointer useless) +{ + PlumaDocument *doc; + PlumaView *view; + + doc = pluma_tab_get_document (tab); + view = pluma_tab_get_view (tab); + + g_signal_connect (doc, "loaded", + G_CALLBACK (on_document_loaded), + window); + + g_signal_connect (doc, "saved", + G_CALLBACK (on_document_saved), + window); +} + +static void +tab_removed_cb (PlumaWindow *window, + PlumaTab *tab, + gpointer useless) +{ + PlumaDocument *doc; + PlumaView *view; + + doc = pluma_tab_get_document (tab); + view = pluma_tab_get_view (tab); + + g_signal_handlers_disconnect_by_func (doc, on_document_loaded, window); + g_signal_handlers_disconnect_by_func (doc, on_document_saved, window); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + ActionData *action_data; + GList *docs, *l; + + pluma_debug (DEBUG_PLUGINS); + + data = g_slice_new (WindowData); + action_data = g_slice_new (ActionData); + action_data->plugin = plugin; + action_data->window = window; + + manager = pluma_window_get_ui_manager (window); + + data->action_group = gtk_action_group_new ("PlumaSpellPluginActions"); + gtk_action_group_set_translation_domain (data->action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions_full (data->action_group, + action_entries, + G_N_ELEMENTS (action_entries), + action_data, + (GDestroyNotify) free_action_data); + gtk_action_group_add_toggle_actions (data->action_group, + toggle_action_entries, + G_N_ELEMENTS (toggle_action_entries), + window); + + gtk_ui_manager_insert_action_group (manager, data->action_group, -1); + + data->ui_id = gtk_ui_manager_new_merge_id (manager); + + data->message_cid = gtk_statusbar_get_context_id + (GTK_STATUSBAR (pluma_window_get_statusbar (window)), + "spell_plugin_message"); + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "CheckSpell", + "CheckSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "AutoSpell", + "AutoSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "ConfigSpell", + "ConfigSpell", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + update_ui_real (window, data); + + docs = pluma_window_get_documents (window); + for (l = docs; l != NULL; l = g_list_next (l)) + { + PlumaDocument *doc = PLUMA_DOCUMENT (l->data); + + set_auto_spell_from_metadata (window, doc, + data->action_group); + + g_signal_handlers_disconnect_by_func (doc, + on_document_loaded, + window); + + g_signal_handlers_disconnect_by_func (doc, + on_document_saved, + window); + } + + data->tab_added_id = + g_signal_connect (window, "tab-added", + G_CALLBACK (tab_added_cb), NULL); + data->tab_removed_id = + g_signal_connect (window, "tab-removed", + G_CALLBACK (tab_removed_cb), NULL); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, data->ui_id); + gtk_ui_manager_remove_action_group (manager, data->action_group); + + g_signal_handler_disconnect (window, data->tab_added_id); + g_signal_handler_disconnect (window, data->tab_removed_id); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, data); +} + +static void +pluma_spell_plugin_class_init (PlumaSpellPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_spell_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; + + if (spell_checker_id == 0) + spell_checker_id = g_quark_from_string ("PlumaSpellCheckerID"); + + if (check_range_id == 0) + check_range_id = g_quark_from_string ("CheckRangeID"); +} diff --git a/plugins/spell/pluma-spell-plugin.h b/plugins/spell/pluma-spell-plugin.h new file mode 100755 index 00000000..44e70a66 --- /dev/null +++ b/plugins/spell/pluma-spell-plugin.h @@ -0,0 +1,75 @@ +/* + * pluma-spell-plugin.h + * + * Copyright (C) 2002-2005 Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_SPELL_PLUGIN_H__ +#define __PLUMA_SPELL_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_SPELL_PLUGIN (pluma_spell_plugin_get_type ()) +#define PLUMA_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPlugin)) +#define PLUMA_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPluginClass)) +#define PLUMA_IS_SPELL_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_SPELL_PLUGIN)) +#define PLUMA_IS_SPELL_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_SPELL_PLUGIN)) +#define PLUMA_SPELL_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_SPELL_PLUGIN, PlumaSpellPluginClass)) + +/* Private structure type */ +typedef struct _PlumaSpellPluginPrivate PlumaSpellPluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaSpellPlugin PlumaSpellPlugin; + +struct _PlumaSpellPlugin +{ + PlumaPlugin parent_instance; +}; + +/* + * Class definition + */ +typedef struct _PlumaSpellPluginClass PlumaSpellPluginClass; + +struct _PlumaSpellPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_spell_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_PLUGIN_H__ */ diff --git a/plugins/spell/pluma-spell-utils.c b/plugins/spell/pluma-spell-utils.c new file mode 100755 index 00000000..504cf042 --- /dev/null +++ b/plugins/spell/pluma-spell-utils.c @@ -0,0 +1,94 @@ +/* + * pluma-spell-utils.c + * This file is part of pluma + * + * Copyright (C) 2010 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include "pluma-spell-utils.h" +#include + +gboolean +pluma_spell_utils_is_digit (const char *text, gssize length) +{ + gunichar c; + const gchar *p; + const gchar *end; + + g_return_val_if_fail (text != NULL, FALSE); + + if (length < 0) + length = strlen (text); + + p = text; + end = text + length; + + while (p != end) { + const gchar *next; + next = g_utf8_next_char (p); + + c = g_utf8_get_char (p); + + if (!g_unichar_isdigit (c) && c != '.' && c != ',') + return FALSE; + + p = next; + } + + return TRUE; +} + +gboolean +pluma_spell_utils_skip_no_spell_check (GtkTextIter *start, + GtkTextIter *end) +{ + GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (start)); + + while (gtk_source_buffer_iter_has_context_class (buffer, start, "no-spell-check")) + { + GtkTextIter last = *start; + + if (!gtk_source_buffer_iter_forward_to_context_class_toggle (buffer, start, "no-spell-check")) + { + return FALSE; + } + + if (gtk_text_iter_compare (start, &last) <= 0) + { + return FALSE; + } + + gtk_text_iter_forward_word_end (start); + gtk_text_iter_backward_word_start (start); + + if (gtk_text_iter_compare (start, &last) <= 0) + { + return FALSE; + } + + if (gtk_text_iter_compare (start, end) >= 0) + { + return FALSE; + } + } + + return TRUE; +} + diff --git a/plugins/spell/pluma-spell-utils.h b/plugins/spell/pluma-spell-utils.h new file mode 100755 index 00000000..a9d2eaf2 --- /dev/null +++ b/plugins/spell/pluma-spell-utils.h @@ -0,0 +1,37 @@ +/* + * pluma-spell-utils.h + * This file is part of pluma + * + * Copyright (C) 2010 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __PLUMA_SPELL_UTILS_H__ +#define __PLUMA_SPELL_UTILS_H__ + +#include + +G_BEGIN_DECLS + +gboolean pluma_spell_utils_is_digit (const char *text, gssize length); + +gboolean pluma_spell_utils_skip_no_spell_check (GtkTextIter *start, GtkTextIter *end); + +G_END_DECLS + +#endif /* __PLUMA_SPELL_UTILS_H__ */ + diff --git a/plugins/spell/spell.gedit-plugin.desktop.in b/plugins/spell/spell.gedit-plugin.desktop.in deleted file mode 100755 index c75c9eee..00000000 --- a/plugins/spell/spell.gedit-plugin.desktop.in +++ /dev/null @@ -1,9 +0,0 @@ -[Gedit Plugin] -Module=spell -IAge=2 -_Name=Spell Checker -_Description=Checks the spelling of the current document. -Icon=gtk-spell-check -Authors=Paolo Maggi -Copyright=Copyright © 2002-2005 Paolo Maggi -Website=http://www.gedit.org diff --git a/plugins/spell/spell.pluma-plugin.desktop.in b/plugins/spell/spell.pluma-plugin.desktop.in new file mode 100755 index 00000000..c4400dc3 --- /dev/null +++ b/plugins/spell/spell.pluma-plugin.desktop.in @@ -0,0 +1,9 @@ +[Pluma Plugin] +Module=spell +IAge=2 +_Name=Spell Checker +_Description=Checks the spelling of the current document. +Icon=gtk-spell-check +Authors=Paolo Maggi +Copyright=Copyright © 2002-2005 Paolo Maggi +Website=http://www.pluma.org diff --git a/plugins/taglist/HTML.tags.xml.in b/plugins/taglist/HTML.tags.xml.in index 116cc247..5eedb254 100755 --- a/plugins/taglist/HTML.tags.xml.in +++ b/plugins/taglist/HTML.tags.xml.in @@ -1,5 +1,5 @@ - + diff --git a/plugins/taglist/Latex.tags.xml.in b/plugins/taglist/Latex.tags.xml.in index 5ac71c0d..78242fe3 100755 --- a/plugins/taglist/Latex.tags.xml.in +++ b/plugins/taglist/Latex.tags.xml.in @@ -1,5 +1,5 @@ - + \cite{ diff --git a/plugins/taglist/Makefile.am b/plugins/taglist/Makefile.am index b04f4584..dd3306f0 100755 --- a/plugins/taglist/Makefile.am +++ b/plugins/taglist/Makefile.am @@ -1,7 +1,7 @@ # Tag list plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) -taglistdir = $(GEDIT_PLUGINS_DATA_DIR)/taglist +taglistdir = $(PLUMA_PLUGINS_DATA_DIR)/taglist taglist_in_files = \ HTML.tags.xml.in \ @@ -13,26 +13,26 @@ taglist_DATA = $(taglist_in_files:.tags.xml.in=.tags.gz) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) plugin_LTLIBRARIES = libtaglist.la libtaglist_la_SOURCES = \ - gedit-taglist-plugin-parser.c \ - gedit-taglist-plugin-parser.h \ - gedit-taglist-plugin-panel.c \ - gedit-taglist-plugin-panel.h \ - gedit-taglist-plugin.c \ - gedit-taglist-plugin.h + pluma-taglist-plugin-parser.c \ + pluma-taglist-plugin-parser.h \ + pluma-taglist-plugin-panel.c \ + pluma-taglist-plugin-panel.h \ + pluma-taglist-plugin.c \ + pluma-taglist-plugin.h libtaglist_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libtaglist_la_LIBADD = $(GEDIT_LIBS) +libtaglist_la_LIBADD = $(PLUMA_LIBS) -plugin_in_files = taglist.gedit-plugin.desktop.in +plugin_in_files = taglist.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache GZIP_ENV = -9 @@ -41,7 +41,7 @@ GZIP_ENV = -9 LC_ALL=C $(INTLTOOL_MERGE) $(top_srcdir)/po $< $(@:.gz=) -x -u -c $(top_builddir)/po/.intltool-merge-cache GZIP=$(GZIP_ENV) gzip -f $(@:.gz=) -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = \ $(taglist_in_files) $(taglist_DATA) \ diff --git a/plugins/taglist/XSLT.tags.xml.in b/plugins/taglist/XSLT.tags.xml.in index f9591a25..e625f6ca 100755 --- a/plugins/taglist/XSLT.tags.xml.in +++ b/plugins/taglist/XSLT.tags.xml.in @@ -1,9 +1,9 @@ - + <xsl:apply-imports> diff --git a/plugins/taglist/XUL.tags.xml.in b/plugins/taglist/XUL.tags.xml.in index fc4c26a7..3d5d3c8c 100755 --- a/plugins/taglist/XUL.tags.xml.in +++ b/plugins/taglist/XUL.tags.xml.in @@ -1,5 +1,5 @@ - + diff --git a/plugins/taglist/gedit-taglist-plugin-panel.c b/plugins/taglist/gedit-taglist-plugin-panel.c deleted file mode 100755 index d66acc08..00000000 --- a/plugins/taglist/gedit-taglist-plugin-panel.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - * gedit-taglist-plugin-panel.c - * This file is part of gedit - * - * Copyright (C) 2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "gedit-taglist-plugin-panel.h" -#include "gedit-taglist-plugin-parser.h" - -#include -#include -#include - -#include -#include - -#define GEDIT_TAGLIST_PLUGIN_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, \ - GeditTaglistPluginPanelPrivate)) - -enum -{ - COLUMN_TAG_NAME, - COLUMN_TAG_INDEX_IN_GROUP, - NUM_COLUMNS -}; - -struct _GeditTaglistPluginPanelPrivate -{ - GeditWindow *window; - - GtkWidget *tag_groups_combo; - GtkWidget *tags_list; - GtkWidget *preview; - - TagGroup *selected_tag_group; - - gchar *data_dir; -}; - -GEDIT_PLUGIN_DEFINE_TYPE (GeditTaglistPluginPanel, gedit_taglist_plugin_panel, GTK_TYPE_VBOX) - -enum -{ - PROP_0, - PROP_WINDOW, -}; - -static void -set_window (GeditTaglistPluginPanel *panel, - GeditWindow *window) -{ - g_return_if_fail (panel->priv->window == NULL); - g_return_if_fail (GEDIT_IS_WINDOW (window)); - - panel->priv->window = window; - - /* TODO */ -} - -static void -gedit_taglist_plugin_panel_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GeditTaglistPluginPanel *panel = GEDIT_TAGLIST_PLUGIN_PANEL (object); - - switch (prop_id) - { - case PROP_WINDOW: - set_window (panel, g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_taglist_plugin_panel_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GeditTaglistPluginPanel *panel = GEDIT_TAGLIST_PLUGIN_PANEL (object); - - switch (prop_id) - { - case PROP_WINDOW: - g_value_set_object (value, - GEDIT_TAGLIST_PLUGIN_PANEL_GET_PRIVATE (panel)->window); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gedit_taglist_plugin_panel_finalize (GObject *object) -{ - GeditTaglistPluginPanel *panel = GEDIT_TAGLIST_PLUGIN_PANEL (object); - - g_free (panel->priv->data_dir); - - G_OBJECT_CLASS (gedit_taglist_plugin_panel_parent_class)->finalize (object); -} - -static void -gedit_taglist_plugin_panel_class_init (GeditTaglistPluginPanelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gedit_taglist_plugin_panel_finalize; - object_class->get_property = gedit_taglist_plugin_panel_get_property; - object_class->set_property = gedit_taglist_plugin_panel_set_property; - - g_object_class_install_property (object_class, - PROP_WINDOW, - g_param_spec_object ("window", - "Window", - "The GeditWindow this GeditTaglistPluginPanel is associated with", - GEDIT_TYPE_WINDOW, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (object_class, sizeof(GeditTaglistPluginPanelPrivate)); -} - -static void -insert_tag (GeditTaglistPluginPanel *panel, - Tag *tag, - gboolean grab_focus) -{ - GeditView *view; - GtkTextBuffer *buffer; - GtkTextIter start, end; - GtkTextIter cursor; - gboolean sel = FALSE; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (panel->priv->window); - g_return_if_fail (view != NULL); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - gtk_text_buffer_begin_user_action (buffer); - - /* always insert the begin tag at the beginning of the selection - * and the end tag at the end, if there is no selection they will - * be automatically inserted at the cursor position. - */ - - if (tag->begin != NULL) - { - sel = gtk_text_buffer_get_selection_bounds (buffer, - &start, - &end); - - gtk_text_buffer_insert (buffer, - &start, - (gchar *)tag->begin, - -1); - - /* get iterators again since they have been invalidated and move - * the cursor after the selection */ - gtk_text_buffer_get_selection_bounds (buffer, - &start, - &cursor); - } - - if (tag->end != NULL) - { - sel = gtk_text_buffer_get_selection_bounds (buffer, - &start, - &end); - - gtk_text_buffer_insert (buffer, - &end, - (gchar *)tag->end, - -1); - - /* if there is no selection and we have a paired tag, move the - * cursor between the pair, otherwise move it at the end */ - if (!sel) - { - gint offset; - - offset = gtk_text_iter_get_offset (&end) - - g_utf8_strlen ((gchar *)tag->end, -1); - - gtk_text_buffer_get_iter_at_offset (buffer, - &end, - offset); - } - - cursor = end; - } - - gtk_text_buffer_place_cursor (buffer, &cursor); - - gtk_text_buffer_end_user_action (buffer); - - if (grab_focus) - gtk_widget_grab_focus (GTK_WIDGET (view)); -} - -static void -tag_list_row_activated_cb (GtkTreeView *tag_list, - GtkTreePath *path, - GtkTreeViewColumn *column, - GeditTaglistPluginPanel *panel) -{ - GtkTreeIter iter; - GtkTreeModel *model; - gint index; - - gedit_debug (DEBUG_PLUGINS); - - model = gtk_tree_view_get_model (tag_list); - - gtk_tree_model_get_iter (model, &iter, path); - g_return_if_fail (&iter != NULL); - - gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); - - gedit_debug_message (DEBUG_PLUGINS, "Index: %d", index); - - insert_tag (panel, - (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index), - TRUE); -} - -static gboolean -tag_list_key_press_event_cb (GtkTreeView *tag_list, - GdkEventKey *event, - GeditTaglistPluginPanel *panel) -{ - gboolean grab_focus; - - grab_focus = (event->state & GDK_CONTROL_MASK) != 0; - - if (event->keyval == GDK_Return) - { - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - gint index; - - gedit_debug_message (DEBUG_PLUGINS, "RETURN Pressed"); - - model = gtk_tree_view_get_model (tag_list); - - selection = gtk_tree_view_get_selection (tag_list); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); - - gedit_debug_message (DEBUG_PLUGINS, "Index: %d", index); - - insert_tag (panel, - (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index), - grab_focus); - } - - return TRUE; - } - - return FALSE; -} - -static GtkTreeModel* -create_model (GeditTaglistPluginPanel *panel) -{ - gint i = 0; - GtkListStore *store; - GtkTreeIter iter; - GList *list; - - gedit_debug (DEBUG_PLUGINS); - - /* create list store */ - store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT); - - /* add data to the list store */ - list = panel->priv->selected_tag_group->tags; - - while (list != NULL) - { - const gchar* tag_name; - - tag_name = (gchar *)((Tag*)list->data)->name; - - gedit_debug_message (DEBUG_PLUGINS, "%d : %s", i, tag_name); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_TAG_NAME, tag_name, - COLUMN_TAG_INDEX_IN_GROUP, i, - -1); - ++i; - - list = g_list_next (list); - } - - gedit_debug_message (DEBUG_PLUGINS, "Rows: %d ", - gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL)); - - return GTK_TREE_MODEL (store); -} - -static void -populate_tags_list (GeditTaglistPluginPanel *panel) -{ - GtkTreeModel* model; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (taglist != NULL); - - model = create_model (panel); - gtk_tree_view_set_model (GTK_TREE_VIEW (panel->priv->tags_list), - model); - g_object_unref (model); -} - -static TagGroup * -find_tag_group (const gchar *name) -{ - GList *l; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (taglist != NULL, NULL); - - for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) - { - if (strcmp (name, (gchar *)((TagGroup*)l->data)->name) == 0) - return (TagGroup*)l->data; - } - - return NULL; -} - -static void -populate_tag_groups_combo (GeditTaglistPluginPanel *panel) -{ - GList *l; - GtkComboBox *combo; - - gedit_debug (DEBUG_PLUGINS); - - combo = GTK_COMBO_BOX (panel->priv->tag_groups_combo); - - if (taglist == NULL) - return; - - for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) - { - gtk_combo_box_append_text (combo, - (gchar *)((TagGroup*)l->data)->name); - } - - gtk_combo_box_set_active (combo, 0); - - return; -} - -static void -selected_group_changed (GtkComboBox *combo, - GeditTaglistPluginPanel *panel) -{ - gchar* group_name; - - gedit_debug (DEBUG_PLUGINS); - - group_name = gtk_combo_box_get_active_text (combo); - - if ((group_name == NULL) || (strlen (group_name) <= 0)) - { - g_free (group_name); - return; - } - - if ((panel->priv->selected_tag_group == NULL) || - (strcmp (group_name, (gchar *)panel->priv->selected_tag_group->name) != 0)) - { - panel->priv->selected_tag_group = find_tag_group (group_name); - g_return_if_fail (panel->priv->selected_tag_group != NULL); - - gedit_debug_message (DEBUG_PLUGINS, - "New selected group: %s", - panel->priv->selected_tag_group->name); - - populate_tags_list (panel); - } - - /* Clean up preview */ - gtk_label_set_text (GTK_LABEL (panel->priv->preview), - ""); - - g_free (group_name); -} - -static gchar * -create_preview_string (Tag *tag) -{ - GString *str; - - str = g_string_new (""); - - if (tag->begin != NULL) - { - gchar *markup; - - markup = g_markup_escape_text ((gchar *)tag->begin, -1); - g_string_append (str, markup); - g_free (markup); - } - - if (tag->end != NULL) - { - gchar *markup; - - markup = g_markup_escape_text ((gchar *)tag->end, -1); - g_string_append (str, markup); - g_free (markup); - } - - g_string_append (str, ""); - - return g_string_free (str, FALSE); -} - -static void -update_preview (GeditTaglistPluginPanel *panel, - Tag *tag) -{ - gchar *str; - - str = create_preview_string (tag); - - gtk_label_set_markup (GTK_LABEL (panel->priv->preview), - str); - - g_free (str); -} - -static void -tag_list_cursor_changed_cb (GtkTreeView *tag_list, - gpointer data) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - gint index; - - GeditTaglistPluginPanel *panel = (GeditTaglistPluginPanel *)data; - - model = gtk_tree_view_get_model (tag_list); - - selection = gtk_tree_view_get_selection (tag_list); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); - - gedit_debug_message (DEBUG_PLUGINS, "Index: %d", index); - - update_preview (panel, - (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index)); - } -} - -static gboolean -tags_list_query_tooltip_cb (GtkWidget *widget, - gint x, - gint y, - gboolean keyboard_tip, - GtkTooltip *tooltip, - GeditTaglistPluginPanel *panel) -{ - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreePath *path = NULL; - gint index; - Tag *tag; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); - - if (keyboard_tip) - { - gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), - &path, - NULL); - - if (path == NULL) - { - return FALSE; - } - } - else - { - gint bin_x, bin_y; - - gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget), - x, y, - &bin_x, &bin_y); - - if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), - bin_x, bin_y, - &path, - NULL, NULL, NULL)) - { - return FALSE; - } - } - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - COLUMN_TAG_INDEX_IN_GROUP, &index, - -1); - - tag = g_list_nth_data (panel->priv->selected_tag_group->tags, index); - if (tag != NULL) - { - gchar *tip; - - tip = create_preview_string (tag); - gtk_tooltip_set_markup (tooltip, tip); - g_free (tip); - gtk_tree_path_free (path); - - return TRUE; - } - - gtk_tree_path_free (path); - - return FALSE; -} - -static gboolean -expose_event_cb (GtkWidget *panel, - GdkEventExpose *event, - gpointer user_data) -{ - GeditTaglistPluginPanel *ppanel = GEDIT_TAGLIST_PLUGIN_PANEL (panel); - - gedit_debug (DEBUG_PLUGINS); - - /* If needed load taglists from files at the first expose */ - if (taglist == NULL) - create_taglist (ppanel->priv->data_dir); - - /* And populate combo box */ - populate_tag_groups_combo (GEDIT_TAGLIST_PLUGIN_PANEL (panel)); - - /* We need to manage only the first expose event -> disconnect */ - g_signal_handlers_disconnect_by_func (panel, expose_event_cb, NULL); - - return FALSE; -} - -static void -set_combo_tooltip (GtkWidget *widget, - gpointer data) -{ - if (GTK_IS_BUTTON (widget)) - { - gtk_widget_set_tooltip_text (widget, - _("Select the group of tags you want to use")); - } -} - -static void -realize_tag_groups_combo (GtkWidget *combo, - gpointer data) -{ - gtk_container_forall (GTK_CONTAINER (combo), - set_combo_tooltip, - NULL); -} - -static void -add_preview_widget (GeditTaglistPluginPanel *panel) -{ - GtkWidget *expander; - GtkWidget *frame; - - expander = gtk_expander_new_with_mnemonic (_("_Preview")); - - panel->priv->preview = gtk_label_new (NULL); - gtk_widget_set_size_request (panel->priv->preview, -1, 80); - - gtk_label_set_line_wrap (GTK_LABEL (panel->priv->preview), TRUE); - gtk_label_set_use_markup (GTK_LABEL (panel->priv->preview), TRUE); - gtk_misc_set_alignment (GTK_MISC (panel->priv->preview), 0, 0); - gtk_misc_set_padding (GTK_MISC (panel->priv->preview), 6, 6); - gtk_label_set_selectable (GTK_LABEL (panel->priv->preview), TRUE); - gtk_label_set_selectable (GTK_LABEL (panel->priv->preview), TRUE); - gtk_label_set_ellipsize (GTK_LABEL (panel->priv->preview), - PANGO_ELLIPSIZE_END); - - frame = gtk_frame_new (0); - gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - - gtk_container_add (GTK_CONTAINER (frame), - panel->priv->preview); - - gtk_container_add (GTK_CONTAINER (expander), - frame); - - gtk_box_pack_start (GTK_BOX (panel), expander, FALSE, FALSE, 0); - - gtk_widget_show_all (expander); -} - -static void -gedit_taglist_plugin_panel_init (GeditTaglistPluginPanel *panel) -{ - GtkWidget *sw; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - GList *focus_chain = NULL; - - gedit_debug (DEBUG_PLUGINS); - - panel->priv = GEDIT_TAGLIST_PLUGIN_PANEL_GET_PRIVATE (panel); - panel->priv->data_dir = NULL; - - /* Build the window content */ - panel->priv->tag_groups_combo = gtk_combo_box_new_text (); - gtk_box_pack_start (GTK_BOX (panel), - panel->priv->tag_groups_combo, - FALSE, - TRUE, - 0); - - g_signal_connect (panel->priv->tag_groups_combo, - "realize", - G_CALLBACK (realize_tag_groups_combo), - panel); - - sw = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), - GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0); - - /* Create tree view */ - panel->priv->tags_list = gtk_tree_view_new (); - - gedit_utils_set_atk_name_description (panel->priv->tag_groups_combo, - _("Available Tag Lists"), - NULL); - gedit_utils_set_atk_name_description (panel->priv->tags_list, - _("Tags"), - NULL); - gedit_utils_set_atk_relation (panel->priv->tag_groups_combo, - panel->priv->tags_list, - ATK_RELATION_CONTROLLER_FOR); - gedit_utils_set_atk_relation (panel->priv->tags_list, - panel->priv->tag_groups_combo, - ATK_RELATION_CONTROLLED_BY); - - gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (panel->priv->tags_list), FALSE); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (panel->priv->tags_list), FALSE); - - g_object_set (panel->priv->tags_list, "has-tooltip", TRUE, NULL); - - /* Add the tags column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Tags"), - cell, - "text", - COLUMN_TAG_NAME, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (panel->priv->tags_list), - column); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (panel->priv->tags_list), - COLUMN_TAG_NAME); - - gtk_container_add (GTK_CONTAINER (sw), panel->priv->tags_list); - - focus_chain = g_list_prepend (focus_chain, panel->priv->tags_list); - focus_chain = g_list_prepend (focus_chain, panel->priv->tag_groups_combo); - - gtk_container_set_focus_chain (GTK_CONTAINER (panel), - focus_chain); - g_list_free (focus_chain); - - add_preview_widget (panel); - - gtk_widget_show_all (GTK_WIDGET (sw)); - gtk_widget_show (GTK_WIDGET (panel->priv->tag_groups_combo)); - - g_signal_connect_after (panel->priv->tags_list, - "row_activated", - G_CALLBACK (tag_list_row_activated_cb), - panel); - g_signal_connect (panel->priv->tags_list, - "key_press_event", - G_CALLBACK (tag_list_key_press_event_cb), - panel); - g_signal_connect (panel->priv->tags_list, - "query-tooltip", - G_CALLBACK (tags_list_query_tooltip_cb), - panel); - g_signal_connect (panel->priv->tags_list, - "cursor_changed", - G_CALLBACK (tag_list_cursor_changed_cb), - panel); - g_signal_connect (panel->priv->tag_groups_combo, - "changed", - G_CALLBACK (selected_group_changed), - panel); - g_signal_connect (panel, - "expose-event", - G_CALLBACK (expose_event_cb), - NULL); -} - -GtkWidget * -gedit_taglist_plugin_panel_new (GeditWindow *window, - const gchar *data_dir) -{ - GeditTaglistPluginPanel *panel; - - g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL); - - panel = g_object_new (GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, - "window", window, - NULL); - - panel->priv->data_dir = g_strdup (data_dir); - - return GTK_WIDGET (panel); -} diff --git a/plugins/taglist/gedit-taglist-plugin-panel.h b/plugins/taglist/gedit-taglist-plugin-panel.h deleted file mode 100755 index 3f8e82d0..00000000 --- a/plugins/taglist/gedit-taglist-plugin-panel.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * gedit-taglist-plugin-panel.h - * This file is part of gedit - * - * Copyright (C) 2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifndef __GEDIT_TAGLIST_PLUGIN_PANEL_H__ -#define __GEDIT_TAGLIST_PLUGIN_PANEL_H__ - -#include - -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_TAGLIST_PLUGIN_PANEL (gedit_taglist_plugin_panel_get_type()) -#define GEDIT_TAGLIST_PLUGIN_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, GeditTaglistPluginPanel)) -#define GEDIT_TAGLIST_PLUGIN_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, GeditTaglistPluginPanel const)) -#define GEDIT_TAGLIST_PLUGIN_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, GeditTaglistPluginPanelClass)) -#define GEDIT_IS_TAGLIST_PLUGIN_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL)) -#define GEDIT_IS_TAGLIST_PLUGIN_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL)) -#define GEDIT_TAGLIST_PLUGIN_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_TAGLIST_PLUGIN_PANEL, GeditTaglistPluginPanelClass)) - -/* Private structure type */ -typedef struct _GeditTaglistPluginPanelPrivate GeditTaglistPluginPanelPrivate; - -/* - * Main object structure - */ -typedef struct _GeditTaglistPluginPanel GeditTaglistPluginPanel; - -struct _GeditTaglistPluginPanel -{ - GtkVBox vbox; - - /*< private > */ - GeditTaglistPluginPanelPrivate *priv; -}; - -/* - * Class definition - */ -typedef struct _GeditTaglistPluginPanelClass GeditTaglistPluginPanelClass; - -struct _GeditTaglistPluginPanelClass -{ - GtkVBoxClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_taglist_plugin_panel_register_type (GTypeModule *module); - -GType gedit_taglist_plugin_panel_get_type (void) G_GNUC_CONST; - -GtkWidget *gedit_taglist_plugin_panel_new (GeditWindow *window, - const gchar *data_dir); - -G_END_DECLS - -#endif /* __GEDIT_TAGLIST_PLUGIN_PANEL_H__ */ diff --git a/plugins/taglist/gedit-taglist-plugin-parser.c b/plugins/taglist/gedit-taglist-plugin-parser.c deleted file mode 100755 index e09c0e25..00000000 --- a/plugins/taglist/gedit-taglist-plugin-parser.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * gedit-taglist-plugin-parser.c - * This file is part of gedit - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -/* FIXME: we should rewrite the parser to avoid using DOM */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "gedit-taglist-plugin-parser.h" - -/* we screwed up so we still look here for compatibility */ -#define USER_GEDIT_TAGLIST_PLUGIN_LOCATION_LEGACY ".gedit-2/plugins/taglist/" -#define USER_GEDIT_TAGLIST_PLUGIN_LOCATION "gedit/taglist/" - -TagList *taglist = NULL; -static gint taglist_ref_count = 0; - -static gboolean parse_tag (Tag *tag, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur); -static gboolean parse_tag_group (TagGroup *tg, const gchar *fn, - xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, - gboolean sort); -static TagGroup* get_tag_group (const gchar* filename, xmlDocPtr doc, - xmlNsPtr ns, xmlNodePtr cur); -static TagList* lookup_best_lang (TagList *taglist, const gchar *filename, - xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur); -static TagList *parse_taglist_file (const gchar* filename); -static TagList *parse_taglist_dir (const gchar *dir); - -static void free_tag (Tag *tag); -static void free_tag_group (TagGroup *tag_group); - -static gboolean -parse_tag (Tag *tag, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - /* - gedit_debug_message (DEBUG_PLUGINS, " Tag name: %s", tag->name); - */ - /* We don't care what the top level element name is */ - cur = cur->xmlChildrenNode; - - while (cur != NULL) - { - if ((!xmlStrcmp (cur->name, (const xmlChar *)"Begin")) && - (cur->ns == ns)) - { - tag->begin = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); - /* - gedit_debug_message (DEBUG_PLUGINS, " - Begin: %s", tag->begin); - */ - } - - if ((!xmlStrcmp (cur->name, (const xmlChar *)"End")) && - (cur->ns == ns)) - { - tag->end = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); - /* - gedit_debug_message (DEBUG_PLUGINS, " - End: %s", tag->end); - */ - } - - cur = cur->next; - } - - if ((tag->begin == NULL) && (tag->end == NULL)) - return FALSE; - - return TRUE; -} - -static gint -tags_cmp (gconstpointer a, gconstpointer b) -{ - gchar *tag_a = (gchar*)((Tag *)a)->name; - gchar *tag_b = (gchar*)((Tag *)b)->name; - - return g_utf8_collate (tag_a, tag_b); -} - -static gboolean -parse_tag_group (TagGroup *tg, const gchar* fn, xmlDocPtr doc, - xmlNsPtr ns, xmlNodePtr cur, gboolean sort) -{ - gedit_debug_message (DEBUG_PLUGINS, "Parse TagGroup: %s", tg->name); - - /* We don't care what the top level element name is */ - cur = cur->xmlChildrenNode; - - while (cur != NULL) - { - if ((xmlStrcmp (cur->name, (const xmlChar *) "Tag")) || (cur->ns != ns)) - { - g_warning ("The tag list file '%s' is of the wrong type, " - "was '%s', 'Tag' expected.", fn, cur->name); - - return FALSE; - } - else - { - Tag *tag; - - tag = g_new0 (Tag, 1); - - /* Get Tag name */ - tag->name = xmlGetProp (cur, (const xmlChar *) "name"); - - if (tag->name == NULL) - { - /* Error: No name */ - g_warning ("The tag list file '%s' is of the wrong type, " - "Tag without name.", fn); - - g_free (tag); - - return FALSE; - } - else - { - /* Parse Tag */ - if (parse_tag (tag, doc, ns, cur)) - { - /* Prepend Tag to TagGroup */ - tg->tags = g_list_prepend (tg->tags, tag); - } - else - { - /* Error parsing Tag */ - g_warning ("The tag list file '%s' is of the wrong type, " - "error parsing Tag '%s' in TagGroup '%s'.", - fn, tag->name, tg->name); - - free_tag (tag); - - return FALSE; - } - } - } - - cur = cur->next; - } - - if (sort) - tg->tags = g_list_sort (tg->tags, tags_cmp); - else - tg->tags = g_list_reverse (tg->tags); - - return TRUE; -} - -static TagGroup* -get_tag_group (const gchar* filename, xmlDocPtr doc, - xmlNsPtr ns, xmlNodePtr cur) -{ - TagGroup *tag_group; - xmlChar *sort_str; - gboolean sort = FALSE; - - tag_group = g_new0 (TagGroup, 1); - - /* Get TagGroup name */ - tag_group->name = xmlGetProp (cur, (const xmlChar *) "name"); - - sort_str = xmlGetProp (cur, (const xmlChar *) "sort"); - - if ((sort_str != NULL) && - ((xmlStrcasecmp (sort_str, (const xmlChar *) "yes") == 0) || - (xmlStrcasecmp (sort_str, (const xmlChar *) "true") == 0) || - (xmlStrcasecmp (sort_str, (const xmlChar *) "1") == 0))) - { - sort = TRUE; - } - - xmlFree(sort_str); - - if (tag_group->name == NULL) - { - /* Error: No name */ - g_warning ("The tag list file '%s' is of the wrong type, " - "TagGroup without name.", filename); - - g_free (tag_group); - } - else - { - /* Name found */ - gboolean exists = FALSE; - GList *t = taglist->tag_groups; - - /* Check if the tag group already exists */ - while (t && !exists) - { - gchar *tgn = (gchar*)((TagGroup*)(t->data))->name; - - if (strcmp (tgn, (gchar*)tag_group->name) == 0) - { - gedit_debug_message (DEBUG_PLUGINS, - "Tag group '%s' already exists.", tgn); - - exists = TRUE; - - free_tag_group (tag_group); - } - - t = g_list_next (t); - } - - if (!exists) - { - /* Parse tag group */ - if (parse_tag_group (tag_group, filename, doc, ns, cur, sort)) - { - return tag_group; - } - else - { - /* Error parsing TagGroup */ - g_warning ("The tag list file '%s' is of the wrong type, " - "error parsing TagGroup '%s'.", - filename, tag_group->name); - - free_tag_group (tag_group); - } - } - } - return NULL; -} - -static gint -groups_cmp (gconstpointer a, gconstpointer b) -{ - gchar *g_a = (gchar *)((TagGroup *)a)->name; - gchar *g_b = (gchar *)((TagGroup *)b)->name; - - return g_utf8_collate (g_a, g_b); -} - -/* - * tags file is localized by intltool-merge below. - * - * - * - * - * - * - * - * ..... - * - * - * ..... - * Therefore need to pick up the best lang on the current locale. - */ -static TagList* -lookup_best_lang (TagList *taglist, const gchar *filename, - xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) -{ - - TagGroup *best_tag_group = NULL; - TagGroup *tag_group; - gint best_lanking = -1; - - /* - * Walk the tree. - * - * First level we expect a list TagGroup - */ - cur = cur->xmlChildrenNode; - - while (cur != NULL) - { - if ((xmlStrcmp (cur->name, (const xmlChar *) "TagGroup")) || (cur->ns != ns)) - { - g_warning ("The tag list file '%s' is of the wrong type, " - "was '%s', 'TagGroup' expected.", filename, cur->name); - xmlFreeDoc (doc); - - return taglist; - } - else - { - const char * const *langs_pointer; - gchar *lang; - gint cur_lanking; - gint i; - - langs_pointer = g_get_language_names (); - - lang = (gchar*) xmlGetProp (cur, (const xmlChar*) "lang"); - cur_lanking = 1; - - /* - * When found a new TagGroup, prepend the best - * tag_group to taglist. In the current intltool-merge, - * the first section is the default lang NULL. - */ - if (lang == NULL) { - if (best_tag_group != NULL) { - taglist->tag_groups = - g_list_prepend (taglist->tag_groups, best_tag_group); - } - - best_tag_group = NULL; - best_lanking = -1; - } - - /* - * If already find the best TagGroup on the current - * locale, ignore the logic. - */ - if (best_lanking != -1 && best_lanking <= cur_lanking) { - cur = cur->next; - continue; - } - - /* try to find the best lang */ - for (i = 0; langs_pointer[i] != NULL; i++) - { - const gchar *best_lang = langs_pointer[i]; - - /* - * if launch on C, POSIX locale or does - * not find the best lang on the current locale, - * this is called. - * g_get_language_names returns lang - * lists with C locale. - */ - if (lang == NULL && - (!g_ascii_strcasecmp (best_lang, "C") || - !g_ascii_strcasecmp (best_lang, "POSIX"))) - { - tag_group = get_tag_group (filename, doc, ns, cur); - if (tag_group != NULL) - { - if (best_tag_group !=NULL) - free_tag_group (best_tag_group); - best_lanking = cur_lanking; - best_tag_group = tag_group; - } - } - - /* if it is possible the best lang is not C */ - else if (lang == NULL) - { - cur_lanking++; - continue; - } - - /* if the best lang is found */ - else if (!g_ascii_strcasecmp (best_lang, lang)) - { - tag_group = get_tag_group (filename, doc, ns, cur); - if (tag_group != NULL) - { - if (best_tag_group !=NULL) - free_tag_group (best_tag_group); - best_lanking = cur_lanking; - best_tag_group = tag_group; - } - } - - cur_lanking++; - } - - if (lang) g_free (lang); - } /* End of else */ - - cur = cur->next; - } /* End of while (cur != NULL) */ - - /* Prepend TagGroup to TagList */ - if (best_tag_group != NULL) { - taglist->tag_groups = - g_list_prepend (taglist->tag_groups, best_tag_group); - } - - taglist->tag_groups = g_list_sort (taglist->tag_groups, groups_cmp); - - return taglist; -} - -static TagList * -parse_taglist_file (const gchar* filename) -{ - xmlDocPtr doc; - - xmlNsPtr ns; - xmlNodePtr cur; - - gedit_debug_message (DEBUG_PLUGINS, "Parse file: %s", filename); - - xmlKeepBlanksDefault (0); - - /* - * build an XML tree from a the file; - */ - doc = xmlParseFile (filename); - if (doc == NULL) - { - g_warning ("The tag list file '%s' is empty.", filename); - - return taglist; - } - - /* - * Check the document is of the right kind - */ - - cur = xmlDocGetRootElement (doc); - - if (cur == NULL) - { - g_warning ("The tag list file '%s' is empty.", filename); - xmlFreeDoc(doc); - return taglist; - } - - ns = xmlSearchNsByHref (doc, cur, - (const xmlChar *) "http://gedit.sourceforge.net/some-location"); - - if (ns == NULL) - { - g_warning ("The tag list file '%s' is of the wrong type, " - "gedit namespace not found.", filename); - xmlFreeDoc (doc); - - return taglist; - } - - if (xmlStrcmp(cur->name, (const xmlChar *) "TagList")) - { - g_warning ("The tag list file '%s' is of the wrong type, " - "root node != TagList.", filename); - xmlFreeDoc (doc); - - return taglist; - } - - /* - * If needed, allocate taglist - */ - - if (taglist == NULL) - taglist = g_new0 (TagList, 1); - - taglist = lookup_best_lang (taglist, filename, doc, ns, cur); - - xmlFreeDoc (doc); - - gedit_debug_message (DEBUG_PLUGINS, "END"); - - return taglist; -} - -static void -free_tag (Tag *tag) -{ - /* - gedit_debug_message (DEBUG_PLUGINS, "Tag: %s", tag->name); - */ - g_return_if_fail (tag != NULL); - - free (tag->name); - - if (tag->begin != NULL) - free (tag->begin); - - if (tag->end != NULL) - free (tag->end); - - g_free (tag); -} - -static void -free_tag_group (TagGroup *tag_group) -{ - GList *l; - - gedit_debug_message (DEBUG_PLUGINS, "Tag group: %s", tag_group->name); - - g_return_if_fail (tag_group != NULL); - - free (tag_group->name); - - for (l = tag_group->tags; l != NULL; l = g_list_next (l)) - { - free_tag ((Tag *) l->data); - } - - g_list_free (tag_group->tags); - g_free (tag_group); - - gedit_debug_message (DEBUG_PLUGINS, "END"); -} - -void -free_taglist (void) -{ - GList *l; - - gedit_debug_message (DEBUG_PLUGINS, "ref_count: %d", taglist_ref_count); - - if (taglist == NULL) - return; - - g_return_if_fail (taglist_ref_count > 0); - - --taglist_ref_count; - if (taglist_ref_count > 0) - return; - - for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) - { - free_tag_group ((TagGroup *) l->data); - } - - g_list_free (taglist->tag_groups); - g_free (taglist); - taglist = NULL; - - gedit_debug_message (DEBUG_PLUGINS, "Really freed"); -} - -static TagList * -parse_taglist_dir (const gchar *dir) -{ - GError *error = NULL; - GDir *d; - const gchar *dirent; - - gedit_debug_message (DEBUG_PLUGINS, "DIR: %s", dir); - - d = g_dir_open (dir, 0, &error); - if (!d) - { - gedit_debug_message (DEBUG_PLUGINS, "%s", error->message); - g_error_free (error); - return taglist; - } - - while ((dirent = g_dir_read_name (d))) - { - if (g_str_has_suffix (dirent, ".tags") || - g_str_has_suffix (dirent, ".tags.gz")) - { - gchar *tags_file = g_build_filename (dir, dirent, NULL); - parse_taglist_file (tags_file); - g_free (tags_file); - } - } - - g_dir_close (d); - - return taglist; -} - -TagList* create_taglist (const gchar *data_dir) -{ - gchar *pdir; - - gedit_debug_message (DEBUG_PLUGINS, "ref_count: %d", taglist_ref_count); - - if (taglist_ref_count > 0) - { - ++taglist_ref_count; - - return taglist; - } - -#ifndef G_OS_WIN32 - const gchar *home; - const gchar *envvar; - - /* load user's taglists */ - - /* legacy dir */ - home = g_get_home_dir (); - if (home != NULL) - { - pdir = g_build_filename (home, - USER_GEDIT_TAGLIST_PLUGIN_LOCATION_LEGACY, - NULL); - parse_taglist_dir (pdir); - g_free (pdir); - } - - /* Support old libmate env var */ - envvar = g_getenv ("MATE22_USER_DIR"); - if (envvar != NULL) - { - pdir = g_build_filename (envvar, - USER_GEDIT_TAGLIST_PLUGIN_LOCATION, - NULL); - parse_taglist_dir (pdir); - g_free (pdir); - } - else if (home != NULL) - { - pdir = g_build_filename (home, - ".mate2", - USER_GEDIT_TAGLIST_PLUGIN_LOCATION, - NULL); - parse_taglist_dir (pdir); - g_free (pdir); - } - -#else - pdir = g_build_filename (g_get_user_config_dir (), - "gedit", - "taglist", - NULL); - parse_taglist_dir (pdir); - g_free (pdir); -#endif - - /* load system's taglists */ - parse_taglist_dir (data_dir); - - ++taglist_ref_count; - g_return_val_if_fail (taglist_ref_count == 1, taglist); - - return taglist; -} diff --git a/plugins/taglist/gedit-taglist-plugin-parser.h b/plugins/taglist/gedit-taglist-plugin-parser.h deleted file mode 100755 index d008836e..00000000 --- a/plugins/taglist/gedit-taglist-plugin-parser.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * gedit-taglist-plugin-parser.h - * This file is part of gedit - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifndef __GEDIT_TAGLIST_PLUGIN_PARSER_H__ -#define __GEDIT_TAGLIST_PLUGIN_PARSER_H__ - -#include -#include - -typedef struct _TagList TagList; -typedef struct _TagGroup TagGroup; -typedef struct _Tag Tag; - -struct _TagList -{ - GList *tag_groups; -}; - -struct _TagGroup -{ - xmlChar *name; - - GList *tags; -}; - -struct _Tag -{ - xmlChar *name; - xmlChar *begin; - xmlChar *end; -}; - -/* Note that the taglist is ref counted */ -extern TagList *taglist; - -TagList* create_taglist (const gchar *data_dir); - -void free_taglist (void); - -#endif /* __GEDIT_TAGLIST_PLUGIN_PARSER_H__ */ - diff --git a/plugins/taglist/gedit-taglist-plugin.c b/plugins/taglist/gedit-taglist-plugin.c deleted file mode 100755 index 081fefcb..00000000 --- a/plugins/taglist/gedit-taglist-plugin.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * gedit-taglist-plugin.h - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "gedit-taglist-plugin.h" -#include "gedit-taglist-plugin-panel.h" -#include "gedit-taglist-plugin-parser.h" - -#include -#include - -#include -#include - -#define WINDOW_DATA_KEY "GeditTaglistPluginWindowData" - -#define GEDIT_TAGLIST_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_TAGLIST_PLUGIN, GeditTaglistPluginPrivate)) - -struct _GeditTaglistPluginPrivate -{ - gpointer dummy; -}; - -GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE (GeditTaglistPlugin, gedit_taglist_plugin, - gedit_taglist_plugin_panel_register_type (module); -) - -static void -gedit_taglist_plugin_init (GeditTaglistPlugin *plugin) -{ - plugin->priv = GEDIT_TAGLIST_PLUGIN_GET_PRIVATE (plugin); - - gedit_debug_message (DEBUG_PLUGINS, "GeditTaglistPlugin initializing"); -} - -static void -gedit_taglist_plugin_finalize (GObject *object) -{ -/* - GeditTaglistPlugin *plugin = GEDIT_TAGLIST_PLUGIN (object); -*/ - gedit_debug_message (DEBUG_PLUGINS, "GeditTaglistPlugin finalizing"); - - free_taglist (); - - G_OBJECT_CLASS (gedit_taglist_plugin_parent_class)->finalize (object); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GeditPanel *side_panel; - GtkWidget *taglist_panel; - gchar *data_dir; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY) == NULL); - - side_panel = gedit_window_get_side_panel (window); - - data_dir = gedit_plugin_get_data_dir (plugin); - taglist_panel = gedit_taglist_plugin_panel_new (window, data_dir); - g_free (data_dir); - - gedit_panel_add_item_with_stock_icon (side_panel, - taglist_panel, - _("Tags"), - GTK_STOCK_ADD); - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - taglist_panel); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GeditPanel *side_panel; - gpointer data; - - gedit_debug (DEBUG_PLUGINS); - - data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - side_panel = gedit_window_get_side_panel (window); - - gedit_panel_remove_item (side_panel, - GTK_WIDGET (data)); - - g_object_set_data (G_OBJECT (window), - WINDOW_DATA_KEY, - NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - gpointer data; - GeditView *view; - - gedit_debug (DEBUG_PLUGINS); - - data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - view = gedit_window_get_active_view (window); - - gtk_widget_set_sensitive (GTK_WIDGET (data), - (view != NULL) && - gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); -} - -static void -gedit_taglist_plugin_class_init (GeditTaglistPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_taglist_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; - - g_type_class_add_private (object_class, sizeof (GeditTaglistPluginPrivate)); -} diff --git a/plugins/taglist/gedit-taglist-plugin.h b/plugins/taglist/gedit-taglist-plugin.h deleted file mode 100755 index d0444e76..00000000 --- a/plugins/taglist/gedit-taglist-plugin.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * gedit-taglist-plugin.h - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifndef __GEDIT_TAGLIST_PLUGIN_H__ -#define __GEDIT_TAGLIST_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_TAGLIST_PLUGIN (gedit_taglist_plugin_get_type ()) -#define GEDIT_TAGLIST_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_TAGLIST_PLUGIN, GeditTaglistPlugin)) -#define GEDIT_TAGLIST_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_TAGLIST_PLUGIN, GeditTaglistPluginClass)) -#define GEDIT_IS_TAGLIST_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_TAGLIST_PLUGIN)) -#define GEDIT_IS_TAGLIST_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_TAGLIST_PLUGIN)) -#define GEDIT_TAGLIST_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_TAGLIST_PLUGIN, GeditTaglistPluginClass)) - -/* Private structure type */ -typedef struct _GeditTaglistPluginPrivate GeditTaglistPluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditTaglistPlugin GeditTaglistPlugin; - -struct _GeditTaglistPlugin -{ - GeditPlugin parent_instance; - - /*< private >*/ - GeditTaglistPluginPrivate *priv; -}; - -/* - * Class definition - */ -typedef struct _GeditTaglistPluginClass GeditTaglistPluginClass; - -struct _GeditTaglistPluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_taglist_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_TAGLIST_PLUGIN_H__ */ diff --git a/plugins/taglist/pluma-taglist-plugin-panel.c b/plugins/taglist/pluma-taglist-plugin-panel.c new file mode 100755 index 00000000..513bf070 --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin-panel.c @@ -0,0 +1,776 @@ +/* + * pluma-taglist-plugin-panel.c + * This file is part of pluma + * + * Copyright (C) 2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "pluma-taglist-plugin-panel.h" +#include "pluma-taglist-plugin-parser.h" + +#include +#include +#include + +#include +#include + +#define PLUMA_TAGLIST_PLUGIN_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, \ + PlumaTaglistPluginPanelPrivate)) + +enum +{ + COLUMN_TAG_NAME, + COLUMN_TAG_INDEX_IN_GROUP, + NUM_COLUMNS +}; + +struct _PlumaTaglistPluginPanelPrivate +{ + PlumaWindow *window; + + GtkWidget *tag_groups_combo; + GtkWidget *tags_list; + GtkWidget *preview; + + TagGroup *selected_tag_group; + + gchar *data_dir; +}; + +PLUMA_PLUGIN_DEFINE_TYPE (PlumaTaglistPluginPanel, pluma_taglist_plugin_panel, GTK_TYPE_VBOX) + +enum +{ + PROP_0, + PROP_WINDOW, +}; + +static void +set_window (PlumaTaglistPluginPanel *panel, + PlumaWindow *window) +{ + g_return_if_fail (panel->priv->window == NULL); + g_return_if_fail (PLUMA_IS_WINDOW (window)); + + panel->priv->window = window; + + /* TODO */ +} + +static void +pluma_taglist_plugin_panel_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PlumaTaglistPluginPanel *panel = PLUMA_TAGLIST_PLUGIN_PANEL (object); + + switch (prop_id) + { + case PROP_WINDOW: + set_window (panel, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_taglist_plugin_panel_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PlumaTaglistPluginPanel *panel = PLUMA_TAGLIST_PLUGIN_PANEL (object); + + switch (prop_id) + { + case PROP_WINDOW: + g_value_set_object (value, + PLUMA_TAGLIST_PLUGIN_PANEL_GET_PRIVATE (panel)->window); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pluma_taglist_plugin_panel_finalize (GObject *object) +{ + PlumaTaglistPluginPanel *panel = PLUMA_TAGLIST_PLUGIN_PANEL (object); + + g_free (panel->priv->data_dir); + + G_OBJECT_CLASS (pluma_taglist_plugin_panel_parent_class)->finalize (object); +} + +static void +pluma_taglist_plugin_panel_class_init (PlumaTaglistPluginPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = pluma_taglist_plugin_panel_finalize; + object_class->get_property = pluma_taglist_plugin_panel_get_property; + object_class->set_property = pluma_taglist_plugin_panel_set_property; + + g_object_class_install_property (object_class, + PROP_WINDOW, + g_param_spec_object ("window", + "Window", + "The PlumaWindow this PlumaTaglistPluginPanel is associated with", + PLUMA_TYPE_WINDOW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (object_class, sizeof(PlumaTaglistPluginPanelPrivate)); +} + +static void +insert_tag (PlumaTaglistPluginPanel *panel, + Tag *tag, + gboolean grab_focus) +{ + PlumaView *view; + GtkTextBuffer *buffer; + GtkTextIter start, end; + GtkTextIter cursor; + gboolean sel = FALSE; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (panel->priv->window); + g_return_if_fail (view != NULL); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + gtk_text_buffer_begin_user_action (buffer); + + /* always insert the begin tag at the beginning of the selection + * and the end tag at the end, if there is no selection they will + * be automatically inserted at the cursor position. + */ + + if (tag->begin != NULL) + { + sel = gtk_text_buffer_get_selection_bounds (buffer, + &start, + &end); + + gtk_text_buffer_insert (buffer, + &start, + (gchar *)tag->begin, + -1); + + /* get iterators again since they have been invalidated and move + * the cursor after the selection */ + gtk_text_buffer_get_selection_bounds (buffer, + &start, + &cursor); + } + + if (tag->end != NULL) + { + sel = gtk_text_buffer_get_selection_bounds (buffer, + &start, + &end); + + gtk_text_buffer_insert (buffer, + &end, + (gchar *)tag->end, + -1); + + /* if there is no selection and we have a paired tag, move the + * cursor between the pair, otherwise move it at the end */ + if (!sel) + { + gint offset; + + offset = gtk_text_iter_get_offset (&end) - + g_utf8_strlen ((gchar *)tag->end, -1); + + gtk_text_buffer_get_iter_at_offset (buffer, + &end, + offset); + } + + cursor = end; + } + + gtk_text_buffer_place_cursor (buffer, &cursor); + + gtk_text_buffer_end_user_action (buffer); + + if (grab_focus) + gtk_widget_grab_focus (GTK_WIDGET (view)); +} + +static void +tag_list_row_activated_cb (GtkTreeView *tag_list, + GtkTreePath *path, + GtkTreeViewColumn *column, + PlumaTaglistPluginPanel *panel) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gint index; + + pluma_debug (DEBUG_PLUGINS); + + model = gtk_tree_view_get_model (tag_list); + + gtk_tree_model_get_iter (model, &iter, path); + g_return_if_fail (&iter != NULL); + + gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); + + pluma_debug_message (DEBUG_PLUGINS, "Index: %d", index); + + insert_tag (panel, + (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index), + TRUE); +} + +static gboolean +tag_list_key_press_event_cb (GtkTreeView *tag_list, + GdkEventKey *event, + PlumaTaglistPluginPanel *panel) +{ + gboolean grab_focus; + + grab_focus = (event->state & GDK_CONTROL_MASK) != 0; + + if (event->keyval == GDK_Return) + { + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gint index; + + pluma_debug_message (DEBUG_PLUGINS, "RETURN Pressed"); + + model = gtk_tree_view_get_model (tag_list); + + selection = gtk_tree_view_get_selection (tag_list); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); + + pluma_debug_message (DEBUG_PLUGINS, "Index: %d", index); + + insert_tag (panel, + (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index), + grab_focus); + } + + return TRUE; + } + + return FALSE; +} + +static GtkTreeModel* +create_model (PlumaTaglistPluginPanel *panel) +{ + gint i = 0; + GtkListStore *store; + GtkTreeIter iter; + GList *list; + + pluma_debug (DEBUG_PLUGINS); + + /* create list store */ + store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT); + + /* add data to the list store */ + list = panel->priv->selected_tag_group->tags; + + while (list != NULL) + { + const gchar* tag_name; + + tag_name = (gchar *)((Tag*)list->data)->name; + + pluma_debug_message (DEBUG_PLUGINS, "%d : %s", i, tag_name); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_TAG_NAME, tag_name, + COLUMN_TAG_INDEX_IN_GROUP, i, + -1); + ++i; + + list = g_list_next (list); + } + + pluma_debug_message (DEBUG_PLUGINS, "Rows: %d ", + gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL)); + + return GTK_TREE_MODEL (store); +} + +static void +populate_tags_list (PlumaTaglistPluginPanel *panel) +{ + GtkTreeModel* model; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (taglist != NULL); + + model = create_model (panel); + gtk_tree_view_set_model (GTK_TREE_VIEW (panel->priv->tags_list), + model); + g_object_unref (model); +} + +static TagGroup * +find_tag_group (const gchar *name) +{ + GList *l; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (taglist != NULL, NULL); + + for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) + { + if (strcmp (name, (gchar *)((TagGroup*)l->data)->name) == 0) + return (TagGroup*)l->data; + } + + return NULL; +} + +static void +populate_tag_groups_combo (PlumaTaglistPluginPanel *panel) +{ + GList *l; + GtkComboBox *combo; + + pluma_debug (DEBUG_PLUGINS); + + combo = GTK_COMBO_BOX (panel->priv->tag_groups_combo); + + if (taglist == NULL) + return; + + for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) + { + gtk_combo_box_append_text (combo, + (gchar *)((TagGroup*)l->data)->name); + } + + gtk_combo_box_set_active (combo, 0); + + return; +} + +static void +selected_group_changed (GtkComboBox *combo, + PlumaTaglistPluginPanel *panel) +{ + gchar* group_name; + + pluma_debug (DEBUG_PLUGINS); + + group_name = gtk_combo_box_get_active_text (combo); + + if ((group_name == NULL) || (strlen (group_name) <= 0)) + { + g_free (group_name); + return; + } + + if ((panel->priv->selected_tag_group == NULL) || + (strcmp (group_name, (gchar *)panel->priv->selected_tag_group->name) != 0)) + { + panel->priv->selected_tag_group = find_tag_group (group_name); + g_return_if_fail (panel->priv->selected_tag_group != NULL); + + pluma_debug_message (DEBUG_PLUGINS, + "New selected group: %s", + panel->priv->selected_tag_group->name); + + populate_tags_list (panel); + } + + /* Clean up preview */ + gtk_label_set_text (GTK_LABEL (panel->priv->preview), + ""); + + g_free (group_name); +} + +static gchar * +create_preview_string (Tag *tag) +{ + GString *str; + + str = g_string_new (""); + + if (tag->begin != NULL) + { + gchar *markup; + + markup = g_markup_escape_text ((gchar *)tag->begin, -1); + g_string_append (str, markup); + g_free (markup); + } + + if (tag->end != NULL) + { + gchar *markup; + + markup = g_markup_escape_text ((gchar *)tag->end, -1); + g_string_append (str, markup); + g_free (markup); + } + + g_string_append (str, ""); + + return g_string_free (str, FALSE); +} + +static void +update_preview (PlumaTaglistPluginPanel *panel, + Tag *tag) +{ + gchar *str; + + str = create_preview_string (tag); + + gtk_label_set_markup (GTK_LABEL (panel->priv->preview), + str); + + g_free (str); +} + +static void +tag_list_cursor_changed_cb (GtkTreeView *tag_list, + gpointer data) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + gint index; + + PlumaTaglistPluginPanel *panel = (PlumaTaglistPluginPanel *)data; + + model = gtk_tree_view_get_model (tag_list); + + selection = gtk_tree_view_get_selection (tag_list); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + gtk_tree_model_get (model, &iter, COLUMN_TAG_INDEX_IN_GROUP, &index, -1); + + pluma_debug_message (DEBUG_PLUGINS, "Index: %d", index); + + update_preview (panel, + (Tag*)g_list_nth_data (panel->priv->selected_tag_group->tags, index)); + } +} + +static gboolean +tags_list_query_tooltip_cb (GtkWidget *widget, + gint x, + gint y, + gboolean keyboard_tip, + GtkTooltip *tooltip, + PlumaTaglistPluginPanel *panel) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *path = NULL; + gint index; + Tag *tag; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + + if (keyboard_tip) + { + gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), + &path, + NULL); + + if (path == NULL) + { + return FALSE; + } + } + else + { + gint bin_x, bin_y; + + gtk_tree_view_convert_widget_to_bin_window_coords (GTK_TREE_VIEW (widget), + x, y, + &bin_x, &bin_y); + + if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), + bin_x, bin_y, + &path, + NULL, NULL, NULL)) + { + return FALSE; + } + } + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + COLUMN_TAG_INDEX_IN_GROUP, &index, + -1); + + tag = g_list_nth_data (panel->priv->selected_tag_group->tags, index); + if (tag != NULL) + { + gchar *tip; + + tip = create_preview_string (tag); + gtk_tooltip_set_markup (tooltip, tip); + g_free (tip); + gtk_tree_path_free (path); + + return TRUE; + } + + gtk_tree_path_free (path); + + return FALSE; +} + +static gboolean +expose_event_cb (GtkWidget *panel, + GdkEventExpose *event, + gpointer user_data) +{ + PlumaTaglistPluginPanel *ppanel = PLUMA_TAGLIST_PLUGIN_PANEL (panel); + + pluma_debug (DEBUG_PLUGINS); + + /* If needed load taglists from files at the first expose */ + if (taglist == NULL) + create_taglist (ppanel->priv->data_dir); + + /* And populate combo box */ + populate_tag_groups_combo (PLUMA_TAGLIST_PLUGIN_PANEL (panel)); + + /* We need to manage only the first expose event -> disconnect */ + g_signal_handlers_disconnect_by_func (panel, expose_event_cb, NULL); + + return FALSE; +} + +static void +set_combo_tooltip (GtkWidget *widget, + gpointer data) +{ + if (GTK_IS_BUTTON (widget)) + { + gtk_widget_set_tooltip_text (widget, + _("Select the group of tags you want to use")); + } +} + +static void +realize_tag_groups_combo (GtkWidget *combo, + gpointer data) +{ + gtk_container_forall (GTK_CONTAINER (combo), + set_combo_tooltip, + NULL); +} + +static void +add_preview_widget (PlumaTaglistPluginPanel *panel) +{ + GtkWidget *expander; + GtkWidget *frame; + + expander = gtk_expander_new_with_mnemonic (_("_Preview")); + + panel->priv->preview = gtk_label_new (NULL); + gtk_widget_set_size_request (panel->priv->preview, -1, 80); + + gtk_label_set_line_wrap (GTK_LABEL (panel->priv->preview), TRUE); + gtk_label_set_use_markup (GTK_LABEL (panel->priv->preview), TRUE); + gtk_misc_set_alignment (GTK_MISC (panel->priv->preview), 0, 0); + gtk_misc_set_padding (GTK_MISC (panel->priv->preview), 6, 6); + gtk_label_set_selectable (GTK_LABEL (panel->priv->preview), TRUE); + gtk_label_set_selectable (GTK_LABEL (panel->priv->preview), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (panel->priv->preview), + PANGO_ELLIPSIZE_END); + + frame = gtk_frame_new (0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + + gtk_container_add (GTK_CONTAINER (frame), + panel->priv->preview); + + gtk_container_add (GTK_CONTAINER (expander), + frame); + + gtk_box_pack_start (GTK_BOX (panel), expander, FALSE, FALSE, 0); + + gtk_widget_show_all (expander); +} + +static void +pluma_taglist_plugin_panel_init (PlumaTaglistPluginPanel *panel) +{ + GtkWidget *sw; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GList *focus_chain = NULL; + + pluma_debug (DEBUG_PLUGINS); + + panel->priv = PLUMA_TAGLIST_PLUGIN_PANEL_GET_PRIVATE (panel); + panel->priv->data_dir = NULL; + + /* Build the window content */ + panel->priv->tag_groups_combo = gtk_combo_box_new_text (); + gtk_box_pack_start (GTK_BOX (panel), + panel->priv->tag_groups_combo, + FALSE, + TRUE, + 0); + + g_signal_connect (panel->priv->tag_groups_combo, + "realize", + G_CALLBACK (realize_tag_groups_combo), + panel); + + sw = gtk_scrolled_window_new (NULL, NULL); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0); + + /* Create tree view */ + panel->priv->tags_list = gtk_tree_view_new (); + + pluma_utils_set_atk_name_description (panel->priv->tag_groups_combo, + _("Available Tag Lists"), + NULL); + pluma_utils_set_atk_name_description (panel->priv->tags_list, + _("Tags"), + NULL); + pluma_utils_set_atk_relation (panel->priv->tag_groups_combo, + panel->priv->tags_list, + ATK_RELATION_CONTROLLER_FOR); + pluma_utils_set_atk_relation (panel->priv->tags_list, + panel->priv->tag_groups_combo, + ATK_RELATION_CONTROLLED_BY); + + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (panel->priv->tags_list), FALSE); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (panel->priv->tags_list), FALSE); + + g_object_set (panel->priv->tags_list, "has-tooltip", TRUE, NULL); + + /* Add the tags column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Tags"), + cell, + "text", + COLUMN_TAG_NAME, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (panel->priv->tags_list), + column); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (panel->priv->tags_list), + COLUMN_TAG_NAME); + + gtk_container_add (GTK_CONTAINER (sw), panel->priv->tags_list); + + focus_chain = g_list_prepend (focus_chain, panel->priv->tags_list); + focus_chain = g_list_prepend (focus_chain, panel->priv->tag_groups_combo); + + gtk_container_set_focus_chain (GTK_CONTAINER (panel), + focus_chain); + g_list_free (focus_chain); + + add_preview_widget (panel); + + gtk_widget_show_all (GTK_WIDGET (sw)); + gtk_widget_show (GTK_WIDGET (panel->priv->tag_groups_combo)); + + g_signal_connect_after (panel->priv->tags_list, + "row_activated", + G_CALLBACK (tag_list_row_activated_cb), + panel); + g_signal_connect (panel->priv->tags_list, + "key_press_event", + G_CALLBACK (tag_list_key_press_event_cb), + panel); + g_signal_connect (panel->priv->tags_list, + "query-tooltip", + G_CALLBACK (tags_list_query_tooltip_cb), + panel); + g_signal_connect (panel->priv->tags_list, + "cursor_changed", + G_CALLBACK (tag_list_cursor_changed_cb), + panel); + g_signal_connect (panel->priv->tag_groups_combo, + "changed", + G_CALLBACK (selected_group_changed), + panel); + g_signal_connect (panel, + "expose-event", + G_CALLBACK (expose_event_cb), + NULL); +} + +GtkWidget * +pluma_taglist_plugin_panel_new (PlumaWindow *window, + const gchar *data_dir) +{ + PlumaTaglistPluginPanel *panel; + + g_return_val_if_fail (PLUMA_IS_WINDOW (window), NULL); + + panel = g_object_new (PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, + "window", window, + NULL); + + panel->priv->data_dir = g_strdup (data_dir); + + return GTK_WIDGET (panel); +} diff --git a/plugins/taglist/pluma-taglist-plugin-panel.h b/plugins/taglist/pluma-taglist-plugin-panel.h new file mode 100755 index 00000000..cfeddfdd --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin-panel.h @@ -0,0 +1,89 @@ +/* + * pluma-taglist-plugin-panel.h + * This file is part of pluma + * + * Copyright (C) 2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +#ifndef __PLUMA_TAGLIST_PLUGIN_PANEL_H__ +#define __PLUMA_TAGLIST_PLUGIN_PANEL_H__ + +#include + +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_TAGLIST_PLUGIN_PANEL (pluma_taglist_plugin_panel_get_type()) +#define PLUMA_TAGLIST_PLUGIN_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, PlumaTaglistPluginPanel)) +#define PLUMA_TAGLIST_PLUGIN_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, PlumaTaglistPluginPanel const)) +#define PLUMA_TAGLIST_PLUGIN_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, PlumaTaglistPluginPanelClass)) +#define PLUMA_IS_TAGLIST_PLUGIN_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL)) +#define PLUMA_IS_TAGLIST_PLUGIN_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL)) +#define PLUMA_TAGLIST_PLUGIN_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PLUMA_TYPE_TAGLIST_PLUGIN_PANEL, PlumaTaglistPluginPanelClass)) + +/* Private structure type */ +typedef struct _PlumaTaglistPluginPanelPrivate PlumaTaglistPluginPanelPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaTaglistPluginPanel PlumaTaglistPluginPanel; + +struct _PlumaTaglistPluginPanel +{ + GtkVBox vbox; + + /*< private > */ + PlumaTaglistPluginPanelPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _PlumaTaglistPluginPanelClass PlumaTaglistPluginPanelClass; + +struct _PlumaTaglistPluginPanelClass +{ + GtkVBoxClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_taglist_plugin_panel_register_type (GTypeModule *module); + +GType pluma_taglist_plugin_panel_get_type (void) G_GNUC_CONST; + +GtkWidget *pluma_taglist_plugin_panel_new (PlumaWindow *window, + const gchar *data_dir); + +G_END_DECLS + +#endif /* __PLUMA_TAGLIST_PLUGIN_PANEL_H__ */ diff --git a/plugins/taglist/pluma-taglist-plugin-parser.c b/plugins/taglist/pluma-taglist-plugin-parser.c new file mode 100755 index 00000000..bc7767d0 --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin-parser.c @@ -0,0 +1,655 @@ +/* + * pluma-taglist-plugin-parser.c + * This file is part of pluma + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002-2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +/* FIXME: we should rewrite the parser to avoid using DOM */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "pluma-taglist-plugin-parser.h" + +/* we screwed up so we still look here for compatibility */ +#define USER_PLUMA_TAGLIST_PLUGIN_LOCATION_LEGACY ".pluma-2/plugins/taglist/" +#define USER_PLUMA_TAGLIST_PLUGIN_LOCATION "pluma/taglist/" + +TagList *taglist = NULL; +static gint taglist_ref_count = 0; + +static gboolean parse_tag (Tag *tag, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur); +static gboolean parse_tag_group (TagGroup *tg, const gchar *fn, + xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, + gboolean sort); +static TagGroup* get_tag_group (const gchar* filename, xmlDocPtr doc, + xmlNsPtr ns, xmlNodePtr cur); +static TagList* lookup_best_lang (TagList *taglist, const gchar *filename, + xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur); +static TagList *parse_taglist_file (const gchar* filename); +static TagList *parse_taglist_dir (const gchar *dir); + +static void free_tag (Tag *tag); +static void free_tag_group (TagGroup *tag_group); + +static gboolean +parse_tag (Tag *tag, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) +{ + /* + pluma_debug_message (DEBUG_PLUGINS, " Tag name: %s", tag->name); + */ + /* We don't care what the top level element name is */ + cur = cur->xmlChildrenNode; + + while (cur != NULL) + { + if ((!xmlStrcmp (cur->name, (const xmlChar *)"Begin")) && + (cur->ns == ns)) + { + tag->begin = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); + /* + pluma_debug_message (DEBUG_PLUGINS, " - Begin: %s", tag->begin); + */ + } + + if ((!xmlStrcmp (cur->name, (const xmlChar *)"End")) && + (cur->ns == ns)) + { + tag->end = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); + /* + pluma_debug_message (DEBUG_PLUGINS, " - End: %s", tag->end); + */ + } + + cur = cur->next; + } + + if ((tag->begin == NULL) && (tag->end == NULL)) + return FALSE; + + return TRUE; +} + +static gint +tags_cmp (gconstpointer a, gconstpointer b) +{ + gchar *tag_a = (gchar*)((Tag *)a)->name; + gchar *tag_b = (gchar*)((Tag *)b)->name; + + return g_utf8_collate (tag_a, tag_b); +} + +static gboolean +parse_tag_group (TagGroup *tg, const gchar* fn, xmlDocPtr doc, + xmlNsPtr ns, xmlNodePtr cur, gboolean sort) +{ + pluma_debug_message (DEBUG_PLUGINS, "Parse TagGroup: %s", tg->name); + + /* We don't care what the top level element name is */ + cur = cur->xmlChildrenNode; + + while (cur != NULL) + { + if ((xmlStrcmp (cur->name, (const xmlChar *) "Tag")) || (cur->ns != ns)) + { + g_warning ("The tag list file '%s' is of the wrong type, " + "was '%s', 'Tag' expected.", fn, cur->name); + + return FALSE; + } + else + { + Tag *tag; + + tag = g_new0 (Tag, 1); + + /* Get Tag name */ + tag->name = xmlGetProp (cur, (const xmlChar *) "name"); + + if (tag->name == NULL) + { + /* Error: No name */ + g_warning ("The tag list file '%s' is of the wrong type, " + "Tag without name.", fn); + + g_free (tag); + + return FALSE; + } + else + { + /* Parse Tag */ + if (parse_tag (tag, doc, ns, cur)) + { + /* Prepend Tag to TagGroup */ + tg->tags = g_list_prepend (tg->tags, tag); + } + else + { + /* Error parsing Tag */ + g_warning ("The tag list file '%s' is of the wrong type, " + "error parsing Tag '%s' in TagGroup '%s'.", + fn, tag->name, tg->name); + + free_tag (tag); + + return FALSE; + } + } + } + + cur = cur->next; + } + + if (sort) + tg->tags = g_list_sort (tg->tags, tags_cmp); + else + tg->tags = g_list_reverse (tg->tags); + + return TRUE; +} + +static TagGroup* +get_tag_group (const gchar* filename, xmlDocPtr doc, + xmlNsPtr ns, xmlNodePtr cur) +{ + TagGroup *tag_group; + xmlChar *sort_str; + gboolean sort = FALSE; + + tag_group = g_new0 (TagGroup, 1); + + /* Get TagGroup name */ + tag_group->name = xmlGetProp (cur, (const xmlChar *) "name"); + + sort_str = xmlGetProp (cur, (const xmlChar *) "sort"); + + if ((sort_str != NULL) && + ((xmlStrcasecmp (sort_str, (const xmlChar *) "yes") == 0) || + (xmlStrcasecmp (sort_str, (const xmlChar *) "true") == 0) || + (xmlStrcasecmp (sort_str, (const xmlChar *) "1") == 0))) + { + sort = TRUE; + } + + xmlFree(sort_str); + + if (tag_group->name == NULL) + { + /* Error: No name */ + g_warning ("The tag list file '%s' is of the wrong type, " + "TagGroup without name.", filename); + + g_free (tag_group); + } + else + { + /* Name found */ + gboolean exists = FALSE; + GList *t = taglist->tag_groups; + + /* Check if the tag group already exists */ + while (t && !exists) + { + gchar *tgn = (gchar*)((TagGroup*)(t->data))->name; + + if (strcmp (tgn, (gchar*)tag_group->name) == 0) + { + pluma_debug_message (DEBUG_PLUGINS, + "Tag group '%s' already exists.", tgn); + + exists = TRUE; + + free_tag_group (tag_group); + } + + t = g_list_next (t); + } + + if (!exists) + { + /* Parse tag group */ + if (parse_tag_group (tag_group, filename, doc, ns, cur, sort)) + { + return tag_group; + } + else + { + /* Error parsing TagGroup */ + g_warning ("The tag list file '%s' is of the wrong type, " + "error parsing TagGroup '%s'.", + filename, tag_group->name); + + free_tag_group (tag_group); + } + } + } + return NULL; +} + +static gint +groups_cmp (gconstpointer a, gconstpointer b) +{ + gchar *g_a = (gchar *)((TagGroup *)a)->name; + gchar *g_b = (gchar *)((TagGroup *)b)->name; + + return g_utf8_collate (g_a, g_b); +} + +/* + * tags file is localized by intltool-merge below. + * + * + * + * + * + * + * + * ..... + * + * + * ..... + * Therefore need to pick up the best lang on the current locale. + */ +static TagList* +lookup_best_lang (TagList *taglist, const gchar *filename, + xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) +{ + + TagGroup *best_tag_group = NULL; + TagGroup *tag_group; + gint best_lanking = -1; + + /* + * Walk the tree. + * + * First level we expect a list TagGroup + */ + cur = cur->xmlChildrenNode; + + while (cur != NULL) + { + if ((xmlStrcmp (cur->name, (const xmlChar *) "TagGroup")) || (cur->ns != ns)) + { + g_warning ("The tag list file '%s' is of the wrong type, " + "was '%s', 'TagGroup' expected.", filename, cur->name); + xmlFreeDoc (doc); + + return taglist; + } + else + { + const char * const *langs_pointer; + gchar *lang; + gint cur_lanking; + gint i; + + langs_pointer = g_get_language_names (); + + lang = (gchar*) xmlGetProp (cur, (const xmlChar*) "lang"); + cur_lanking = 1; + + /* + * When found a new TagGroup, prepend the best + * tag_group to taglist. In the current intltool-merge, + * the first section is the default lang NULL. + */ + if (lang == NULL) { + if (best_tag_group != NULL) { + taglist->tag_groups = + g_list_prepend (taglist->tag_groups, best_tag_group); + } + + best_tag_group = NULL; + best_lanking = -1; + } + + /* + * If already find the best TagGroup on the current + * locale, ignore the logic. + */ + if (best_lanking != -1 && best_lanking <= cur_lanking) { + cur = cur->next; + continue; + } + + /* try to find the best lang */ + for (i = 0; langs_pointer[i] != NULL; i++) + { + const gchar *best_lang = langs_pointer[i]; + + /* + * if launch on C, POSIX locale or does + * not find the best lang on the current locale, + * this is called. + * g_get_language_names returns lang + * lists with C locale. + */ + if (lang == NULL && + (!g_ascii_strcasecmp (best_lang, "C") || + !g_ascii_strcasecmp (best_lang, "POSIX"))) + { + tag_group = get_tag_group (filename, doc, ns, cur); + if (tag_group != NULL) + { + if (best_tag_group !=NULL) + free_tag_group (best_tag_group); + best_lanking = cur_lanking; + best_tag_group = tag_group; + } + } + + /* if it is possible the best lang is not C */ + else if (lang == NULL) + { + cur_lanking++; + continue; + } + + /* if the best lang is found */ + else if (!g_ascii_strcasecmp (best_lang, lang)) + { + tag_group = get_tag_group (filename, doc, ns, cur); + if (tag_group != NULL) + { + if (best_tag_group !=NULL) + free_tag_group (best_tag_group); + best_lanking = cur_lanking; + best_tag_group = tag_group; + } + } + + cur_lanking++; + } + + if (lang) g_free (lang); + } /* End of else */ + + cur = cur->next; + } /* End of while (cur != NULL) */ + + /* Prepend TagGroup to TagList */ + if (best_tag_group != NULL) { + taglist->tag_groups = + g_list_prepend (taglist->tag_groups, best_tag_group); + } + + taglist->tag_groups = g_list_sort (taglist->tag_groups, groups_cmp); + + return taglist; +} + +static TagList * +parse_taglist_file (const gchar* filename) +{ + xmlDocPtr doc; + + xmlNsPtr ns; + xmlNodePtr cur; + + pluma_debug_message (DEBUG_PLUGINS, "Parse file: %s", filename); + + xmlKeepBlanksDefault (0); + + /* + * build an XML tree from a the file; + */ + doc = xmlParseFile (filename); + if (doc == NULL) + { + g_warning ("The tag list file '%s' is empty.", filename); + + return taglist; + } + + /* + * Check the document is of the right kind + */ + + cur = xmlDocGetRootElement (doc); + + if (cur == NULL) + { + g_warning ("The tag list file '%s' is empty.", filename); + xmlFreeDoc(doc); + return taglist; + } + + ns = xmlSearchNsByHref (doc, cur, + (const xmlChar *) "http://pluma.sourceforge.net/some-location"); + + if (ns == NULL) + { + g_warning ("The tag list file '%s' is of the wrong type, " + "pluma namespace not found.", filename); + xmlFreeDoc (doc); + + return taglist; + } + + if (xmlStrcmp(cur->name, (const xmlChar *) "TagList")) + { + g_warning ("The tag list file '%s' is of the wrong type, " + "root node != TagList.", filename); + xmlFreeDoc (doc); + + return taglist; + } + + /* + * If needed, allocate taglist + */ + + if (taglist == NULL) + taglist = g_new0 (TagList, 1); + + taglist = lookup_best_lang (taglist, filename, doc, ns, cur); + + xmlFreeDoc (doc); + + pluma_debug_message (DEBUG_PLUGINS, "END"); + + return taglist; +} + +static void +free_tag (Tag *tag) +{ + /* + pluma_debug_message (DEBUG_PLUGINS, "Tag: %s", tag->name); + */ + g_return_if_fail (tag != NULL); + + free (tag->name); + + if (tag->begin != NULL) + free (tag->begin); + + if (tag->end != NULL) + free (tag->end); + + g_free (tag); +} + +static void +free_tag_group (TagGroup *tag_group) +{ + GList *l; + + pluma_debug_message (DEBUG_PLUGINS, "Tag group: %s", tag_group->name); + + g_return_if_fail (tag_group != NULL); + + free (tag_group->name); + + for (l = tag_group->tags; l != NULL; l = g_list_next (l)) + { + free_tag ((Tag *) l->data); + } + + g_list_free (tag_group->tags); + g_free (tag_group); + + pluma_debug_message (DEBUG_PLUGINS, "END"); +} + +void +free_taglist (void) +{ + GList *l; + + pluma_debug_message (DEBUG_PLUGINS, "ref_count: %d", taglist_ref_count); + + if (taglist == NULL) + return; + + g_return_if_fail (taglist_ref_count > 0); + + --taglist_ref_count; + if (taglist_ref_count > 0) + return; + + for (l = taglist->tag_groups; l != NULL; l = g_list_next (l)) + { + free_tag_group ((TagGroup *) l->data); + } + + g_list_free (taglist->tag_groups); + g_free (taglist); + taglist = NULL; + + pluma_debug_message (DEBUG_PLUGINS, "Really freed"); +} + +static TagList * +parse_taglist_dir (const gchar *dir) +{ + GError *error = NULL; + GDir *d; + const gchar *dirent; + + pluma_debug_message (DEBUG_PLUGINS, "DIR: %s", dir); + + d = g_dir_open (dir, 0, &error); + if (!d) + { + pluma_debug_message (DEBUG_PLUGINS, "%s", error->message); + g_error_free (error); + return taglist; + } + + while ((dirent = g_dir_read_name (d))) + { + if (g_str_has_suffix (dirent, ".tags") || + g_str_has_suffix (dirent, ".tags.gz")) + { + gchar *tags_file = g_build_filename (dir, dirent, NULL); + parse_taglist_file (tags_file); + g_free (tags_file); + } + } + + g_dir_close (d); + + return taglist; +} + +TagList* create_taglist (const gchar *data_dir) +{ + gchar *pdir; + + pluma_debug_message (DEBUG_PLUGINS, "ref_count: %d", taglist_ref_count); + + if (taglist_ref_count > 0) + { + ++taglist_ref_count; + + return taglist; + } + +#ifndef G_OS_WIN32 + const gchar *home; + const gchar *envvar; + + /* load user's taglists */ + + /* legacy dir */ + home = g_get_home_dir (); + if (home != NULL) + { + pdir = g_build_filename (home, + USER_PLUMA_TAGLIST_PLUGIN_LOCATION_LEGACY, + NULL); + parse_taglist_dir (pdir); + g_free (pdir); + } + + /* Support old libmate env var */ + envvar = g_getenv ("MATE22_USER_DIR"); + if (envvar != NULL) + { + pdir = g_build_filename (envvar, + USER_PLUMA_TAGLIST_PLUGIN_LOCATION, + NULL); + parse_taglist_dir (pdir); + g_free (pdir); + } + else if (home != NULL) + { + pdir = g_build_filename (home, + ".mate2", + USER_PLUMA_TAGLIST_PLUGIN_LOCATION, + NULL); + parse_taglist_dir (pdir); + g_free (pdir); + } + +#else + pdir = g_build_filename (g_get_user_config_dir (), + "pluma", + "taglist", + NULL); + parse_taglist_dir (pdir); + g_free (pdir); +#endif + + /* load system's taglists */ + parse_taglist_dir (data_dir); + + ++taglist_ref_count; + g_return_val_if_fail (taglist_ref_count == 1, taglist); + + return taglist; +} diff --git a/plugins/taglist/pluma-taglist-plugin-parser.h b/plugins/taglist/pluma-taglist-plugin-parser.h new file mode 100755 index 00000000..42a8d3ff --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin-parser.h @@ -0,0 +1,68 @@ +/* + * pluma-taglist-plugin-parser.h + * This file is part of pluma + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the pluma Team, 2002-2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +#ifndef __PLUMA_TAGLIST_PLUGIN_PARSER_H__ +#define __PLUMA_TAGLIST_PLUGIN_PARSER_H__ + +#include +#include + +typedef struct _TagList TagList; +typedef struct _TagGroup TagGroup; +typedef struct _Tag Tag; + +struct _TagList +{ + GList *tag_groups; +}; + +struct _TagGroup +{ + xmlChar *name; + + GList *tags; +}; + +struct _Tag +{ + xmlChar *name; + xmlChar *begin; + xmlChar *end; +}; + +/* Note that the taglist is ref counted */ +extern TagList *taglist; + +TagList* create_taglist (const gchar *data_dir); + +void free_taglist (void); + +#endif /* __PLUMA_TAGLIST_PLUGIN_PARSER_H__ */ + diff --git a/plugins/taglist/pluma-taglist-plugin.c b/plugins/taglist/pluma-taglist-plugin.c new file mode 100755 index 00000000..202ab12e --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin.c @@ -0,0 +1,160 @@ +/* + * pluma-taglist-plugin.h + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + * Modified by the pluma Team, 2002-2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "pluma-taglist-plugin.h" +#include "pluma-taglist-plugin-panel.h" +#include "pluma-taglist-plugin-parser.h" + +#include +#include + +#include +#include + +#define WINDOW_DATA_KEY "PlumaTaglistPluginWindowData" + +#define PLUMA_TAGLIST_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), PLUMA_TYPE_TAGLIST_PLUGIN, PlumaTaglistPluginPrivate)) + +struct _PlumaTaglistPluginPrivate +{ + gpointer dummy; +}; + +PLUMA_PLUGIN_REGISTER_TYPE_WITH_CODE (PlumaTaglistPlugin, pluma_taglist_plugin, + pluma_taglist_plugin_panel_register_type (module); +) + +static void +pluma_taglist_plugin_init (PlumaTaglistPlugin *plugin) +{ + plugin->priv = PLUMA_TAGLIST_PLUGIN_GET_PRIVATE (plugin); + + pluma_debug_message (DEBUG_PLUGINS, "PlumaTaglistPlugin initializing"); +} + +static void +pluma_taglist_plugin_finalize (GObject *object) +{ +/* + PlumaTaglistPlugin *plugin = PLUMA_TAGLIST_PLUGIN (object); +*/ + pluma_debug_message (DEBUG_PLUGINS, "PlumaTaglistPlugin finalizing"); + + free_taglist (); + + G_OBJECT_CLASS (pluma_taglist_plugin_parent_class)->finalize (object); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + PlumaPanel *side_panel; + GtkWidget *taglist_panel; + gchar *data_dir; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY) == NULL); + + side_panel = pluma_window_get_side_panel (window); + + data_dir = pluma_plugin_get_data_dir (plugin); + taglist_panel = pluma_taglist_plugin_panel_new (window, data_dir); + g_free (data_dir); + + pluma_panel_add_item_with_stock_icon (side_panel, + taglist_panel, + _("Tags"), + GTK_STOCK_ADD); + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + taglist_panel); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + PlumaPanel *side_panel; + gpointer data; + + pluma_debug (DEBUG_PLUGINS); + + data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + side_panel = pluma_window_get_side_panel (window); + + pluma_panel_remove_item (side_panel, + GTK_WIDGET (data)); + + g_object_set_data (G_OBJECT (window), + WINDOW_DATA_KEY, + NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + gpointer data; + PlumaView *view; + + pluma_debug (DEBUG_PLUGINS); + + data = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + view = pluma_window_get_active_view (window); + + gtk_widget_set_sensitive (GTK_WIDGET (data), + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +pluma_taglist_plugin_class_init (PlumaTaglistPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_taglist_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; + + g_type_class_add_private (object_class, sizeof (PlumaTaglistPluginPrivate)); +} diff --git a/plugins/taglist/pluma-taglist-plugin.h b/plugins/taglist/pluma-taglist-plugin.h new file mode 100755 index 00000000..3ec8e088 --- /dev/null +++ b/plugins/taglist/pluma-taglist-plugin.h @@ -0,0 +1,85 @@ +/* + * pluma-taglist-plugin.h + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + * Modified by the pluma Team, 2002-2005. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + * + * $Id$ + */ + +#ifndef __PLUMA_TAGLIST_PLUGIN_H__ +#define __PLUMA_TAGLIST_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_TAGLIST_PLUGIN (pluma_taglist_plugin_get_type ()) +#define PLUMA_TAGLIST_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_TAGLIST_PLUGIN, PlumaTaglistPlugin)) +#define PLUMA_TAGLIST_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_TAGLIST_PLUGIN, PlumaTaglistPluginClass)) +#define PLUMA_IS_TAGLIST_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_TAGLIST_PLUGIN)) +#define PLUMA_IS_TAGLIST_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_TAGLIST_PLUGIN)) +#define PLUMA_TAGLIST_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_TAGLIST_PLUGIN, PlumaTaglistPluginClass)) + +/* Private structure type */ +typedef struct _PlumaTaglistPluginPrivate PlumaTaglistPluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaTaglistPlugin PlumaTaglistPlugin; + +struct _PlumaTaglistPlugin +{ + PlumaPlugin parent_instance; + + /*< private >*/ + PlumaTaglistPluginPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _PlumaTaglistPluginClass PlumaTaglistPluginClass; + +struct _PlumaTaglistPluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_taglist_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_TAGLIST_PLUGIN_H__ */ diff --git a/plugins/taglist/taglist.gedit-plugin.desktop.in b/plugins/taglist/taglist.gedit-plugin.desktop.in deleted file mode 100755 index 09d0f2d0..00000000 --- a/plugins/taglist/taglist.gedit-plugin.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Gedit Plugin] -Module=taglist -IAge=2 -_Name=Tag list -_Description=Provides a method to easily insert commonly used tags/strings into a document without having to type them. -Authors=Paolo Maggi -Copyright=Copyright © 2002-2005 Paolo Maggi -Website=http://www.gedit.org diff --git a/plugins/taglist/taglist.pluma-plugin.desktop.in b/plugins/taglist/taglist.pluma-plugin.desktop.in new file mode 100755 index 00000000..7337358a --- /dev/null +++ b/plugins/taglist/taglist.pluma-plugin.desktop.in @@ -0,0 +1,8 @@ +[Pluma Plugin] +Module=taglist +IAge=2 +_Name=Tag list +_Description=Provides a method to easily insert commonly used tags/strings into a document without having to type them. +Authors=Paolo Maggi +Copyright=Copyright © 2002-2005 Paolo Maggi +Website=http://www.pluma.org diff --git a/plugins/time/Makefile.am b/plugins/time/Makefile.am index c532f7d4..bfb442b6 100755 --- a/plugins/time/Makefile.am +++ b/plugins/time/Makefile.am @@ -1,31 +1,31 @@ # time plugin -plugindir = $(GEDIT_PLUGINS_LIBS_DIR) +plugindir = $(PLUMA_PLUGINS_LIBS_DIR) INCLUDES = \ -I$(top_srcdir) \ - $(GEDIT_CFLAGS) \ + $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) plugin_LTLIBRARIES = libtime.la libtime_la_SOURCES = \ - gedit-time-plugin.h \ - gedit-time-plugin.c + pluma-time-plugin.h \ + pluma-time-plugin.c libtime_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) -libtime_la_LIBADD = $(GEDIT_LIBS) +libtime_la_LIBADD = $(PLUMA_LIBS) -uidir = $(GEDIT_PLUGINS_DATA_DIR)/time +uidir = $(PLUMA_PLUGINS_DATA_DIR)/time ui_DATA = \ - gedit-time-dialog.ui \ - gedit-time-setup-dialog.ui + pluma-time-dialog.ui \ + pluma-time-setup-dialog.ui -plugin_in_files = time.gedit-plugin.desktop.in +plugin_in_files = time.pluma-plugin.desktop.in -%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache +%.pluma-plugin: %.pluma-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache -plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin) +plugin_DATA = $(plugin_in_files:.pluma-plugin.desktop.in=.pluma-plugin) EXTRA_DIST = $(ui_DATA) $(plugin_in_files) diff --git a/plugins/time/gedit-time-dialog.ui b/plugins/time/gedit-time-dialog.ui deleted file mode 100755 index 398e9b98..00000000 --- a/plugins/time/gedit-time-dialog.ui +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - 5 - Insert Date and Time - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - True - False - - - True - False - 2 - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-help - True - GTK_RELIEF_NORMAL - - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - - - - - True - True - True - GTK_RELIEF_NORMAL - - - True - 0.5 - 0.5 - 0 - 0 - - - True - False - 2 - - - True - mate-stock-timer - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - True - _Insert - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - - - - - - 0 - False - True - GTK_PACK_END - - - - - 5 - True - False - 6 - - - True - False - 6 - - - True - True - Use the _selected format - True - GTK_RELIEF_NORMAL - False - False - True - - - 0 - True - True - - - - - True - False - 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - True - False - False - False - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - True - False - 2 - - - True - False - 12 - - - True - True - _Use custom format - True - GTK_RELIEF_NORMAL - False - False - True - use_sel_format_radiobutton - - - 0 - False - False - - - - - True - True - True - True - 0 - %d/%m/%Y %H:%M:%S - True - False - - - 0 - True - True - - - - - 2 - True - True - - - - - True - 01/11/2009 17:52:00 - False - GTK_JUSTIFY_RIGHT - False - False - 1 - 0.5 - 0 - 0 - - - - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - False - True - - - - - - helpbutton1 - cancelbutton1 - okbutton1 - - - diff --git a/plugins/time/gedit-time-plugin.c b/plugins/time/gedit-time-plugin.c deleted file mode 100755 index 42bf6cb9..00000000 --- a/plugins/time/gedit-time-plugin.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* - * gedit-time-plugin.c - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -/* - * Modified by the gedit Team, 2002. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include - -#include "gedit-time-plugin.h" -#include - -#include -#include -#include - -#include -#include - -#define GEDIT_TIME_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ - GEDIT_TYPE_TIME_PLUGIN, \ - GeditTimePluginPrivate)) - -#define WINDOW_DATA_KEY "GeditTimePluginWindowData" -#define MENU_PATH "/MenuBar/EditMenu/EditOps_4" - -/* mateconf keys */ -#define TIME_BASE_KEY "/apps/gedit-2/plugins/time" -#define PROMPT_TYPE_KEY TIME_BASE_KEY "/prompt_type" -#define SELECTED_FORMAT_KEY TIME_BASE_KEY "/selected_format" -#define CUSTOM_FORMAT_KEY TIME_BASE_KEY "/custom_format" - -#define DEFAULT_CUSTOM_FORMAT "%d/%m/%Y %H:%M:%S" - -static const gchar *formats[] = -{ - "%c", - "%x", - "%X", - "%x %X", - "%Y-%m-%d %H:%M:%S", - "%a %b %d %H:%M:%S %Z %Y", - "%a %b %d %H:%M:%S %Y", - "%a %d %b %Y %H:%M:%S %Z", - "%a %d %b %Y %H:%M:%S", - "%d/%m/%Y", - "%d/%m/%y", -#ifndef G_OS_WIN32 - "%D", /* This one is not supported on win32 */ -#endif - "%A %d %B %Y", - "%A %B %d %Y", - "%Y-%m-%d", - "%d %B %Y", - "%B %d, %Y", - "%A %b %d", - "%H:%M:%S", - "%H:%M", - "%I:%M:%S %p", - "%I:%M %p", - "%H.%M.%S", - "%H.%M", - "%I.%M.%S %p", - "%I.%M %p", - "%d/%m/%Y %H:%M:%S", - "%d/%m/%y %H:%M:%S", -#if __GLIBC__ >= 2 - "%a, %d %b %Y %H:%M:%S %z", -#endif - NULL -}; - -enum -{ - COLUMN_FORMATS = 0, - COLUMN_INDEX, - NUM_COLUMNS -}; - -typedef struct _TimeConfigureDialog TimeConfigureDialog; - -struct _TimeConfigureDialog -{ - GtkWidget *dialog; - - GtkWidget *list; - - /* Radio buttons to indicate what should be done */ - GtkWidget *prompt; - GtkWidget *use_list; - GtkWidget *custom; - - GtkWidget *custom_entry; - GtkWidget *custom_format_example; - - /* Info needed for the response handler */ - GeditTimePlugin *plugin; -}; - -typedef struct _ChooseFormatDialog ChooseFormatDialog; - -struct _ChooseFormatDialog -{ - GtkWidget *dialog; - - GtkWidget *list; - - /* Radio buttons to indicate what should be done */ - GtkWidget *use_list; - GtkWidget *custom; - - GtkWidget *custom_entry; - GtkWidget *custom_format_example; - - /* Info needed for the response handler */ - GtkTextBuffer *buffer; - GeditTimePlugin *plugin; -}; - -typedef enum -{ - PROMPT_SELECTED_FORMAT = 0, /* Popup dialog with list preselected */ - PROMPT_CUSTOM_FORMAT, /* Popup dialog with entry preselected */ - USE_SELECTED_FORMAT, /* Use selected format directly */ - USE_CUSTOM_FORMAT /* Use custom format directly */ -} GeditTimePluginPromptType; - -struct _GeditTimePluginPrivate -{ - MateConfClient *mateconf_client; -}; - -GEDIT_PLUGIN_REGISTER_TYPE(GeditTimePlugin, gedit_time_plugin) - -typedef struct -{ - GtkActionGroup *action_group; - guint ui_id; -} WindowData; - -typedef struct -{ - GeditWindow *window; - GeditTimePlugin *plugin; -} ActionData; - -static void time_cb (GtkAction *action, ActionData *data); - -static const GtkActionEntry action_entries[] = -{ - { - "InsertDateAndTime", - NULL, - N_("In_sert Date and Time..."), - NULL, - N_("Insert current date and time at the cursor position"), - G_CALLBACK (time_cb) - }, -}; - -static void -gedit_time_plugin_init (GeditTimePlugin *plugin) -{ - gedit_debug_message (DEBUG_PLUGINS, "GeditTimePlugin initializing"); - - plugin->priv = GEDIT_TIME_PLUGIN_GET_PRIVATE (plugin); - - plugin->priv->mateconf_client = mateconf_client_get_default (); - - mateconf_client_add_dir (plugin->priv->mateconf_client, - TIME_BASE_KEY, - MATECONF_CLIENT_PRELOAD_ONELEVEL, - NULL); -} - -static void -gedit_time_plugin_finalize (GObject *object) -{ - GeditTimePlugin *plugin = GEDIT_TIME_PLUGIN (object); - - gedit_debug_message (DEBUG_PLUGINS, "GeditTimePlugin finalizing"); - - mateconf_client_suggest_sync (plugin->priv->mateconf_client, NULL); - - g_object_unref (G_OBJECT (plugin->priv->mateconf_client)); - - G_OBJECT_CLASS (gedit_time_plugin_parent_class)->finalize (object); -} - -static void -free_window_data (WindowData *data) -{ - g_return_if_fail (data != NULL); - - g_object_unref (data->action_group); - g_free (data); -} - -static void -update_ui_real (GeditWindow *window, - WindowData *data) -{ - GeditView *view; - GtkAction *action; - - gedit_debug (DEBUG_PLUGINS); - - view = gedit_window_get_active_view (window); - - gedit_debug_message (DEBUG_PLUGINS, "View: %p", view); - - action = gtk_action_group_get_action (data->action_group, - "InsertDateAndTime"); - gtk_action_set_sensitive (action, - (view != NULL) && - gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); -} - -static void -impl_activate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - ActionData *action_data; - - gedit_debug (DEBUG_PLUGINS); - - data = g_new (WindowData, 1); - action_data = g_new (ActionData, 1); - - action_data->plugin = GEDIT_TIME_PLUGIN (plugin); - action_data->window = window; - - manager = gedit_window_get_ui_manager (window); - - data->action_group = gtk_action_group_new ("GeditTimePluginActions"); - gtk_action_group_set_translation_domain (data->action_group, - GETTEXT_PACKAGE); - gtk_action_group_add_actions_full (data->action_group, - action_entries, - G_N_ELEMENTS (action_entries), - action_data, - (GDestroyNotify) g_free); - - gtk_ui_manager_insert_action_group (manager, data->action_group, -1); - - data->ui_id = gtk_ui_manager_new_merge_id (manager); - - g_object_set_data_full (G_OBJECT (window), - WINDOW_DATA_KEY, - data, - (GDestroyNotify) free_window_data); - - gtk_ui_manager_add_ui (manager, - data->ui_id, - MENU_PATH, - "InsertDateAndTime", - "InsertDateAndTime", - GTK_UI_MANAGER_MENUITEM, - FALSE); - - update_ui_real (window, data); -} - -static void -impl_deactivate (GeditPlugin *plugin, - GeditWindow *window) -{ - GtkUIManager *manager; - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - manager = gedit_window_get_ui_manager (window); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - gtk_ui_manager_remove_ui (manager, data->ui_id); - gtk_ui_manager_remove_action_group (manager, data->action_group); - - g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); -} - -static void -impl_update_ui (GeditPlugin *plugin, - GeditWindow *window) -{ - WindowData *data; - - gedit_debug (DEBUG_PLUGINS); - - data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); - g_return_if_fail (data != NULL); - - update_ui_real (window, data); -} - -/* whether we should prompt the user or use the specified format */ -static GeditTimePluginPromptType -get_prompt_type (GeditTimePlugin *plugin) -{ - gchar *prompt_type; - GeditTimePluginPromptType res; - - prompt_type = mateconf_client_get_string (plugin->priv->mateconf_client, - PROMPT_TYPE_KEY, - NULL); - - if (prompt_type == NULL) - return PROMPT_SELECTED_FORMAT; - - if (strcmp (prompt_type, "USE_SELECTED_FORMAT") == 0) - res = USE_SELECTED_FORMAT; - else if (strcmp (prompt_type, "USE_CUSTOM_FORMAT") == 0) - res = USE_CUSTOM_FORMAT; - else if (strcmp (prompt_type, "PROMPT_CUSTOM_FORMAT") == 0) - res = PROMPT_CUSTOM_FORMAT; - else - res = PROMPT_SELECTED_FORMAT; - - g_free (prompt_type); - - return res; -} - -static void -set_prompt_type (GeditTimePlugin *plugin, - GeditTimePluginPromptType prompt_type) -{ - const gchar * str; - - if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, - PROMPT_TYPE_KEY, - NULL)) - { - return; - } - - switch (prompt_type) - { - case USE_SELECTED_FORMAT: - str = "USE_SELECTED_FORMAT"; - break; - case USE_CUSTOM_FORMAT: - str = "USE_CUSTOM_FORMAT"; - break; - case PROMPT_CUSTOM_FORMAT: - str = "PROMPT_CUSTOM_FORMAT"; - break; - default: - str = "PROMPT_SELECTED_FORMAT"; - } - - mateconf_client_set_string (plugin->priv->mateconf_client, - PROMPT_TYPE_KEY, - str, - NULL); -} - -/* The selected format in the list */ -static gchar * -get_selected_format (GeditTimePlugin *plugin) -{ - gchar *sel_format; - - sel_format = mateconf_client_get_string (plugin->priv->mateconf_client, - SELECTED_FORMAT_KEY, - NULL); - - return sel_format ? sel_format : g_strdup (formats [0]); -} - -static void -set_selected_format (GeditTimePlugin *plugin, - const gchar *format) -{ - g_return_if_fail (format != NULL); - - if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, - SELECTED_FORMAT_KEY, - NULL)) - { - return; - } - - mateconf_client_set_string (plugin->priv->mateconf_client, - SELECTED_FORMAT_KEY, - format, - NULL); -} - -/* the custom format in the entry */ -static gchar * -get_custom_format (GeditTimePlugin *plugin) -{ - gchar *format; - - format = mateconf_client_get_string (plugin->priv->mateconf_client, - CUSTOM_FORMAT_KEY, - NULL); - - return format ? format : g_strdup (DEFAULT_CUSTOM_FORMAT); -} - -static void -set_custom_format (GeditTimePlugin *plugin, - const gchar *format) -{ - g_return_if_fail (format != NULL); - - if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, - CUSTOM_FORMAT_KEY, - NULL)) - return; - - mateconf_client_set_string (plugin->priv->mateconf_client, - CUSTOM_FORMAT_KEY, - format, - NULL); -} - -static gchar * -get_time (const gchar* format) -{ - gchar *out = NULL; - gchar *out_utf8 = NULL; - time_t clock; - struct tm *now; - size_t out_length = 0; - gchar *locale_format; - - gedit_debug (DEBUG_PLUGINS); - - g_return_val_if_fail (format != NULL, NULL); - - if (strlen (format) == 0) - return g_strdup (" "); - - locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL); - if (locale_format == NULL) - return g_strdup (" "); - - clock = time (NULL); - now = localtime (&clock); - - do - { - out_length += 255; - out = g_realloc (out, out_length); - } - while (strftime (out, out_length, locale_format, now) == 0); - - g_free (locale_format); - - if (g_utf8_validate (out, -1, NULL)) - { - out_utf8 = out; - } - else - { - out_utf8 = g_locale_to_utf8 (out, -1, NULL, NULL, NULL); - g_free (out); - - if (out_utf8 == NULL) - out_utf8 = g_strdup (" "); - } - - return out_utf8; -} - -static void -dialog_destroyed (GtkObject *obj, gpointer dialog_pointer) -{ - gedit_debug (DEBUG_PLUGINS); - - g_free (dialog_pointer); - - gedit_debug_message (DEBUG_PLUGINS, "END"); -} - -static GtkTreeModel * -create_model (GtkWidget *listview, - const gchar *sel_format, - GeditTimePlugin *plugin) -{ - gint i = 0; - GtkListStore *store; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gedit_debug (DEBUG_PLUGINS); - - /* create list store */ - store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT); - - /* Set tree view model*/ - gtk_tree_view_set_model (GTK_TREE_VIEW (listview), - GTK_TREE_MODEL (store)); - g_object_unref (G_OBJECT (store)); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (listview)); - g_return_val_if_fail (selection != NULL, GTK_TREE_MODEL (store)); - - /* there should always be one line selected */ - gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); - - /* add data to the list store */ - while (formats[i] != NULL) - { - gchar *str; - - str = get_time (formats[i]); - - gedit_debug_message (DEBUG_PLUGINS, "%d : %s", i, str); - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - COLUMN_FORMATS, str, - COLUMN_INDEX, i, - -1); - g_free (str); - - if (sel_format && strcmp (formats[i], sel_format) == 0) - gtk_tree_selection_select_iter (selection, &iter); - - ++i; - } - - /* fall back to select the first iter */ - if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) - { - gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter); - gtk_tree_selection_select_iter (selection, &iter); - } - - return GTK_TREE_MODEL (store); -} - -static void -scroll_to_selected (GtkTreeView *tree_view) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gedit_debug (DEBUG_PLUGINS); - - model = gtk_tree_view_get_model (tree_view); - g_return_if_fail (model != NULL); - - /* Scroll to selected */ - selection = gtk_tree_view_get_selection (tree_view); - g_return_if_fail (selection != NULL); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - GtkTreePath* path; - - path = gtk_tree_model_get_path (model, &iter); - g_return_if_fail (path != NULL); - - gtk_tree_view_scroll_to_cell (tree_view, - path, NULL, TRUE, 1.0, 0.0); - gtk_tree_path_free (path); - } -} - -static void -create_formats_list (GtkWidget *listview, - const gchar *sel_format, - GeditTimePlugin *plugin) -{ - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (listview != NULL); - g_return_if_fail (sel_format != NULL); - - /* the Available formats column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ( - _("Available formats"), - cell, - "text", COLUMN_FORMATS, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (listview), column); - - /* Create model, it also add model to the tree view */ - create_model (listview, sel_format, plugin); - - g_signal_connect (listview, - "realize", - G_CALLBACK (scroll_to_selected), - NULL); - - gtk_widget_show (listview); -} - -static void -updated_custom_format_example (GtkEntry *format_entry, - GtkLabel *format_example) -{ - const gchar *format; - gchar *time; - gchar *str; - gchar *escaped_time; - - gedit_debug (DEBUG_PLUGINS); - - g_return_if_fail (GTK_IS_ENTRY (format_entry)); - g_return_if_fail (GTK_IS_LABEL (format_example)); - - format = gtk_entry_get_text (format_entry); - - time = get_time (format); - escaped_time = g_markup_escape_text (time, -1); - - str = g_strdup_printf ("%s", escaped_time); - - gtk_label_set_markup (format_example, str); - - g_free (escaped_time); - g_free (time); - g_free (str); -} - -static void -choose_format_dialog_button_toggled (GtkToggleButton *button, - ChooseFormatDialog *dialog) -{ - gedit_debug (DEBUG_PLUGINS); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) - { - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, TRUE); - gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); - - return; - } - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) - { - gtk_widget_set_sensitive (dialog->list, TRUE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - - return; - } -} - -static void -configure_dialog_button_toggled (GtkToggleButton *button, TimeConfigureDialog *dialog) -{ - gedit_debug (DEBUG_PLUGINS); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) - { - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, TRUE); - gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); - - return; - } - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) - { - gtk_widget_set_sensitive (dialog->list, TRUE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - - return; - } - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->prompt))) - { - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - - return; - } -} - -static gint -get_format_from_list (GtkWidget *listview) -{ - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - gedit_debug (DEBUG_PLUGINS); - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (listview)); - g_return_val_if_fail (model != NULL, 0); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (listview)); - g_return_val_if_fail (selection != NULL, 0); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - gint selected_value; - - gtk_tree_model_get (model, &iter, COLUMN_INDEX, &selected_value, -1); - - gedit_debug_message (DEBUG_PLUGINS, "Sel value: %d", selected_value); - - return selected_value; - } - - g_return_val_if_reached (0); -} - -static TimeConfigureDialog * -get_configure_dialog (GeditTimePlugin *plugin) -{ - TimeConfigureDialog *dialog = NULL; - gchar *data_dir; - gchar *ui_file; - GtkWidget *content; - GtkWidget *viewport; - GeditTimePluginPromptType prompt_type; - gchar *sf, *cf; - GtkWidget *error_widget; - gboolean ret; - gchar *root_objects[] = { - "time_dialog_content", - NULL - }; - - gedit_debug (DEBUG_PLUGINS); - - dialog = g_new0 (TimeConfigureDialog, 1); - - dialog->dialog = gtk_dialog_new_with_buttons (_("Configure insert date/time plugin..."), - NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - GTK_STOCK_HELP, - GTK_RESPONSE_HELP, - NULL); - - /* HIG defaults */ - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog->dialog)), 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), - 2); /* 2 * 5 + 2 = 12 */ - gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dialog->dialog))), - 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog->dialog))), 6); - - g_return_val_if_fail (dialog->dialog != NULL, NULL); - - data_dir = gedit_plugin_get_data_dir (GEDIT_PLUGIN (plugin)); - ui_file = g_build_filename (data_dir, "gedit-time-setup-dialog.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - root_objects, - &error_widget, - "time_dialog_content", &content, - "formats_viewport", &viewport, - "formats_tree", &dialog->list, - "always_prompt", &dialog->prompt, - "never_prompt", &dialog->use_list, - "use_custom", &dialog->custom, - "custom_entry", &dialog->custom_entry, - "custom_format_example", &dialog->custom_format_example, - NULL); - - g_free (data_dir); - g_free (ui_file); - - if (!ret) - { - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), - error_widget, - TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (error_widget), 5); - - gtk_widget_show (error_widget); - - return dialog; - } - - gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE); - gtk_dialog_set_has_separator (GTK_DIALOG (dialog->dialog), FALSE); - - sf = get_selected_format (plugin); - create_formats_list (dialog->list, sf, plugin); - g_free (sf); - - prompt_type = get_prompt_type (plugin); - - cf = get_custom_format (plugin); - gtk_entry_set_text (GTK_ENTRY(dialog->custom_entry), cf); - g_free (cf); - - if (prompt_type == USE_CUSTOM_FORMAT) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->custom), TRUE); - - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, TRUE); - gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); - } - else if (prompt_type == USE_SELECTED_FORMAT) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->use_list), TRUE); - - gtk_widget_set_sensitive (dialog->list, TRUE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - } - else - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->prompt), TRUE); - - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - } - - updated_custom_format_example (GTK_ENTRY (dialog->custom_entry), - GTK_LABEL (dialog->custom_format_example)); - - /* setup a window of a sane size. */ - gtk_widget_set_size_request (GTK_WIDGET (viewport), 10, 200); - - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), - content, FALSE, FALSE, 0); - g_object_unref (content); - gtk_container_set_border_width (GTK_CONTAINER (content), 5); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), - GTK_RESPONSE_OK); - - g_signal_connect (dialog->custom, - "toggled", - G_CALLBACK (configure_dialog_button_toggled), - dialog); - g_signal_connect (dialog->prompt, - "toggled", - G_CALLBACK (configure_dialog_button_toggled), - dialog); - g_signal_connect (dialog->use_list, - "toggled", - G_CALLBACK (configure_dialog_button_toggled), - dialog); - g_signal_connect (dialog->dialog, - "destroy", - G_CALLBACK (dialog_destroyed), - dialog); - g_signal_connect (dialog->custom_entry, - "changed", - G_CALLBACK (updated_custom_format_example), - dialog->custom_format_example); - - return dialog; -} - -static void -real_insert_time (GtkTextBuffer *buffer, - const gchar *the_time) -{ - gedit_debug_message (DEBUG_PLUGINS, "Insert: %s", the_time); - - gtk_text_buffer_begin_user_action (buffer); - - gtk_text_buffer_insert_at_cursor (buffer, the_time, -1); - gtk_text_buffer_insert_at_cursor (buffer, " ", -1); - - gtk_text_buffer_end_user_action (buffer); -} - -static void -choose_format_dialog_row_activated (GtkTreeView *list, - GtkTreePath *path, - GtkTreeViewColumn *column, - ChooseFormatDialog *dialog) -{ - gint sel_format; - gchar *the_time; - - sel_format = get_format_from_list (dialog->list); - the_time = get_time (formats[sel_format]); - - set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); - set_selected_format (dialog->plugin, formats[sel_format]); - - g_return_if_fail (the_time != NULL); - - real_insert_time (dialog->buffer, the_time); - - g_free (the_time); -} - -static ChooseFormatDialog * -get_choose_format_dialog (GtkWindow *parent, - GeditTimePluginPromptType prompt_type, - GeditTimePlugin *plugin) -{ - ChooseFormatDialog *dialog; - gchar *data_dir; - gchar *ui_file; - GtkWidget *error_widget; - gboolean ret; - gchar *sf, *cf; - GtkWindowGroup *wg = NULL; - - if (parent != NULL) - wg = gtk_window_get_group (parent); - - dialog = g_new0 (ChooseFormatDialog, 1); - - data_dir = gedit_plugin_get_data_dir (GEDIT_PLUGIN (plugin)); - ui_file = g_build_filename (data_dir, "gedit-time-dialog.ui", NULL); - ret = gedit_utils_get_ui_objects (ui_file, - NULL, - &error_widget, - "choose_format_dialog", &dialog->dialog, - "choice_list", &dialog->list, - "use_sel_format_radiobutton", &dialog->use_list, - "use_custom_radiobutton", &dialog->custom, - "custom_entry", &dialog->custom_entry, - "custom_format_example", &dialog->custom_format_example, - NULL); - - g_free (data_dir); - g_free (ui_file); - - if (!ret) - { - GtkWidget *err_dialog; - - err_dialog = gtk_dialog_new_with_buttons (NULL, - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - NULL); - - if (wg != NULL) - gtk_window_group_add_window (wg, GTK_WINDOW (err_dialog)); - - gtk_window_set_resizable (GTK_WINDOW (err_dialog), FALSE); - gtk_dialog_set_has_separator (GTK_DIALOG (err_dialog), FALSE); - gtk_dialog_set_default_response (GTK_DIALOG (err_dialog), GTK_RESPONSE_OK); - - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (err_dialog))), - error_widget); - - g_signal_connect (G_OBJECT (err_dialog), - "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - - gtk_widget_show_all (err_dialog); - - return NULL; - } - - gtk_window_group_add_window (wg, - GTK_WINDOW (dialog->dialog)); - gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), parent); - gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); - - sf = get_selected_format (plugin); - create_formats_list (dialog->list, sf, plugin); - g_free (sf); - - cf = get_custom_format (plugin); - gtk_entry_set_text (GTK_ENTRY(dialog->custom_entry), cf); - g_free (cf); - - updated_custom_format_example (GTK_ENTRY (dialog->custom_entry), - GTK_LABEL (dialog->custom_format_example)); - - if (prompt_type == PROMPT_CUSTOM_FORMAT) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->custom), TRUE); - - gtk_widget_set_sensitive (dialog->list, FALSE); - gtk_widget_set_sensitive (dialog->custom_entry, TRUE); - gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); - } - else if (prompt_type == PROMPT_SELECTED_FORMAT) - { - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->use_list), TRUE); - - gtk_widget_set_sensitive (dialog->list, TRUE); - gtk_widget_set_sensitive (dialog->custom_entry, FALSE); - gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); - } - else - { - g_return_val_if_reached (NULL); - } - - /* setup a window of a sane size. */ - gtk_widget_set_size_request (dialog->list, 10, 200); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), - GTK_RESPONSE_OK); - - g_signal_connect (dialog->custom, - "toggled", - G_CALLBACK (choose_format_dialog_button_toggled), - dialog); - g_signal_connect (dialog->use_list, - "toggled", - G_CALLBACK (choose_format_dialog_button_toggled), - dialog); - g_signal_connect (dialog->dialog, - "destroy", - G_CALLBACK (dialog_destroyed), - dialog); - g_signal_connect (dialog->custom_entry, - "changed", - G_CALLBACK (updated_custom_format_example), - dialog->custom_format_example); - g_signal_connect (dialog->list, - "row_activated", - G_CALLBACK (choose_format_dialog_row_activated), - dialog); - - gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE); - - return dialog; -} - -static void -choose_format_dialog_response_cb (GtkWidget *widget, - gint response, - ChooseFormatDialog *dialog) -{ - switch (response) - { - case GTK_RESPONSE_HELP: - { - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_HELP"); - gedit_help_display (GTK_WINDOW (widget), - NULL, - "gedit-insert-date-time-plugin"); - break; - } - case GTK_RESPONSE_OK: - { - gchar *the_time; - - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); - - /* Get the user's chosen format */ - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) - { - gint sel_format; - - sel_format = get_format_from_list (dialog->list); - the_time = get_time (formats[sel_format]); - - set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); - set_selected_format (dialog->plugin, formats[sel_format]); - } - else - { - const gchar *format; - - format = gtk_entry_get_text (GTK_ENTRY (dialog->custom_entry)); - the_time = get_time (format); - - set_prompt_type (dialog->plugin, PROMPT_CUSTOM_FORMAT); - set_custom_format (dialog->plugin, format); - } - - g_return_if_fail (the_time != NULL); - - real_insert_time (dialog->buffer, the_time); - g_free (the_time); - - gtk_widget_destroy (dialog->dialog); - break; - } - case GTK_RESPONSE_CANCEL: - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CANCEL"); - gtk_widget_destroy (dialog->dialog); - } -} - -static void -time_cb (GtkAction *action, - ActionData *data) -{ - GtkTextBuffer *buffer; - gchar *the_time = NULL; - GeditTimePluginPromptType prompt_type; - - gedit_debug (DEBUG_PLUGINS); - - buffer = GTK_TEXT_BUFFER (gedit_window_get_active_document (data->window)); - g_return_if_fail (buffer != NULL); - - prompt_type = get_prompt_type (data->plugin); - - if (prompt_type == USE_CUSTOM_FORMAT) - { - gchar *cf = get_custom_format (data->plugin); - the_time = get_time (cf); - g_free (cf); - } - else if (prompt_type == USE_SELECTED_FORMAT) - { - gchar *sf = get_selected_format (data->plugin); - the_time = get_time (sf); - g_free (sf); - } - else - { - ChooseFormatDialog *dialog; - - dialog = get_choose_format_dialog (GTK_WINDOW (data->window), - prompt_type, - data->plugin); - if (dialog != NULL) - { - dialog->buffer = buffer; - dialog->plugin = data->plugin; - - g_signal_connect (dialog->dialog, - "response", - G_CALLBACK (choose_format_dialog_response_cb), - dialog); - - gtk_widget_show (GTK_WIDGET (dialog->dialog)); - } - - return; - } - - g_return_if_fail (the_time != NULL); - - real_insert_time (buffer, the_time); - - g_free (the_time); -} - -static void -ok_button_pressed (TimeConfigureDialog *dialog) -{ - gint sel_format; - const gchar *custom_format; - - gedit_debug (DEBUG_PLUGINS); - - sel_format = get_format_from_list (dialog->list); - - custom_format = gtk_entry_get_text (GTK_ENTRY (dialog->custom_entry)); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) - { - set_prompt_type (dialog->plugin, USE_CUSTOM_FORMAT); - set_custom_format (dialog->plugin, custom_format); - } - else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) - { - set_prompt_type (dialog->plugin, USE_SELECTED_FORMAT); - set_selected_format (dialog->plugin, formats [sel_format]); - } - else - { - /* Default to prompt the user with the list selected */ - set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); - } - - gedit_debug_message (DEBUG_PLUGINS, "Sel: %d", sel_format); -} - -static void -configure_dialog_response_cb (GtkWidget *widget, - gint response, - TimeConfigureDialog *dialog) -{ - switch (response) - { - case GTK_RESPONSE_HELP: - { - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_HELP"); - - gedit_help_display (GTK_WINDOW (dialog), - NULL, - "gedit-date-time-configure"); - break; - } - case GTK_RESPONSE_OK: - { - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); - - ok_button_pressed (dialog); - - gtk_widget_destroy (dialog->dialog); - break; - } - case GTK_RESPONSE_CANCEL: - { - gedit_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CANCEL"); - gtk_widget_destroy (dialog->dialog); - } - } -} - -static GtkWidget * -impl_create_configure_dialog (GeditPlugin *plugin) -{ - TimeConfigureDialog *dialog; - - dialog = get_configure_dialog (GEDIT_TIME_PLUGIN (plugin)); - - dialog->plugin = GEDIT_TIME_PLUGIN (plugin); - - g_signal_connect (dialog->dialog, - "response", - G_CALLBACK (configure_dialog_response_cb), - dialog); - - return GTK_WIDGET (dialog->dialog); -} - -static void -gedit_time_plugin_class_init (GeditTimePluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass); - - object_class->finalize = gedit_time_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - plugin_class->update_ui = impl_update_ui; - - plugin_class->create_configure_dialog = impl_create_configure_dialog; - - g_type_class_add_private (object_class, sizeof (GeditTimePluginPrivate)); -} diff --git a/plugins/time/gedit-time-plugin.h b/plugins/time/gedit-time-plugin.h deleted file mode 100755 index 6d598264..00000000 --- a/plugins/time/gedit-time-plugin.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * gedit-time-plugin.h - * - * Copyright (C) 2002-2005 - Paolo Maggi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#ifndef __GEDIT_TIME_PLUGIN_H__ -#define __GEDIT_TIME_PLUGIN_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -/* - * Type checking and casting macros - */ -#define GEDIT_TYPE_TIME_PLUGIN (gedit_time_plugin_get_type ()) -#define GEDIT_TIME_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GEDIT_TYPE_TIME_PLUGIN, GeditTimePlugin)) -#define GEDIT_TIME_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GEDIT_TYPE_TIME_PLUGIN, GeditTimePluginClass)) -#define GEDIT_IS_TIME_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GEDIT_TYPE_TIME_PLUGIN)) -#define GEDIT_IS_TIME_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_TIME_PLUGIN)) -#define GEDIT_TIME_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_TIME_PLUGIN, GeditTimePluginClass)) - -/* Private structure type */ -typedef struct _GeditTimePluginPrivate GeditTimePluginPrivate; - -/* - * Main object structure - */ -typedef struct _GeditTimePlugin GeditTimePlugin; - -struct _GeditTimePlugin -{ - GeditPlugin parent_instance; - - /*< private >*/ - GeditTimePluginPrivate *priv; -}; - -/* - * Class definition - */ -typedef struct _GeditTimePluginClass GeditTimePluginClass; - -struct _GeditTimePluginClass -{ - GeditPluginClass parent_class; -}; - -/* - * Public methods - */ -GType gedit_time_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GEDIT_TIME_PLUGIN_H__ */ diff --git a/plugins/time/gedit-time-setup-dialog.ui b/plugins/time/gedit-time-setup-dialog.ui deleted file mode 100755 index 46fb5b9d..00000000 --- a/plugins/time/gedit-time-setup-dialog.ui +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - Configure date/time plugin - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - False - False - False - - - True - False - 8 - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-help - True - GTK_RELIEF_NORMAL - - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - - - - - 0 - False - True - GTK_PACK_END - - - - - 10 - True - False - 6 - - - True - When inserting date/time... - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - - - - - - 0 - False - False - - - - - True - False - 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - True - False - 6 - - - True - True - _Prompt for a format - True - GTK_RELIEF_NORMAL - False - False - True - - - 0 - True - True - - - - - True - False - 6 - - - True - True - Use the _selected format - True - GTK_RELIEF_NORMAL - False - False - True - always_prompt - - - 0 - True - True - - - - - True - False - 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - True - False - False - False - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - True - False - 2 - - - True - False - 12 - - - True - True - _Use custom format - True - GTK_RELIEF_NORMAL - False - False - True - always_prompt - - - 0 - False - False - - - - - True - True - True - True - 0 - %d/%m/%Y %H:%M:%S - True - False - - - 0 - True - True - - - - - 2 - True - True - - - - - True - 01/11/2009 17:52:00 - False - GTK_JUSTIFY_RIGHT - False - False - 1 - 0.5 - 0 - 0 - - - - - - 0 - False - False - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - True - True - - - - - 0 - False - True - - - - - - button1 - button3 - button4 - - - diff --git a/plugins/time/pluma-time-dialog.ui b/plugins/time/pluma-time-dialog.ui new file mode 100755 index 00000000..398e9b98 --- /dev/null +++ b/plugins/time/pluma-time-dialog.ui @@ -0,0 +1,297 @@ + + + + + + 5 + Insert Date and Time + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + False + + + True + False + 2 + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + + + + + True + True + True + GTK_RELIEF_NORMAL + + + True + 0.5 + 0.5 + 0 + 0 + + + True + False + 2 + + + True + mate-stock-timer + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + True + _Insert + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + 5 + True + False + 6 + + + True + False + 6 + + + True + True + Use the _selected format + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + True + True + + + + + True + False + 0 + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + True + False + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + True + False + 2 + + + True + False + 12 + + + True + True + _Use custom format + True + GTK_RELIEF_NORMAL + False + False + True + use_sel_format_radiobutton + + + 0 + False + False + + + + + True + True + True + True + 0 + %d/%m/%Y %H:%M:%S + True + False + + + 0 + True + True + + + + + 2 + True + True + + + + + True + 01/11/2009 17:52:00 + False + GTK_JUSTIFY_RIGHT + False + False + 1 + 0.5 + 0 + 0 + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + False + True + + + + + + helpbutton1 + cancelbutton1 + okbutton1 + + + diff --git a/plugins/time/pluma-time-plugin.c b/plugins/time/pluma-time-plugin.c new file mode 100755 index 00000000..d504bdf4 --- /dev/null +++ b/plugins/time/pluma-time-plugin.c @@ -0,0 +1,1272 @@ +/* + * pluma-time-plugin.c + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +/* + * Modified by the pluma Team, 2002. See the AUTHORS file for a + * list of people on the pluma Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "pluma-time-plugin.h" +#include + +#include +#include +#include + +#include +#include + +#define PLUMA_TIME_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + PLUMA_TYPE_TIME_PLUGIN, \ + PlumaTimePluginPrivate)) + +#define WINDOW_DATA_KEY "PlumaTimePluginWindowData" +#define MENU_PATH "/MenuBar/EditMenu/EditOps_4" + +/* mateconf keys */ +#define TIME_BASE_KEY "/apps/pluma-2/plugins/time" +#define PROMPT_TYPE_KEY TIME_BASE_KEY "/prompt_type" +#define SELECTED_FORMAT_KEY TIME_BASE_KEY "/selected_format" +#define CUSTOM_FORMAT_KEY TIME_BASE_KEY "/custom_format" + +#define DEFAULT_CUSTOM_FORMAT "%d/%m/%Y %H:%M:%S" + +static const gchar *formats[] = +{ + "%c", + "%x", + "%X", + "%x %X", + "%Y-%m-%d %H:%M:%S", + "%a %b %d %H:%M:%S %Z %Y", + "%a %b %d %H:%M:%S %Y", + "%a %d %b %Y %H:%M:%S %Z", + "%a %d %b %Y %H:%M:%S", + "%d/%m/%Y", + "%d/%m/%y", +#ifndef G_OS_WIN32 + "%D", /* This one is not supported on win32 */ +#endif + "%A %d %B %Y", + "%A %B %d %Y", + "%Y-%m-%d", + "%d %B %Y", + "%B %d, %Y", + "%A %b %d", + "%H:%M:%S", + "%H:%M", + "%I:%M:%S %p", + "%I:%M %p", + "%H.%M.%S", + "%H.%M", + "%I.%M.%S %p", + "%I.%M %p", + "%d/%m/%Y %H:%M:%S", + "%d/%m/%y %H:%M:%S", +#if __GLIBC__ >= 2 + "%a, %d %b %Y %H:%M:%S %z", +#endif + NULL +}; + +enum +{ + COLUMN_FORMATS = 0, + COLUMN_INDEX, + NUM_COLUMNS +}; + +typedef struct _TimeConfigureDialog TimeConfigureDialog; + +struct _TimeConfigureDialog +{ + GtkWidget *dialog; + + GtkWidget *list; + + /* Radio buttons to indicate what should be done */ + GtkWidget *prompt; + GtkWidget *use_list; + GtkWidget *custom; + + GtkWidget *custom_entry; + GtkWidget *custom_format_example; + + /* Info needed for the response handler */ + PlumaTimePlugin *plugin; +}; + +typedef struct _ChooseFormatDialog ChooseFormatDialog; + +struct _ChooseFormatDialog +{ + GtkWidget *dialog; + + GtkWidget *list; + + /* Radio buttons to indicate what should be done */ + GtkWidget *use_list; + GtkWidget *custom; + + GtkWidget *custom_entry; + GtkWidget *custom_format_example; + + /* Info needed for the response handler */ + GtkTextBuffer *buffer; + PlumaTimePlugin *plugin; +}; + +typedef enum +{ + PROMPT_SELECTED_FORMAT = 0, /* Popup dialog with list preselected */ + PROMPT_CUSTOM_FORMAT, /* Popup dialog with entry preselected */ + USE_SELECTED_FORMAT, /* Use selected format directly */ + USE_CUSTOM_FORMAT /* Use custom format directly */ +} PlumaTimePluginPromptType; + +struct _PlumaTimePluginPrivate +{ + MateConfClient *mateconf_client; +}; + +PLUMA_PLUGIN_REGISTER_TYPE(PlumaTimePlugin, pluma_time_plugin) + +typedef struct +{ + GtkActionGroup *action_group; + guint ui_id; +} WindowData; + +typedef struct +{ + PlumaWindow *window; + PlumaTimePlugin *plugin; +} ActionData; + +static void time_cb (GtkAction *action, ActionData *data); + +static const GtkActionEntry action_entries[] = +{ + { + "InsertDateAndTime", + NULL, + N_("In_sert Date and Time..."), + NULL, + N_("Insert current date and time at the cursor position"), + G_CALLBACK (time_cb) + }, +}; + +static void +pluma_time_plugin_init (PlumaTimePlugin *plugin) +{ + pluma_debug_message (DEBUG_PLUGINS, "PlumaTimePlugin initializing"); + + plugin->priv = PLUMA_TIME_PLUGIN_GET_PRIVATE (plugin); + + plugin->priv->mateconf_client = mateconf_client_get_default (); + + mateconf_client_add_dir (plugin->priv->mateconf_client, + TIME_BASE_KEY, + MATECONF_CLIENT_PRELOAD_ONELEVEL, + NULL); +} + +static void +pluma_time_plugin_finalize (GObject *object) +{ + PlumaTimePlugin *plugin = PLUMA_TIME_PLUGIN (object); + + pluma_debug_message (DEBUG_PLUGINS, "PlumaTimePlugin finalizing"); + + mateconf_client_suggest_sync (plugin->priv->mateconf_client, NULL); + + g_object_unref (G_OBJECT (plugin->priv->mateconf_client)); + + G_OBJECT_CLASS (pluma_time_plugin_parent_class)->finalize (object); +} + +static void +free_window_data (WindowData *data) +{ + g_return_if_fail (data != NULL); + + g_object_unref (data->action_group); + g_free (data); +} + +static void +update_ui_real (PlumaWindow *window, + WindowData *data) +{ + PlumaView *view; + GtkAction *action; + + pluma_debug (DEBUG_PLUGINS); + + view = pluma_window_get_active_view (window); + + pluma_debug_message (DEBUG_PLUGINS, "View: %p", view); + + action = gtk_action_group_get_action (data->action_group, + "InsertDateAndTime"); + gtk_action_set_sensitive (action, + (view != NULL) && + gtk_text_view_get_editable (GTK_TEXT_VIEW (view))); +} + +static void +impl_activate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + ActionData *action_data; + + pluma_debug (DEBUG_PLUGINS); + + data = g_new (WindowData, 1); + action_data = g_new (ActionData, 1); + + action_data->plugin = PLUMA_TIME_PLUGIN (plugin); + action_data->window = window; + + manager = pluma_window_get_ui_manager (window); + + data->action_group = gtk_action_group_new ("PlumaTimePluginActions"); + gtk_action_group_set_translation_domain (data->action_group, + GETTEXT_PACKAGE); + gtk_action_group_add_actions_full (data->action_group, + action_entries, + G_N_ELEMENTS (action_entries), + action_data, + (GDestroyNotify) g_free); + + gtk_ui_manager_insert_action_group (manager, data->action_group, -1); + + data->ui_id = gtk_ui_manager_new_merge_id (manager); + + g_object_set_data_full (G_OBJECT (window), + WINDOW_DATA_KEY, + data, + (GDestroyNotify) free_window_data); + + gtk_ui_manager_add_ui (manager, + data->ui_id, + MENU_PATH, + "InsertDateAndTime", + "InsertDateAndTime", + GTK_UI_MANAGER_MENUITEM, + FALSE); + + update_ui_real (window, data); +} + +static void +impl_deactivate (PlumaPlugin *plugin, + PlumaWindow *window) +{ + GtkUIManager *manager; + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + manager = pluma_window_get_ui_manager (window); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + gtk_ui_manager_remove_ui (manager, data->ui_id); + gtk_ui_manager_remove_action_group (manager, data->action_group); + + g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL); +} + +static void +impl_update_ui (PlumaPlugin *plugin, + PlumaWindow *window) +{ + WindowData *data; + + pluma_debug (DEBUG_PLUGINS); + + data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY); + g_return_if_fail (data != NULL); + + update_ui_real (window, data); +} + +/* whether we should prompt the user or use the specified format */ +static PlumaTimePluginPromptType +get_prompt_type (PlumaTimePlugin *plugin) +{ + gchar *prompt_type; + PlumaTimePluginPromptType res; + + prompt_type = mateconf_client_get_string (plugin->priv->mateconf_client, + PROMPT_TYPE_KEY, + NULL); + + if (prompt_type == NULL) + return PROMPT_SELECTED_FORMAT; + + if (strcmp (prompt_type, "USE_SELECTED_FORMAT") == 0) + res = USE_SELECTED_FORMAT; + else if (strcmp (prompt_type, "USE_CUSTOM_FORMAT") == 0) + res = USE_CUSTOM_FORMAT; + else if (strcmp (prompt_type, "PROMPT_CUSTOM_FORMAT") == 0) + res = PROMPT_CUSTOM_FORMAT; + else + res = PROMPT_SELECTED_FORMAT; + + g_free (prompt_type); + + return res; +} + +static void +set_prompt_type (PlumaTimePlugin *plugin, + PlumaTimePluginPromptType prompt_type) +{ + const gchar * str; + + if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, + PROMPT_TYPE_KEY, + NULL)) + { + return; + } + + switch (prompt_type) + { + case USE_SELECTED_FORMAT: + str = "USE_SELECTED_FORMAT"; + break; + case USE_CUSTOM_FORMAT: + str = "USE_CUSTOM_FORMAT"; + break; + case PROMPT_CUSTOM_FORMAT: + str = "PROMPT_CUSTOM_FORMAT"; + break; + default: + str = "PROMPT_SELECTED_FORMAT"; + } + + mateconf_client_set_string (plugin->priv->mateconf_client, + PROMPT_TYPE_KEY, + str, + NULL); +} + +/* The selected format in the list */ +static gchar * +get_selected_format (PlumaTimePlugin *plugin) +{ + gchar *sel_format; + + sel_format = mateconf_client_get_string (plugin->priv->mateconf_client, + SELECTED_FORMAT_KEY, + NULL); + + return sel_format ? sel_format : g_strdup (formats [0]); +} + +static void +set_selected_format (PlumaTimePlugin *plugin, + const gchar *format) +{ + g_return_if_fail (format != NULL); + + if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, + SELECTED_FORMAT_KEY, + NULL)) + { + return; + } + + mateconf_client_set_string (plugin->priv->mateconf_client, + SELECTED_FORMAT_KEY, + format, + NULL); +} + +/* the custom format in the entry */ +static gchar * +get_custom_format (PlumaTimePlugin *plugin) +{ + gchar *format; + + format = mateconf_client_get_string (plugin->priv->mateconf_client, + CUSTOM_FORMAT_KEY, + NULL); + + return format ? format : g_strdup (DEFAULT_CUSTOM_FORMAT); +} + +static void +set_custom_format (PlumaTimePlugin *plugin, + const gchar *format) +{ + g_return_if_fail (format != NULL); + + if (!mateconf_client_key_is_writable (plugin->priv->mateconf_client, + CUSTOM_FORMAT_KEY, + NULL)) + return; + + mateconf_client_set_string (plugin->priv->mateconf_client, + CUSTOM_FORMAT_KEY, + format, + NULL); +} + +static gchar * +get_time (const gchar* format) +{ + gchar *out = NULL; + gchar *out_utf8 = NULL; + time_t clock; + struct tm *now; + size_t out_length = 0; + gchar *locale_format; + + pluma_debug (DEBUG_PLUGINS); + + g_return_val_if_fail (format != NULL, NULL); + + if (strlen (format) == 0) + return g_strdup (" "); + + locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL); + if (locale_format == NULL) + return g_strdup (" "); + + clock = time (NULL); + now = localtime (&clock); + + do + { + out_length += 255; + out = g_realloc (out, out_length); + } + while (strftime (out, out_length, locale_format, now) == 0); + + g_free (locale_format); + + if (g_utf8_validate (out, -1, NULL)) + { + out_utf8 = out; + } + else + { + out_utf8 = g_locale_to_utf8 (out, -1, NULL, NULL, NULL); + g_free (out); + + if (out_utf8 == NULL) + out_utf8 = g_strdup (" "); + } + + return out_utf8; +} + +static void +dialog_destroyed (GtkObject *obj, gpointer dialog_pointer) +{ + pluma_debug (DEBUG_PLUGINS); + + g_free (dialog_pointer); + + pluma_debug_message (DEBUG_PLUGINS, "END"); +} + +static GtkTreeModel * +create_model (GtkWidget *listview, + const gchar *sel_format, + PlumaTimePlugin *plugin) +{ + gint i = 0; + GtkListStore *store; + GtkTreeSelection *selection; + GtkTreeIter iter; + + pluma_debug (DEBUG_PLUGINS); + + /* create list store */ + store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT); + + /* Set tree view model*/ + gtk_tree_view_set_model (GTK_TREE_VIEW (listview), + GTK_TREE_MODEL (store)); + g_object_unref (G_OBJECT (store)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (listview)); + g_return_val_if_fail (selection != NULL, GTK_TREE_MODEL (store)); + + /* there should always be one line selected */ + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + + /* add data to the list store */ + while (formats[i] != NULL) + { + gchar *str; + + str = get_time (formats[i]); + + pluma_debug_message (DEBUG_PLUGINS, "%d : %s", i, str); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + COLUMN_FORMATS, str, + COLUMN_INDEX, i, + -1); + g_free (str); + + if (sel_format && strcmp (formats[i], sel_format) == 0) + gtk_tree_selection_select_iter (selection, &iter); + + ++i; + } + + /* fall back to select the first iter */ + if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) + { + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter); + gtk_tree_selection_select_iter (selection, &iter); + } + + return GTK_TREE_MODEL (store); +} + +static void +scroll_to_selected (GtkTreeView *tree_view) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + pluma_debug (DEBUG_PLUGINS); + + model = gtk_tree_view_get_model (tree_view); + g_return_if_fail (model != NULL); + + /* Scroll to selected */ + selection = gtk_tree_view_get_selection (tree_view); + g_return_if_fail (selection != NULL); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + GtkTreePath* path; + + path = gtk_tree_model_get_path (model, &iter); + g_return_if_fail (path != NULL); + + gtk_tree_view_scroll_to_cell (tree_view, + path, NULL, TRUE, 1.0, 0.0); + gtk_tree_path_free (path); + } +} + +static void +create_formats_list (GtkWidget *listview, + const gchar *sel_format, + PlumaTimePlugin *plugin) +{ + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (listview != NULL); + g_return_if_fail (sel_format != NULL); + + /* the Available formats column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ( + _("Available formats"), + cell, + "text", COLUMN_FORMATS, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (listview), column); + + /* Create model, it also add model to the tree view */ + create_model (listview, sel_format, plugin); + + g_signal_connect (listview, + "realize", + G_CALLBACK (scroll_to_selected), + NULL); + + gtk_widget_show (listview); +} + +static void +updated_custom_format_example (GtkEntry *format_entry, + GtkLabel *format_example) +{ + const gchar *format; + gchar *time; + gchar *str; + gchar *escaped_time; + + pluma_debug (DEBUG_PLUGINS); + + g_return_if_fail (GTK_IS_ENTRY (format_entry)); + g_return_if_fail (GTK_IS_LABEL (format_example)); + + format = gtk_entry_get_text (format_entry); + + time = get_time (format); + escaped_time = g_markup_escape_text (time, -1); + + str = g_strdup_printf ("%s", escaped_time); + + gtk_label_set_markup (format_example, str); + + g_free (escaped_time); + g_free (time); + g_free (str); +} + +static void +choose_format_dialog_button_toggled (GtkToggleButton *button, + ChooseFormatDialog *dialog) +{ + pluma_debug (DEBUG_PLUGINS); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) + { + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, TRUE); + gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); + + return; + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) + { + gtk_widget_set_sensitive (dialog->list, TRUE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + + return; + } +} + +static void +configure_dialog_button_toggled (GtkToggleButton *button, TimeConfigureDialog *dialog) +{ + pluma_debug (DEBUG_PLUGINS); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) + { + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, TRUE); + gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); + + return; + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) + { + gtk_widget_set_sensitive (dialog->list, TRUE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + + return; + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->prompt))) + { + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + + return; + } +} + +static gint +get_format_from_list (GtkWidget *listview) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + GtkTreeIter iter; + + pluma_debug (DEBUG_PLUGINS); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (listview)); + g_return_val_if_fail (model != NULL, 0); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (listview)); + g_return_val_if_fail (selection != NULL, 0); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) + { + gint selected_value; + + gtk_tree_model_get (model, &iter, COLUMN_INDEX, &selected_value, -1); + + pluma_debug_message (DEBUG_PLUGINS, "Sel value: %d", selected_value); + + return selected_value; + } + + g_return_val_if_reached (0); +} + +static TimeConfigureDialog * +get_configure_dialog (PlumaTimePlugin *plugin) +{ + TimeConfigureDialog *dialog = NULL; + gchar *data_dir; + gchar *ui_file; + GtkWidget *content; + GtkWidget *viewport; + PlumaTimePluginPromptType prompt_type; + gchar *sf, *cf; + GtkWidget *error_widget; + gboolean ret; + gchar *root_objects[] = { + "time_dialog_content", + NULL + }; + + pluma_debug (DEBUG_PLUGINS); + + dialog = g_new0 (TimeConfigureDialog, 1); + + dialog->dialog = gtk_dialog_new_with_buttons (_("Configure insert date/time plugin..."), + NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + GTK_STOCK_HELP, + GTK_RESPONSE_HELP, + NULL); + + /* HIG defaults */ + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog->dialog)), 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), + 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dialog->dialog))), + 5); + gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog->dialog))), 6); + + g_return_val_if_fail (dialog->dialog != NULL, NULL); + + data_dir = pluma_plugin_get_data_dir (PLUMA_PLUGIN (plugin)); + ui_file = g_build_filename (data_dir, "pluma-time-setup-dialog.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + root_objects, + &error_widget, + "time_dialog_content", &content, + "formats_viewport", &viewport, + "formats_tree", &dialog->list, + "always_prompt", &dialog->prompt, + "never_prompt", &dialog->use_list, + "use_custom", &dialog->custom, + "custom_entry", &dialog->custom_entry, + "custom_format_example", &dialog->custom_format_example, + NULL); + + g_free (data_dir); + g_free (ui_file); + + if (!ret) + { + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), + error_widget, + TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (error_widget), 5); + + gtk_widget_show (error_widget); + + return dialog; + } + + gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog->dialog), FALSE); + + sf = get_selected_format (plugin); + create_formats_list (dialog->list, sf, plugin); + g_free (sf); + + prompt_type = get_prompt_type (plugin); + + cf = get_custom_format (plugin); + gtk_entry_set_text (GTK_ENTRY(dialog->custom_entry), cf); + g_free (cf); + + if (prompt_type == USE_CUSTOM_FORMAT) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->custom), TRUE); + + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, TRUE); + gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); + } + else if (prompt_type == USE_SELECTED_FORMAT) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->use_list), TRUE); + + gtk_widget_set_sensitive (dialog->list, TRUE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + } + else + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->prompt), TRUE); + + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + } + + updated_custom_format_example (GTK_ENTRY (dialog->custom_entry), + GTK_LABEL (dialog->custom_format_example)); + + /* setup a window of a sane size. */ + gtk_widget_set_size_request (GTK_WIDGET (viewport), 10, 200); + + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), + content, FALSE, FALSE, 0); + g_object_unref (content); + gtk_container_set_border_width (GTK_CONTAINER (content), 5); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), + GTK_RESPONSE_OK); + + g_signal_connect (dialog->custom, + "toggled", + G_CALLBACK (configure_dialog_button_toggled), + dialog); + g_signal_connect (dialog->prompt, + "toggled", + G_CALLBACK (configure_dialog_button_toggled), + dialog); + g_signal_connect (dialog->use_list, + "toggled", + G_CALLBACK (configure_dialog_button_toggled), + dialog); + g_signal_connect (dialog->dialog, + "destroy", + G_CALLBACK (dialog_destroyed), + dialog); + g_signal_connect (dialog->custom_entry, + "changed", + G_CALLBACK (updated_custom_format_example), + dialog->custom_format_example); + + return dialog; +} + +static void +real_insert_time (GtkTextBuffer *buffer, + const gchar *the_time) +{ + pluma_debug_message (DEBUG_PLUGINS, "Insert: %s", the_time); + + gtk_text_buffer_begin_user_action (buffer); + + gtk_text_buffer_insert_at_cursor (buffer, the_time, -1); + gtk_text_buffer_insert_at_cursor (buffer, " ", -1); + + gtk_text_buffer_end_user_action (buffer); +} + +static void +choose_format_dialog_row_activated (GtkTreeView *list, + GtkTreePath *path, + GtkTreeViewColumn *column, + ChooseFormatDialog *dialog) +{ + gint sel_format; + gchar *the_time; + + sel_format = get_format_from_list (dialog->list); + the_time = get_time (formats[sel_format]); + + set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); + set_selected_format (dialog->plugin, formats[sel_format]); + + g_return_if_fail (the_time != NULL); + + real_insert_time (dialog->buffer, the_time); + + g_free (the_time); +} + +static ChooseFormatDialog * +get_choose_format_dialog (GtkWindow *parent, + PlumaTimePluginPromptType prompt_type, + PlumaTimePlugin *plugin) +{ + ChooseFormatDialog *dialog; + gchar *data_dir; + gchar *ui_file; + GtkWidget *error_widget; + gboolean ret; + gchar *sf, *cf; + GtkWindowGroup *wg = NULL; + + if (parent != NULL) + wg = gtk_window_get_group (parent); + + dialog = g_new0 (ChooseFormatDialog, 1); + + data_dir = pluma_plugin_get_data_dir (PLUMA_PLUGIN (plugin)); + ui_file = g_build_filename (data_dir, "pluma-time-dialog.ui", NULL); + ret = pluma_utils_get_ui_objects (ui_file, + NULL, + &error_widget, + "choose_format_dialog", &dialog->dialog, + "choice_list", &dialog->list, + "use_sel_format_radiobutton", &dialog->use_list, + "use_custom_radiobutton", &dialog->custom, + "custom_entry", &dialog->custom_entry, + "custom_format_example", &dialog->custom_format_example, + NULL); + + g_free (data_dir); + g_free (ui_file); + + if (!ret) + { + GtkWidget *err_dialog; + + err_dialog = gtk_dialog_new_with_buttons (NULL, + parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + + if (wg != NULL) + gtk_window_group_add_window (wg, GTK_WINDOW (err_dialog)); + + gtk_window_set_resizable (GTK_WINDOW (err_dialog), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (err_dialog), FALSE); + gtk_dialog_set_default_response (GTK_DIALOG (err_dialog), GTK_RESPONSE_OK); + + gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (err_dialog))), + error_widget); + + g_signal_connect (G_OBJECT (err_dialog), + "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + gtk_widget_show_all (err_dialog); + + return NULL; + } + + gtk_window_group_add_window (wg, + GTK_WINDOW (dialog->dialog)); + gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), parent); + gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); + + sf = get_selected_format (plugin); + create_formats_list (dialog->list, sf, plugin); + g_free (sf); + + cf = get_custom_format (plugin); + gtk_entry_set_text (GTK_ENTRY(dialog->custom_entry), cf); + g_free (cf); + + updated_custom_format_example (GTK_ENTRY (dialog->custom_entry), + GTK_LABEL (dialog->custom_format_example)); + + if (prompt_type == PROMPT_CUSTOM_FORMAT) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->custom), TRUE); + + gtk_widget_set_sensitive (dialog->list, FALSE); + gtk_widget_set_sensitive (dialog->custom_entry, TRUE); + gtk_widget_set_sensitive (dialog->custom_format_example, TRUE); + } + else if (prompt_type == PROMPT_SELECTED_FORMAT) + { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->use_list), TRUE); + + gtk_widget_set_sensitive (dialog->list, TRUE); + gtk_widget_set_sensitive (dialog->custom_entry, FALSE); + gtk_widget_set_sensitive (dialog->custom_format_example, FALSE); + } + else + { + g_return_val_if_reached (NULL); + } + + /* setup a window of a sane size. */ + gtk_widget_set_size_request (dialog->list, 10, 200); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog->dialog), + GTK_RESPONSE_OK); + + g_signal_connect (dialog->custom, + "toggled", + G_CALLBACK (choose_format_dialog_button_toggled), + dialog); + g_signal_connect (dialog->use_list, + "toggled", + G_CALLBACK (choose_format_dialog_button_toggled), + dialog); + g_signal_connect (dialog->dialog, + "destroy", + G_CALLBACK (dialog_destroyed), + dialog); + g_signal_connect (dialog->custom_entry, + "changed", + G_CALLBACK (updated_custom_format_example), + dialog->custom_format_example); + g_signal_connect (dialog->list, + "row_activated", + G_CALLBACK (choose_format_dialog_row_activated), + dialog); + + gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE); + + return dialog; +} + +static void +choose_format_dialog_response_cb (GtkWidget *widget, + gint response, + ChooseFormatDialog *dialog) +{ + switch (response) + { + case GTK_RESPONSE_HELP: + { + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_HELP"); + pluma_help_display (GTK_WINDOW (widget), + NULL, + "pluma-insert-date-time-plugin"); + break; + } + case GTK_RESPONSE_OK: + { + gchar *the_time; + + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); + + /* Get the user's chosen format */ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) + { + gint sel_format; + + sel_format = get_format_from_list (dialog->list); + the_time = get_time (formats[sel_format]); + + set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); + set_selected_format (dialog->plugin, formats[sel_format]); + } + else + { + const gchar *format; + + format = gtk_entry_get_text (GTK_ENTRY (dialog->custom_entry)); + the_time = get_time (format); + + set_prompt_type (dialog->plugin, PROMPT_CUSTOM_FORMAT); + set_custom_format (dialog->plugin, format); + } + + g_return_if_fail (the_time != NULL); + + real_insert_time (dialog->buffer, the_time); + g_free (the_time); + + gtk_widget_destroy (dialog->dialog); + break; + } + case GTK_RESPONSE_CANCEL: + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CANCEL"); + gtk_widget_destroy (dialog->dialog); + } +} + +static void +time_cb (GtkAction *action, + ActionData *data) +{ + GtkTextBuffer *buffer; + gchar *the_time = NULL; + PlumaTimePluginPromptType prompt_type; + + pluma_debug (DEBUG_PLUGINS); + + buffer = GTK_TEXT_BUFFER (pluma_window_get_active_document (data->window)); + g_return_if_fail (buffer != NULL); + + prompt_type = get_prompt_type (data->plugin); + + if (prompt_type == USE_CUSTOM_FORMAT) + { + gchar *cf = get_custom_format (data->plugin); + the_time = get_time (cf); + g_free (cf); + } + else if (prompt_type == USE_SELECTED_FORMAT) + { + gchar *sf = get_selected_format (data->plugin); + the_time = get_time (sf); + g_free (sf); + } + else + { + ChooseFormatDialog *dialog; + + dialog = get_choose_format_dialog (GTK_WINDOW (data->window), + prompt_type, + data->plugin); + if (dialog != NULL) + { + dialog->buffer = buffer; + dialog->plugin = data->plugin; + + g_signal_connect (dialog->dialog, + "response", + G_CALLBACK (choose_format_dialog_response_cb), + dialog); + + gtk_widget_show (GTK_WIDGET (dialog->dialog)); + } + + return; + } + + g_return_if_fail (the_time != NULL); + + real_insert_time (buffer, the_time); + + g_free (the_time); +} + +static void +ok_button_pressed (TimeConfigureDialog *dialog) +{ + gint sel_format; + const gchar *custom_format; + + pluma_debug (DEBUG_PLUGINS); + + sel_format = get_format_from_list (dialog->list); + + custom_format = gtk_entry_get_text (GTK_ENTRY (dialog->custom_entry)); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->custom))) + { + set_prompt_type (dialog->plugin, USE_CUSTOM_FORMAT); + set_custom_format (dialog->plugin, custom_format); + } + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->use_list))) + { + set_prompt_type (dialog->plugin, USE_SELECTED_FORMAT); + set_selected_format (dialog->plugin, formats [sel_format]); + } + else + { + /* Default to prompt the user with the list selected */ + set_prompt_type (dialog->plugin, PROMPT_SELECTED_FORMAT); + } + + pluma_debug_message (DEBUG_PLUGINS, "Sel: %d", sel_format); +} + +static void +configure_dialog_response_cb (GtkWidget *widget, + gint response, + TimeConfigureDialog *dialog) +{ + switch (response) + { + case GTK_RESPONSE_HELP: + { + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_HELP"); + + pluma_help_display (GTK_WINDOW (dialog), + NULL, + "pluma-date-time-configure"); + break; + } + case GTK_RESPONSE_OK: + { + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_OK"); + + ok_button_pressed (dialog); + + gtk_widget_destroy (dialog->dialog); + break; + } + case GTK_RESPONSE_CANCEL: + { + pluma_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_CANCEL"); + gtk_widget_destroy (dialog->dialog); + } + } +} + +static GtkWidget * +impl_create_configure_dialog (PlumaPlugin *plugin) +{ + TimeConfigureDialog *dialog; + + dialog = get_configure_dialog (PLUMA_TIME_PLUGIN (plugin)); + + dialog->plugin = PLUMA_TIME_PLUGIN (plugin); + + g_signal_connect (dialog->dialog, + "response", + G_CALLBACK (configure_dialog_response_cb), + dialog); + + return GTK_WIDGET (dialog->dialog); +} + +static void +pluma_time_plugin_class_init (PlumaTimePluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PlumaPluginClass *plugin_class = PLUMA_PLUGIN_CLASS (klass); + + object_class->finalize = pluma_time_plugin_finalize; + + plugin_class->activate = impl_activate; + plugin_class->deactivate = impl_deactivate; + plugin_class->update_ui = impl_update_ui; + + plugin_class->create_configure_dialog = impl_create_configure_dialog; + + g_type_class_add_private (object_class, sizeof (PlumaTimePluginPrivate)); +} diff --git a/plugins/time/pluma-time-plugin.h b/plugins/time/pluma-time-plugin.h new file mode 100755 index 00000000..e7b66909 --- /dev/null +++ b/plugins/time/pluma-time-plugin.h @@ -0,0 +1,78 @@ +/* + * pluma-time-plugin.h + * + * Copyright (C) 2002-2005 - Paolo Maggi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#ifndef __PLUMA_TIME_PLUGIN_H__ +#define __PLUMA_TIME_PLUGIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_TIME_PLUGIN (pluma_time_plugin_get_type ()) +#define PLUMA_TIME_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PLUMA_TYPE_TIME_PLUGIN, PlumaTimePlugin)) +#define PLUMA_TIME_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PLUMA_TYPE_TIME_PLUGIN, PlumaTimePluginClass)) +#define PLUMA_IS_TIME_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PLUMA_TYPE_TIME_PLUGIN)) +#define PLUMA_IS_TIME_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PLUMA_TYPE_TIME_PLUGIN)) +#define PLUMA_TIME_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PLUMA_TYPE_TIME_PLUGIN, PlumaTimePluginClass)) + +/* Private structure type */ +typedef struct _PlumaTimePluginPrivate PlumaTimePluginPrivate; + +/* + * Main object structure + */ +typedef struct _PlumaTimePlugin PlumaTimePlugin; + +struct _PlumaTimePlugin +{ + PlumaPlugin parent_instance; + + /*< private >*/ + PlumaTimePluginPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _PlumaTimePluginClass PlumaTimePluginClass; + +struct _PlumaTimePluginClass +{ + PlumaPluginClass parent_class; +}; + +/* + * Public methods + */ +GType pluma_time_plugin_get_type (void) G_GNUC_CONST; + +/* All the plugins must implement this function */ +G_MODULE_EXPORT GType register_pluma_plugin (GTypeModule *module); + +G_END_DECLS + +#endif /* __PLUMA_TIME_PLUGIN_H__ */ diff --git a/plugins/time/pluma-time-setup-dialog.ui b/plugins/time/pluma-time-setup-dialog.ui new file mode 100755 index 00000000..46fb5b9d --- /dev/null +++ b/plugins/time/pluma-time-setup-dialog.ui @@ -0,0 +1,330 @@ + + + + + + Configure date/time plugin + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + False + + + True + False + 8 + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + + + + + 0 + False + True + GTK_PACK_END + + + + + 10 + True + False + 6 + + + True + When inserting date/time... + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + + + + + + 0 + False + False + + + + + True + False + 0 + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + True + False + 6 + + + True + True + _Prompt for a format + True + GTK_RELIEF_NORMAL + False + False + True + + + 0 + True + True + + + + + True + False + 6 + + + True + True + Use the _selected format + True + GTK_RELIEF_NORMAL + False + False + True + always_prompt + + + 0 + True + True + + + + + True + False + 0 + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + True + False + False + False + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + True + False + 2 + + + True + False + 12 + + + True + True + _Use custom format + True + GTK_RELIEF_NORMAL + False + False + True + always_prompt + + + 0 + False + False + + + + + True + True + True + True + 0 + %d/%m/%Y %H:%M:%S + True + False + + + 0 + True + True + + + + + 2 + True + True + + + + + True + 01/11/2009 17:52:00 + False + GTK_JUSTIFY_RIGHT + False + False + 1 + 0.5 + 0 + 0 + + + + + + 0 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + + button1 + button3 + button4 + + + diff --git a/plugins/time/time.gedit-plugin.desktop.in b/plugins/time/time.gedit-plugin.desktop.in deleted file mode 100755 index ba06854a..00000000 --- a/plugins/time/time.gedit-plugin.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Gedit Plugin] -Module=time -IAge=2 -_Name=Insert Date/Time -_Description=Inserts current date and time at the cursor position. -Authors=Paolo Maggi ;Lee Mallabone -Copyright=Copyright © 2002-2005 Paolo Maggi -Website=http://www.gedit.org diff --git a/plugins/time/time.pluma-plugin.desktop.in b/plugins/time/time.pluma-plugin.desktop.in new file mode 100755 index 00000000..a6dbc791 --- /dev/null +++ b/plugins/time/time.pluma-plugin.desktop.in @@ -0,0 +1,8 @@ +[Pluma Plugin] +Module=time +IAge=2 +_Name=Insert Date/Time +_Description=Inserts current date and time at the cursor position. +Authors=Paolo Maggi ;Lee Mallabone +Copyright=Copyright © 2002-2005 Paolo Maggi +Website=http://www.pluma.org -- cgit v1.2.1