diff --git a/Makefile.am b/Makefile.am index 2d8c87d51..1baff0ebf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -172,6 +172,10 @@ if ENABLE_WEBHELPER SUBDIRS += webhelper endif +if ENABLE_WORKBENCH +SUBDIRS += workbench +endif + if ENABLE_XMLSNIPPETS SUBDIRS += xmlsnippets endif diff --git a/build/workbench.m4 b/build/workbench.m4 new file mode 100644 index 000000000..2e883a9b1 --- /dev/null +++ b/build/workbench.m4 @@ -0,0 +1,15 @@ +AC_DEFUN([GP_CHECK_WORKBENCH], +[ + GP_ARG_DISABLE([Workbench], [auto]) + GP_COMMIT_PLUGIN_STATUS([Workbench]) + AC_CONFIG_FILES([ + workbench/Makefile + workbench/src/Makefile + workbench/icons/Makefile + workbench/icons/16x16/Makefile + workbench/icons/24x24/Makefile + workbench/icons/32x32/Makefile + workbench/icons/48x48/Makefile + workbench/icons/scalable/Makefile + ]) +]) diff --git a/configure.ac b/configure.ac index f03726dcc..48c693250 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,7 @@ GP_CHECK_TREEBROWSER GP_CHECK_TABLECONVERT GP_CHECK_UPDATECHECKER GP_CHECK_WEBHELPER +GP_CHECK_WORKBENCH GP_CHECK_XMLSNIPPETS AC_CONFIG_FILES([ diff --git a/po/POTFILES.in b/po/POTFILES.in index 05ed01d2a..e281d86b1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -312,6 +312,17 @@ webhelper/src/gwh-utils.c webhelper/src/gwh-browser.c webhelper/src/gwh-plugin.c +# workbench +workbench/src/dialogs.c +workbench/src/menu.c +workbench/src/plugin_main.c +workbench/src/popup_menu.c +workbench/src/sidebar.c +workbench/src/utils.c +workbench/src/wb_globals.c +workbench/src/wb_project.c +workbench/src/workbench.c + # XMLSnippets xmlsnippets/src/plugin.c xmlsnippets/src/xmlsnippets.c diff --git a/po/be.po b/po/be.po index 5c0a4a503..681d893f2 100644 --- a/po/be.po +++ b/po/be.po @@ -3405,7 +3405,7 @@ msgstr "" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5564,7 +5564,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5623,31 +5623,31 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5704,70 +5704,70 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Знайсьці і праэкце" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/ca.po b/po/ca.po index 3dc78382b..a883dbb67 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3344,7 +3344,7 @@ msgstr "Cancel·la la la Selecció" msgid "Toggle Insert/Overwrite mode" msgstr "Commuta entre el mode d'Inserció i el mode de Sobreescriptura" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tabulador" @@ -5517,7 +5517,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5576,31 +5576,31 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Sagnat" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Espai" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Salt de línia" @@ -5655,74 +5655,74 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Patrons de fitxers de codi font:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Patrons de fitxers de capçalera:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 #, fuzzy msgid "Ignored file patterns:" msgstr "Patrons de fitxers de codi font:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 #, fuzzy msgid "Ignored directory patterns:" msgstr "Patrons de fitxers de capçalera:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Cerca en els fitxers del projecte" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 #, fuzzy msgid "Yes" msgstr "sí" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "No." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/da.po b/po/da.po index 5c7976447..b55a22816 100644 --- a/po/da.po +++ b/po/da.po @@ -3361,7 +3361,7 @@ msgstr "" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5490,7 +5490,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5549,31 +5549,31 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5623,69 +5623,69 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/de.po b/po/de.po index faa20d376..85723dba6 100644 --- a/po/de.po +++ b/po/de.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: Geany-Plugins 1.30\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-24 16:57+0200\n" +"POT-Creation-Date: 2017-08-20 13:13+0200\n" "PO-Revision-Date: 2016-08-08 22:38+0200\n" "Last-Translator: Dominic Hopf \n" "Language-Team: German \n" @@ -3828,7 +3828,10 @@ msgstr "_OK" #: ../geanymacro/src/geanymacro.c:1394 ../geanymacro/src/geanymacro.c:1537 #: ../geanymacro/src/geanymacro.c:1827 -#: ../projectorganizer/src/prjorg-sidebar.c:306 +#: ../projectorganizer/src/prjorg-sidebar.c:306 ../workbench/src/dialogs.c:45 +#: ../workbench/src/dialogs.c:76 ../workbench/src/dialogs.c:115 +#: ../workbench/src/dialogs.c:152 ../workbench/src/dialogs.c:221 +#: ../workbench/src/dialogs.c:350 msgid "_Cancel" msgstr "_Abbrechen" @@ -4523,7 +4526,7 @@ msgstr "Projekteigenschaften" msgid "New Project" msgstr "Neues Projekt" -#: ../geanyprj/src/menu.c:110 +#: ../geanyprj/src/menu.c:110 ../workbench/src/dialogs.c:46 msgid "C_reate" msgstr "_Erstellen" @@ -5425,7 +5428,8 @@ msgstr "Datei als HTML speichern" msgid "HTML Files" msgstr "HTML-Dateien" -#: ../markdown/src/plugin.c:311 +#: ../markdown/src/plugin.c:311 ../workbench/src/dialogs.c:84 +#: ../workbench/src/dialogs.c:123 msgid "All Files" msgstr "Alle Dateien" @@ -6034,7 +6038,7 @@ msgstr "" "identifizieren. Wird hauptsächlich für das Umschalten zwischen Quellen und " "Header verwendet." -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:597 ../workbench/src/dialogs.c:243 msgid "Ignored file patterns:" msgstr "Muster für zu ignorierende Dateien:" @@ -6047,7 +6051,7 @@ msgstr "" "erkennen, die nicht im projektspezifischen Dateibaum angezeigt werden " "sollen. " -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:609 ../workbench/src/dialogs.c:254 msgid "Ignored directory patterns:" msgstr "Muster für zu ignorierende Verzeichnisse:" @@ -6146,6 +6150,7 @@ msgid "Add external directory" msgstr "Externes Verzeichnis hinzufügen" #: ../projectorganizer/src/prjorg-sidebar.c:1374 +#: ../workbench/src/popup_menu.c:435 msgid "Expand all" msgstr "Alle ausklappen" @@ -7977,6 +7982,326 @@ msgstr "Browser" msgid "Windows" msgstr "Fenster" +#: ../workbench/src/dialogs.c:43 +#, fuzzy +msgid "Create new workbench" +msgstr "Neue Werkbank anlegen" + +#: ../workbench/src/dialogs.c:74 +#, fuzzy +msgid "Open workbench" +msgstr "Öffne Werkbank" + +#. Create new menu item "Open Workbench" +#: ../workbench/src/dialogs.c:77 ../workbench/src/menu.c:188 +#, fuzzy +msgid "_Open" +msgstr "Öffnen" + +#: ../workbench/src/dialogs.c:80 +msgid "Workbench files (.geanywb)" +msgstr "Werkbank Dateien (.geanywb)" + +#: ../workbench/src/dialogs.c:113 ../workbench/src/popup_menu.c:373 +#, fuzzy +msgid "Add project" +msgstr "Projekt hinzufügen" + +#: ../workbench/src/dialogs.c:116 ../workbench/src/dialogs.c:153 +#, fuzzy +msgid "_Add" +msgstr "_Beides hinzufügen" + +#: ../workbench/src/dialogs.c:119 +#, fuzzy +msgid "Project files (.geany)" +msgstr "Projektdateien (.geany)" + +#: ../workbench/src/dialogs.c:150 ../workbench/src/popup_menu.c:401 +#, fuzzy +msgid "Add directory" +msgstr "Verzeichnis hinzufügen" + +#: ../workbench/src/dialogs.c:218 ../workbench/src/popup_menu.c:419 +#, fuzzy +msgid "Directory settings" +msgstr "Verzeichnis Einstellungen" + +#: ../workbench/src/dialogs.c:222 ../workbench/src/dialogs.c:351 +#, fuzzy +msgid "_OK" +msgstr "OK" + +#: ../workbench/src/dialogs.c:232 +#, fuzzy +msgid "File patterns:" +msgstr "Dateimuster:" + +#: ../workbench/src/dialogs.c:238 +#, fuzzy +msgid "" +"Space separated list of patterns that are used to identify files that shall " +"be displayed in the directory tree." +msgstr "" +"Leerzeichengetrennte Liste mit Mustern, die genutzt werden, um Dateien zu " +"erkennen, die im Verzeichnisbaum angezeigt werden sollen." + +#: ../workbench/src/dialogs.c:249 +#, fuzzy +msgid "" +"Space separated list of patterns that are used to identify files that shall " +"not be displayed in the directory tree." +msgstr "" +"Leerzeichengetrennte Liste mit Mustern, die genutzt werden, um Dateien zu " +"erkennen, die im Verzeichnisbaum nicht angezeigt werden sollen." + +#: ../workbench/src/dialogs.c:260 +#, fuzzy +msgid "" +"Space separated list of patterns that are used to identify directories that " +"shall not be scanned for source files." +msgstr "" +"Leerzeichengetrennte Liste mit Mustern, die genutzt werden, um Verzeichnisse " +"zu erkennen, die nicht nach Quelldateien durchsucht werden sollen. " + +#: ../workbench/src/dialogs.c:268 +msgid "" +"Note: the patterns above affect only the workbench directory and are not " +"used in the Find in Files\n" +"dialog." +msgstr "" +"Anmerkung: die Muser oben beeinflußen nur das Werkbank-Verzeichnis und " +"werden nicht in In Dateien suchen verwendet." + +#: ../workbench/src/dialogs.c:347 +msgid "Workbench settings" +msgstr "Werkbank Einstellungen" + +#: ../workbench/src/dialogs.c:361 +#, fuzzy +msgid "Rescan all projects on open:" +msgstr "Beim Öffnen alle Projekte durchsuchen:" + +#: ../workbench/src/dialogs.c:366 +msgid "" +"If the option is activated (default), then all projects will be re-scanned " +"on opening of the workbench." +msgstr "" +"Wenn die Option aktiviert ist (Standard), dann werden beim Öffnen einer " +"Werkbank alle Projekte durchsucht." + +#: ../workbench/src/menu.c:95 +#, fuzzy, c-format +msgid "Could not create new workbench file: %s" +msgstr "Konnte die Werkbank Datei nicht anlegen: %s" + +#: ../workbench/src/menu.c:122 +#, fuzzy, c-format +msgid "Could not open workbench file: %s" +msgstr "Konnte die Werkbank Datei nicht öffnen: %s" + +#: ../workbench/src/menu.c:139 +#, fuzzy, c-format +msgid "Could not save workbench file: %s" +msgstr "Konnte die Werkbank Datei nicht speichern: %s" + +#. Set metadata +#: ../workbench/src/menu.c:177 ../workbench/src/plugin_main.c:129 +#: ../workbench/src/sidebar.c:992 +msgid "Workbench" +msgstr "Werkbank" + +#. Create new menu item "New Workbench" +#: ../workbench/src/menu.c:181 +msgid "_New" +msgstr "" + +#. Create new menu item "Save Workbench" +#: ../workbench/src/menu.c:195 +#, fuzzy +msgid "_Save" +msgstr "Datei speichern" + +#. Create new menu item "Workbench Settings" +#: ../workbench/src/menu.c:202 +#, fuzzy +msgid "S_ettings" +msgstr "Einstellungen" + +#. Create new menu item "Close Workbench" +#: ../workbench/src/menu.c:209 +#, fuzzy +msgid "_Close" +msgstr "Schließen" + +#: ../workbench/src/plugin_main.c:93 ../workbench/src/sidebar.c:564 +msgid "" +"Create or open a workbench\n" +"using the workbench menu." +msgstr "" +"Erstellen oder Öffen Sie eine Werkbank\n" +"mit dem Werkbank Menü." + +#: ../workbench/src/plugin_main.c:130 +msgid "Manage and customize multiple projects." +msgstr "Verwalten und anpassen mehrere Projekte." + +#: ../workbench/src/popup_menu.c:171 +#, fuzzy, c-format +msgid "Could not add project file: %s" +msgstr "Konnte die Projektdatei nicht hinzufügen: %s" + +#: ../workbench/src/popup_menu.c:379 +#, fuzzy +msgid "Save project" +msgstr "Projekt speichern" + +#: ../workbench/src/popup_menu.c:385 +#, fuzzy +msgid "Remove project" +msgstr "Projekt entfernen" + +#: ../workbench/src/popup_menu.c:391 +#, fuzzy +msgid "Fold/unfold project" +msgstr "Projekt falten/ausklappen" + +#: ../workbench/src/popup_menu.c:407 +#, fuzzy +msgid "Remove directory" +msgstr "Verzeichnis entfernen" + +#: ../workbench/src/popup_menu.c:413 +#, fuzzy +msgid "Rescan directory" +msgstr "Verzeichnis durchsuchen" + +#: ../workbench/src/popup_menu.c:425 +#, fuzzy +msgid "Fold/unfold directory" +msgstr "Verzeichnis falten/ausklappen" + +#: ../workbench/src/popup_menu.c:441 +#, fuzzy +msgid "Collapse all" +msgstr "Alle e_inklappen" + +#: ../workbench/src/popup_menu.c:451 +msgid "Add to Workbench Bookmarks" +msgstr "Zu Werkbank Lesezeichen hinzufügen" + +#: ../workbench/src/popup_menu.c:457 +msgid "Add to Project Bookmarks" +msgstr "Zu Projekt Lesezeichen hinzufügen" + +#: ../workbench/src/popup_menu.c:463 +#, fuzzy +msgid "Remove from Bookmarks" +msgstr "Von _Lesezeichen entfernen" + +#: ../workbench/src/sidebar.c:300 +#, fuzzy +msgid "No directories" +msgstr "Keine Verzeichnisse" + +#. *** label *** +#: ../workbench/src/sidebar.c:562 ../workbench/src/sidebar.c:943 +msgid "No workbench opened." +msgstr "Keine Werkbank geöffnet." + +#: ../workbench/src/sidebar.c:574 +#, fuzzy +msgid "Projects" +msgstr "Projekte" + +#: ../workbench/src/sidebar.c:584 +msgid "" +"Add a project\n" +"using the context menu." +msgstr "" +"Fügen Sie ein Projekt\n" +"über das Kontextmenü hinzu." + +#: ../workbench/src/sidebar.c:696 +#, c-format +msgid "" +"%s\n" +"Project file not found!" +msgstr "" +"%s\n" +"Projekt Datei nicht gefunden!" + +#: ../workbench/src/sidebar.c:710 +msgid "" +"This project has no directories. Directories can be added to a project using " +"the context menu." +msgstr "" +"Dieses Projekt hat keine Verzeichnisse. Verzeichnisse können über " +"dasKontextmenü zum Projekt hinzugefügt werden." + +#: ../workbench/src/wb_project.c:997 +#, fuzzy, c-format +msgid "Directory-Name: %s\n" +msgstr "Verzeichnis-Name: %s\n" + +#: ../workbench/src/wb_project.c:998 +#, fuzzy, c-format +msgid "Base-Directory: %s\n" +msgstr "Basis-Verzeichnis: %s\n" + +#: ../workbench/src/wb_project.c:1000 +#, fuzzy +msgid "File Patterns:" +msgstr "Datei Muster:" + +#: ../workbench/src/wb_project.c:1012 +#, fuzzy +msgid "Ignored Dir. Patterns:" +msgstr "Muster für zu ignorierende Dateien:" + +#: ../workbench/src/wb_project.c:1024 +#, fuzzy +msgid "Ignored File Patterns:" +msgstr "Muster für zu ignorierende Dateien:" + +#: ../workbench/src/wb_project.c:1036 +#, c-format +msgid "Number of Sub-Folders: %u\n" +msgstr "Anzahl der Unter-Verzeichnisse: %u\n" + +#: ../workbench/src/wb_project.c:1037 +#, fuzzy, c-format +msgid "Number of Files: %u\n" +msgstr "Anzahl von Dateien: %u\n" + +#: ../workbench/src/wb_project.c:1061 +#, fuzzy, c-format +msgid "Project: %s\n" +msgstr "Projekt: %s\n" + +#: ../workbench/src/wb_project.c:1062 +#, fuzzy, c-format +msgid "File: %s\n" +msgstr "Datei: %s\n" + +#: ../workbench/src/wb_project.c:1063 +#, fuzzy, c-format +msgid "Number of Directories: %u\n" +msgstr "Anzahl der Verzeichnisse: %u\n" + +#: ../workbench/src/wb_project.c:1066 +msgid "" +"\n" +"The project contains unsafed changes!\n" +msgstr "" +"\n" +"Das Projekt enthält nicht gesicherte Änderungen!\n" + +#: ../workbench/src/workbench.c:710 +#, fuzzy, c-format +msgid "File %s is not a valid workbench file!" +msgstr "Die Datei %s ist keine gültige Workbench-Datei!" + #: ../xmlsnippets/src/plugin.c:44 msgid "XML Snippets" msgstr "XML-Schnipsel" @@ -7985,6 +8310,14 @@ msgstr "XML-Schnipsel" msgid "Autocompletes XML/HTML tags using snippets." msgstr "Autovervollständigt XML/HTML-Tags unter Verwendung von Schnipseln." +#, fuzzy +#~ msgid "Create" +#~ msgstr "_Erstellen" + +#, fuzzy +#~ msgid "New" +#~ msgstr "Neu" + #~ msgid "Call documentation viewer on current symbol." #~ msgstr "Dokumentation für das aktuelle Wort anzeigen." @@ -8072,9 +8405,6 @@ msgstr "Autovervollständigt XML/HTML-Tags unter Verwendung von Schnipseln." #~ msgid "Find Project Tag..." #~ msgstr "Tag im Projekt finden..." -#~ msgid "Find project tag" -#~ msgstr "Tag im Projekt finden" - #~ msgid "Generate tags for all project files:" #~ msgstr "Tags für alle Projektdateien erstellen" diff --git a/po/es.po b/po/es.po index 029cb9a49..4369bd318 100644 --- a/po/es.po +++ b/po/es.po @@ -3502,7 +3502,7 @@ msgstr "Cancelar selección" msgid "Toggle Insert/Overwrite mode" msgstr "Intercambiar modo inserción/sobrescritura" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tab" @@ -5830,7 +5830,7 @@ msgstr "" "No se pudo encontrar el widget «%s» en la definición de UI, compruebe su " "instalación." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "PrettyPrinter XML" @@ -5896,31 +5896,31 @@ msgstr "Nodos de texto" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "Nodos vacíos" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Concatenación ( a )" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Espaciado ( a )" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Expansión ( a )" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Sangría" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Espacio" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Cambio de línea" @@ -5972,11 +5972,11 @@ msgstr "Intercambiar cabecera/fuente" msgid "Open Selected File (Project Organizer)" msgstr "Abrir archivo seleccionado (organizador de proyectos)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Patrones de código:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." @@ -5984,11 +5984,11 @@ msgstr "" "Lista de patrones separados por espacios utilizados para identificar " "archivos de código. Usado para el intercambio entre cabeceras y código." -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Patrones de cabecera:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." @@ -5996,11 +5996,11 @@ msgstr "" "Lista de patrones separados por espacios, usados para identificar archivos " "de cabeceras. Usado para el intercambio entre cabeceras y código." -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "Patrones de directorios ignorados:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." @@ -6008,11 +6008,11 @@ msgstr "" "Lista de patrones separados por espacios, usados para identificar archivos " "que no se mostrarán en el árbol de proyectos." -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "Patrones de directorios ignorados:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -6020,23 +6020,23 @@ msgstr "" "Lista de patrones separados por espacios, usados para identificar " "directorios en los que no se buscarán archivos de código fuente." -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "Indexar todos los archivos del proyecto:" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "Auto (indexar si hay menos de 300 archivos)" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "Sí" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "No" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." @@ -6045,7 +6045,7 @@ msgstr "" "solo para los archivos abiertos actualmente. Podría resultar lento para " "proyectos grandes." -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" @@ -7360,6 +7360,7 @@ msgid "TreeBrowser" msgstr "Visor de árbol" #: ../treebrowser/src/treebrowser.c:128 +#, fuzzy msgid "" "This plugin adds a tree browser to Geany, allowing the user to browse files " "using a tree view of the directory being browsed.\n" diff --git a/po/fr.po b/po/fr.po index 40c6d890d..78ab8e2c3 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3487,7 +3487,7 @@ msgstr "Annuler la sélection" msgid "Toggle Insert/Overwrite mode" msgstr "Basculer le mode d'insertion/écrasement" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tab" @@ -5822,7 +5822,7 @@ msgstr "" "Impossible de trouver le widget « %s » dans la définition d'interface, " "veuillez vérifier votre installation." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5881,31 +5881,31 @@ msgstr "Nœuds texte" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "Nœuds vides" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Concaténation ( to )" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Espace ( to )" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Expansion ( to )" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Indentation" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Espace" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Retour à la ligne" @@ -5957,11 +5957,11 @@ msgstr "Basculer à l'en-tête/la source" msgid "Open Selected File (Project Organizer)" msgstr "Ouvrir le fichier sélectionné (Organisateur de projet)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Motifs de sources :" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." @@ -5969,11 +5969,11 @@ msgstr "" "Une liste séparée par des espaces de motifs utilisés pour identifier les " "fichiers source. Utilisée pour basculer entre l'en-tête et la source." -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Motifs d'en-têtes :" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." @@ -5981,11 +5981,11 @@ msgstr "" "Une liste séparée par des espaces de motifs utilisés pour identifier les " "fichiers d'en-tête. Utilisée pour basculer entre l'en-tête et la source." -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "Motifs de dossiers ignorés :" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." @@ -5993,11 +5993,11 @@ msgstr "" "Une liste séparée par des espaces de motifs utilisés pour identifier les " "fichiers à ne pas afficher dans l'arborescence du projet." -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "Motifs de dossiers ignorés :" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -6005,23 +6005,23 @@ msgstr "" "Une liste séparée par des espaces de motifs utilisés pour identifier les " "dossiers à ignorer." -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "Indexer tous les fichiers du projet :" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "Automatique (indexer s'il y a moins de 300 fichiers)" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "Oui" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "Non" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." @@ -6029,7 +6029,7 @@ msgstr "" "Génère la liste des symboles pour tous les fichiers du projet et non " "uniquement ceux ouverts. Peut être lent avec de gros projets." -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/gl.po b/po/gl.po index 7301381d0..89f88fc94 100644 --- a/po/gl.po +++ b/po/gl.po @@ -3530,7 +3530,7 @@ msgstr "Selección extra" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5770,7 +5770,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5831,33 +5831,33 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 #, fuzzy msgid "Empty nodes" msgstr "(Liña baleira)" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 #, fuzzy msgid "Indentation" msgstr "Presentación" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5914,74 +5914,74 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 #, fuzzy msgid "Header patterns:" msgstr "Extensións de cabeceiras" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 #, fuzzy msgid "Ignored file patterns:" msgstr "Extensións de cabeceiras" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 #, fuzzy msgid "Ignored directory patterns:" msgstr "Extensións de cabeceiras" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Procurar en todo o proxecto " -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "Núm." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/it.po b/po/it.po index 7ea9d7da6..71f1889ab 100644 --- a/po/it.po +++ b/po/it.po @@ -3465,7 +3465,7 @@ msgstr "Elimina selezione" msgid "Toggle Insert/Overwrite mode" msgstr "Attiva/Disattiva modalità sovrascrivi" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tab" @@ -5774,7 +5774,7 @@ msgstr "" "Impossibile trovare il widge t\"%s\" nella definizione delle UI, si prega di " "controllare l'installazione." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "XML PrettyPrinter" @@ -5837,31 +5837,31 @@ msgstr "Nodi di testo" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "Nodi vuoti" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Concatenazione (da a )" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Spaziatura (da a )" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Espansione (da a )" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Indentazione" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Spazio" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Interruzione di riga" @@ -5917,11 +5917,11 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "Open file selezionato (gproject)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Patterns sorgente:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 #, fuzzy msgid "" "Space separated list of patterns that are used to identify source files. " @@ -5930,11 +5930,11 @@ msgstr "" "Lista separata da spazi dei patterns che saranno usati per identificare i " "file intestazione. Usato principalmente per scambiare intestazione/sorgente" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Intestazione patterns:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 #, fuzzy msgid "" "Space separated list of patterns that are used to identify headers. Used for " @@ -5943,12 +5943,12 @@ msgstr "" "Lista separata da spazi dei patterns che saranno usati per identificare i " "file intestazione. Usato principalmente per scambiare intestazione/sorgente" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 #, fuzzy msgid "Ignored file patterns:" msgstr "Ignora patters directory:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 #, fuzzy msgid "" "Space separated list of patterns that are used to identify files that are " @@ -5957,12 +5957,12 @@ msgstr "" "Lista separata da spazi dei patterns che saranno usati per identificare le " "directory che non saranno scansione per file sorgenti." -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 #, fuzzy msgid "Ignored directory patterns:" msgstr "Ignora patters directory:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -5970,26 +5970,26 @@ msgstr "" "Lista separata da spazi dei patterns che saranno usati per identificare le " "directory che non saranno scansione per file sorgenti." -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Cerca nei file del progetto" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 #, fuzzy msgid "Yes" msgstr "sì" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "N°" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 #, fuzzy msgid "" "Generate symbol list for all project files instead of only for the currently " @@ -5999,7 +5999,7 @@ msgstr "" "correttamente aperti. Troppo lento per grandi progetti (>1000 files) e " "dovrebbe essere disabilitato in questo caso." -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/ja.po b/po/ja.po index 968b3e175..e7481f4ee 100644 --- a/po/ja.po +++ b/po/ja.po @@ -3430,7 +3430,7 @@ msgstr "選択を解除" msgid "Toggle Insert/Overwrite mode" msgstr "挿入/上書きモードを切替" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "タブ" @@ -5688,7 +5688,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "XML整形" @@ -5750,31 +5750,31 @@ msgstr "文字ノード" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "空ノード" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "結合 (にする)" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "空白を開ける (にする)" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "展開 (にする)" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "インデント" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "空白" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "改行" @@ -5830,11 +5830,11 @@ msgstr "ヘッダ/ソースを交換" msgid "Open Selected File (Project Organizer)" msgstr "選択したファイルを開く(gproject)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "ソースのフィルタ:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 #, fuzzy msgid "" "Space separated list of patterns that are used to identify source files. " @@ -5843,11 +5843,11 @@ msgstr "" "空白で区切られたヘッダファイルとして使用するファイルパターンのリストヘッダ。" "ソースの交換に使用します。" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "ヘッダのフィルタ:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 #, fuzzy msgid "" "Space separated list of patterns that are used to identify headers. Used for " @@ -5856,12 +5856,12 @@ msgstr "" "空白で区切られたヘッダファイルとして使用するファイルパターンのリストヘッダ。" "ソースの交換に使用します。" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 #, fuzzy msgid "Ignored file patterns:" msgstr "無視するディレクトリ:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 #, fuzzy msgid "" "Space separated list of patterns that are used to identify files that are " @@ -5870,12 +5870,12 @@ msgstr "" "空白で区切られたソースファイル検索の対象から外すディレクトリのパターンのリス" "ト" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 #, fuzzy msgid "Ignored directory patterns:" msgstr "無視するディレクトリ:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -5883,26 +5883,26 @@ msgstr "" "空白で区切られたソースファイル検索の対象から外すディレクトリのパターンのリス" "ト" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "プロジェクトファイルを検索" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 #, fuzzy msgid "Yes" msgstr "はい" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "番号" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 #, fuzzy msgid "" "Generate symbol list for all project files instead of only for the currently " @@ -5912,7 +5912,7 @@ msgstr "" "トを生成します。大きなプロジェクト(1000ファイル以上)ではとても遅いので、使用" "しないでください。" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/kk.po b/po/kk.po index 008df96e2..27a20cbf5 100644 --- a/po/kk.po +++ b/po/kk.po @@ -3327,7 +3327,7 @@ msgstr "" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tab" @@ -5452,7 +5452,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5511,31 +5511,31 @@ msgstr "" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Шегіну" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Space" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5585,69 +5585,69 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "Иә" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/nl.po b/po/nl.po index 527bbd0b3..d9483c64f 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3355,7 +3355,7 @@ msgstr "" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5554,7 +5554,7 @@ msgstr "" "Kon widget '%s' niet vinden in grafische interface definitie. Controleer de " "installatie." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5613,31 +5613,31 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5692,72 +5692,72 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Zoek in projectbestanden" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 #, fuzzy msgid "Yes" msgstr "ja" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "Nee." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/pt.po b/po/pt.po index 08221fc74..9aa260fa6 100644 --- a/po/pt.po +++ b/po/pt.po @@ -3493,7 +3493,7 @@ msgstr "Cancelar seleção" msgid "Toggle Insert/Overwrite mode" msgstr "Alternar modo Inserir/Sobrescrever" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Tab" @@ -5812,7 +5812,7 @@ msgstr "" "Impossível encontrar o widget \"%s\" na definição do UI, por favor verifique " "a sua instalação." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "XML PrettyPrinter" @@ -5877,31 +5877,31 @@ msgstr "Nós de texto" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "Nós vazios" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Concatenação ( to )" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Espaçamento ( to )" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Expansão ( to )" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Indentação" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Espaço" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Quebra de linha" @@ -5953,11 +5953,11 @@ msgstr "Trocar cabeçalho/código" msgid "Open Selected File (Project Organizer)" msgstr "Abrir ficheiro selecionado (Organizador de projeto)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Padrões de fontes:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." @@ -5965,11 +5965,11 @@ msgstr "" "Lista de padrões separados por espaços, usados para identificar ficheiros " "fonte. Usado para trocas entre cabeçalho/fonte." -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Padrões de ficheiros de cabeçalhos:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." @@ -5977,11 +5977,11 @@ msgstr "" "Lista de padrões separados por espaços, usados para identificar cabeçalhos. " "Usado para trocas entre cabeçalho/fonte." -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "Padrões de ficheiro a ignorar:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." @@ -5989,11 +5989,11 @@ msgstr "" "Lista de padrões separados por espaços, usados para identificar ficheiros " "que não são mostrados na árvore do projeto." -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "Padrões de pasta a ignorar:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -6001,23 +6001,23 @@ msgstr "" "Lista separada por espaços, de padrões a ser usados para identificar " "diretórios onde não se procurarão ficheiros de código." -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "Indexar todos os ficheiros de projeto:" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "Automático (indexar se menos de 300 ficheiros)" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "Sim" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "Não" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." @@ -6025,7 +6025,7 @@ msgstr "" "Gerar lista de símbolos para todos os ficheiros do projeto e não só para os " "atualmente abertos. Pode ser lento para projetos grandes." -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" @@ -7337,6 +7337,7 @@ msgid "TreeBrowser" msgstr "Navegador em árvore" #: ../treebrowser/src/treebrowser.c:128 +#, fuzzy msgid "" "This plugin adds a tree browser to Geany, allowing the user to browse files " "using a tree view of the directory being browsed.\n" diff --git a/po/pt_BR.po b/po/pt_BR.po index e91fff4fe..62b684dde 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -3542,7 +3542,7 @@ msgstr "Seleção Extra" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5775,7 +5775,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5836,33 +5836,33 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 #, fuzzy msgid "Empty nodes" msgstr "(Linha vazia)" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 #, fuzzy msgid "Indentation" msgstr "Apresentação" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5919,74 +5919,74 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 #, fuzzy msgid "Header patterns:" msgstr "Extensões de cabeçalhos" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 #, fuzzy msgid "Ignored file patterns:" msgstr "Extensões de cabeçalhos" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 #, fuzzy msgid "Ignored directory patterns:" msgstr "Extensões de cabeçalhos" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Pesquisa em Projeto" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "Não." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/ru.po b/po/ru.po index a2df2ba48..643d1d507 100644 --- a/po/ru.po +++ b/po/ru.po @@ -3462,7 +3462,7 @@ msgstr "Сбросить выделение" msgid "Toggle Insert/Overwrite mode" msgstr "Переключить режим вставки/замены" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Табуляция" @@ -5761,7 +5761,7 @@ msgstr "" "Невозможно найти виджет \"%s\" в файле интерфейса, проверьте правильность " "установки." -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "Форматирование XML" @@ -5824,31 +5824,31 @@ msgstr "Текстовые элементы" msgid "CDATA" msgstr "Символьные данные" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "Пустые элементы" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Объединение ( to )" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Пробелы ( to )" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Расширение ( to )" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Отступы" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Пробелы" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Перевод строки" @@ -5899,11 +5899,11 @@ msgstr "Переключить заголовок/реализацию" msgid "Open Selected File (Project Organizer)" msgstr "Открыть выбранный файл (органайзер проектов)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "Шаблоны файлов с исходным текстом:" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." @@ -5911,11 +5911,11 @@ msgstr "" "Разделённый пробелами список шаблонов для определения файлов с исходным " "текстом. Нужно для переключения исходник/заголовок." -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "Шаблоны заголовочных файлов:" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." @@ -5923,11 +5923,11 @@ msgstr "" "Разделённый пробелами список шаблонов для определения заголовочных файлов. " "Нужно для переключения исходник/заголовок." -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "Шаблоны игнорируемых файлов:" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." @@ -5935,11 +5935,11 @@ msgstr "" "Разделённый пробелами список шаблонов, которые используются для определения " "файлов, не отображаемых в дереве файлов проекта." -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "Игнорируемые шаблоны каталогов:" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." @@ -5947,23 +5947,23 @@ msgstr "" "Разделённый пробелами список шаблонов, которые используются для определения " "каталогов, не просматриваемых на предмет наличия файлов проекта." -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 msgid "Index all project files:" msgstr "Индексировать все файлы проекта:" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "Автоматически (индексировать, если файлов не более 300)" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "Да" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 msgid "No" msgstr "Нет" -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." @@ -5971,7 +5971,7 @@ msgstr "" "Генерировать список символов для всех файлов проекта, а не только для " "открытых. Может работать медленно для больших проектов." -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/tr.po b/po/tr.po index 0b3d7dbd2..c3816e0fa 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3396,7 +3396,7 @@ msgstr "Seçimi iptal et" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "Sekme" @@ -5594,7 +5594,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5653,31 +5653,31 @@ msgstr "" msgid "CDATA" msgstr "CDATA" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 msgid "Empty nodes" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "Bağlanma ( den e)" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "Boşluklama ( den e)" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "Genişleme ( den e)" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 msgid "Indentation" msgstr "Girinti" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "Boşluk" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "Satır sonu" @@ -5733,72 +5733,72 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "Seçilen Dosyayı Aç (gproject)" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "Proje dosyalarında ara" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 #, fuzzy msgid "Yes" msgstr "evet" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "No." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index 95539a92f..a4088fca3 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3546,7 +3546,7 @@ msgstr "选择字体" msgid "Toggle Insert/Overwrite mode" msgstr "" -#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:239 +#: ../geanymacro/src/geanymacro.c:137 ../pretty-printer/src/ConfigUI.c:429 msgid "Tab" msgstr "" @@ -5758,7 +5758,7 @@ msgid "" "installation." msgstr "" -#: ../pretty-printer/src/PluginEntry.c:36 +#: ../pretty-printer/src/PluginEntry.c:41 msgid "XML PrettyPrinter" msgstr "" @@ -5818,33 +5818,33 @@ msgstr "" msgid "CDATA" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:205 +#: ../pretty-printer/src/ConfigUI.c:395 #, fuzzy msgid "Empty nodes" msgstr "(空行)" -#: ../pretty-printer/src/ConfigUI.c:206 +#: ../pretty-printer/src/ConfigUI.c:396 msgid "Concatenation ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:207 +#: ../pretty-printer/src/ConfigUI.c:397 msgid "Spacing ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:208 +#: ../pretty-printer/src/ConfigUI.c:398 msgid "Expansion ( to )" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:235 +#: ../pretty-printer/src/ConfigUI.c:425 #, fuzzy msgid "Indentation" msgstr "简报" -#: ../pretty-printer/src/ConfigUI.c:240 +#: ../pretty-printer/src/ConfigUI.c:430 msgid "Space" msgstr "" -#: ../pretty-printer/src/ConfigUI.c:264 +#: ../pretty-printer/src/ConfigUI.c:454 msgid "Line break" msgstr "" @@ -5901,71 +5901,71 @@ msgstr "" msgid "Open Selected File (Project Organizer)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:573 +#: ../projectorganizer/src/prjorg-project.c:578 msgid "Source patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:579 +#: ../projectorganizer/src/prjorg-project.c:584 msgid "" "Space separated list of patterns that are used to identify source files. " "Used for header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:585 +#: ../projectorganizer/src/prjorg-project.c:590 msgid "Header patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:591 +#: ../projectorganizer/src/prjorg-project.c:596 msgid "" "Space separated list of patterns that are used to identify headers. Used for " "header/source swapping." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:597 +#: ../projectorganizer/src/prjorg-project.c:602 msgid "Ignored file patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:603 +#: ../projectorganizer/src/prjorg-project.c:608 msgid "" "Space separated list of patterns that are used to identify files that are " "not displayed in the project tree." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:609 +#: ../projectorganizer/src/prjorg-project.c:614 msgid "Ignored directory patterns:" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:615 +#: ../projectorganizer/src/prjorg-project.c:620 msgid "" "Space separated list of patterns that are used to identify directories that " "are not scanned for source files." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:621 +#: ../projectorganizer/src/prjorg-project.c:626 #, fuzzy msgid "Index all project files:" msgstr "在项目中查找" -#: ../projectorganizer/src/prjorg-project.c:624 +#: ../projectorganizer/src/prjorg-project.c:629 msgid "Auto (index if less than 300 files)" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:625 +#: ../projectorganizer/src/prjorg-project.c:630 msgid "Yes" msgstr "" -#: ../projectorganizer/src/prjorg-project.c:626 +#: ../projectorganizer/src/prjorg-project.c:631 #, fuzzy msgid "No" msgstr "No." -#: ../projectorganizer/src/prjorg-project.c:630 +#: ../projectorganizer/src/prjorg-project.c:635 msgid "" "Generate symbol list for all project files instead of only for the currently " "opened files. Might be slow for big projects." msgstr "" -#: ../projectorganizer/src/prjorg-project.c:636 +#: ../projectorganizer/src/prjorg-project.c:641 msgid "" "Note: the patterns above affect only the sidebar and are not used in the " "Find in Files\n" diff --git a/workbench/AUTHORS b/workbench/AUTHORS new file mode 100644 index 000000000..94c363ee2 --- /dev/null +++ b/workbench/AUTHORS @@ -0,0 +1 @@ +LarsGit223 diff --git a/workbench/COPYING b/workbench/COPYING new file mode 100644 index 000000000..8c4c849e2 --- /dev/null +++ b/workbench/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/workbench/ChangeLog b/workbench/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/workbench/Makefile.am b/workbench/Makefile.am new file mode 100644 index 000000000..62210cb9c --- /dev/null +++ b/workbench/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/build/vars.auxfiles.mk + +SUBDIRS = src icons +plugin = workbench diff --git a/workbench/NEWS b/workbench/NEWS new file mode 100644 index 000000000..b671f54ab --- /dev/null +++ b/workbench/NEWS @@ -0,0 +1,2 @@ +Juli 2017 +* Created plugin, initial commit (work in progress) diff --git a/workbench/README b/workbench/README new file mode 100644 index 000000000..f9b5c26ac --- /dev/null +++ b/workbench/README @@ -0,0 +1,151 @@ +========= +Workbench +========= + +.. contents:: + +About +===== + +The Workbench plugin is an extension that makes it possible to manage +multiple projects in geany. You can add geany projects to a workbench. +From there you can add directories to the project to manage the files +belonging to the project. + +Usage +===== + +Enabling the plugin +------------------- +The plugin can be enabled in the plugin manager. After enabling the plugin +a new tab will be displayed in the Sidebar. There will also be a new entry +in the menubar. Both are labeled "Workbench". + +The Workbench menu +------------------ +The Workbench menu is the starting point for creating your first workbench. +Choose "New" from the menu to create your workbench file. Workbench files +use the prefix ".geanywb". Just like Geany project files they are also +simple text files containing key-value pairs. + +The complete managment of the Workbench file is done using the Workbench +menu: +- Item "New": as explained above, creates a new Workbench +- Item "Open": open a Workbench +- Item "Save": save the opened Workbench. This "only" saves any changes + in the Workbench file. It does not save any changes of the projects + belonging to the Workbench. +- Item "Settings": open the Workbench settings dialog. +- Item "Close": closes the opened Workbench. + +The new Workbench +----------------- +A newly created Workbench is completely empty. In the Workbench tab of +the sidebar you should see the hint "Add a project using the context +menu". Anything which is dealing with projects and their Workbench +related settings is done using the context menu on the sidebar. Some +items in the context menu will only be active if you right click inside +a project, directory or bookmark. + +The Workbench context menu: +--------------------------- + +These are the available items: + +- "Add project": + Add an existing Geany project to the Workbench. Create your projects + with Geany. The Workbench plugin does not help you with that. After + adding a project you need to save the workbench settings by selecting + "Workbench / Save" in the menubar. +- "Save project": + Selecting this item will save the Workbench related project settings in + the Geany project file. It is only available if you right clicked inside + of a project. It will only save the settings of the project that you + clicked on. +- "Remove project": + Remove the project from the Workbench. It is only available if you + right clicked inside of a project. After removing a project you need + to save the workbench settings by selecting "Workbench / Save" in the + menubar. +- "Fold/unfold project": + Fold or unfold the items belonging to the project. It is only available + if you right clicked inside of a project. + +- "Add directory": + Add a directory to the project. It is only available + if you right clicked inside of a project. After selecting it a dialog + will be opened. Chosse the directory which shall be added. After that + the directory will be shown inside the project folder. After adding a + new directory, all files and folders beneath the directory will be + displayed. See "Directory settings" for more information. +- "Remove directory": + Remove the directory from the project. It is only available if you + right clicked inside of a project directory. +- "Rescan directory": + Rescan the directory for files and update the sidebar accordingly. + It is only available if you right clicked inside of a project directory. + If the content of a directory changes, e.g. a new file is added, then + the new file will only be visible in the sidebar after a rescan. +- "Directory settings": + Select this item to change the directory settings. It is only available + if you right clicked inside of a project directory. In the directory + settings you can set a filter which controls the files and folders + that shall be displayed or not. +- "Fold/unfold directory": + Fold or unfold the items belonging to the directory. It is only available + if you right clicked inside of a directory. + +- "Unfold All": + Select this item to unfold all projects, directories and folders. +- "Collapse All": + Select this item to collpase/fold all projects, directories and folders. + +- "Add to Workbench Bookmarks": + Add the file to the Workbench Bookmarks. It is only available + if you right clicked on a file. After adding a file to the Workbench + bookmarks a ribbon will be shown for the file in the Workbench sidebar + tab in front of the first project. Clicking on it will open the file. + Workbench bookmarks give you quick access to files which you often need. +- "Add to Project Bookmarks": + Add the file to the Project Bookmarks. It is only available + if you right clicked on a file. After adding a file to the Project + bookmarks a ribbon will be shown for the file in the Workbench sidebar + tab in front of the first directory of the project. Clicking on it will + open the file. Project bookmarks give you quick access to files which + you often need in that project. +- "Remove from Bookmarks": + Remove file from the Workbench or project bookmarks. It is only available + if you right clicked on a bookmark. + +Known issues +============ + +None. + +License +======= + +The Workbench plugin is distributed 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. A copy +of this license can be found in the file COPYING included with the source +code of this program. + +Downloads +========= + +The Workbench plugin is not (yet) part of the combined Geany Plugins release. +So please download it from the github page, see below. + +Development Code +================ + +Get the code from:: + + git clone https://github.com/LarsGit223/geany-plugins + +Ideas, questions, patches and bug reports +========================================= + +Please post any ideas, feature requests, questions and bugs in the +github issue tracker. diff --git a/workbench/THANKS b/workbench/THANKS new file mode 100644 index 000000000..0fbb33948 --- /dev/null +++ b/workbench/THANKS @@ -0,0 +1,13 @@ +What's this file about? +----------------------- +This file lists all external people that have contributed to this project. + +Project Organizer Plugin: +------------------------- +This plugin is heavily based on code from the Project Organizer plugin. +So big thanks go to the author Jiří Techet. + +Geany and Geany plugins: +------------------------ +Thanks to all Geany developers for support and writing an simple, lightweight, +open and extensible IDE. diff --git a/workbench/icons/16x16/Makefile.am b/workbench/icons/16x16/Makefile.am new file mode 100644 index 000000000..b3cc7d364 --- /dev/null +++ b/workbench/icons/16x16/Makefile.am @@ -0,0 +1,9 @@ +iconsdir = $(datadir)/icons/hicolor/16x16 +icons_appsdir = $(iconsdir)/apps + +dist_icons_apps_DATA = \ + workbench-bookmark.png \ + workbench-dir.png \ + workbench-nodirs.png \ + workbench-project.png \ + workbench-project-error.png diff --git a/workbench/icons/16x16/workbench-bookmark.png b/workbench/icons/16x16/workbench-bookmark.png new file mode 100644 index 000000000..672b1b27e Binary files /dev/null and b/workbench/icons/16x16/workbench-bookmark.png differ diff --git a/workbench/icons/16x16/workbench-dir.png b/workbench/icons/16x16/workbench-dir.png new file mode 100644 index 000000000..993d486ae Binary files /dev/null and b/workbench/icons/16x16/workbench-dir.png differ diff --git a/workbench/icons/16x16/workbench-nodirs.png b/workbench/icons/16x16/workbench-nodirs.png new file mode 100644 index 000000000..52442d047 Binary files /dev/null and b/workbench/icons/16x16/workbench-nodirs.png differ diff --git a/workbench/icons/16x16/workbench-project-error.png b/workbench/icons/16x16/workbench-project-error.png new file mode 100644 index 000000000..ec7315431 Binary files /dev/null and b/workbench/icons/16x16/workbench-project-error.png differ diff --git a/workbench/icons/16x16/workbench-project.png b/workbench/icons/16x16/workbench-project.png new file mode 100644 index 000000000..e12dc7b53 Binary files /dev/null and b/workbench/icons/16x16/workbench-project.png differ diff --git a/workbench/icons/24x24/Makefile.am b/workbench/icons/24x24/Makefile.am new file mode 100644 index 000000000..7f52f0f61 --- /dev/null +++ b/workbench/icons/24x24/Makefile.am @@ -0,0 +1,9 @@ +iconsdir = $(datadir)/icons/hicolor/24x24 +icons_appsdir = $(iconsdir)/apps + +dist_icons_apps_DATA = \ + workbench-bookmark.png \ + workbench-dir.png \ + workbench-nodirs.png \ + workbench-project.png \ + workbench-project-error.png diff --git a/workbench/icons/24x24/workbench-bookmark.png b/workbench/icons/24x24/workbench-bookmark.png new file mode 100644 index 000000000..079cd1465 Binary files /dev/null and b/workbench/icons/24x24/workbench-bookmark.png differ diff --git a/workbench/icons/24x24/workbench-dir.png b/workbench/icons/24x24/workbench-dir.png new file mode 100644 index 000000000..1be6994cd Binary files /dev/null and b/workbench/icons/24x24/workbench-dir.png differ diff --git a/workbench/icons/24x24/workbench-nodirs.png b/workbench/icons/24x24/workbench-nodirs.png new file mode 100644 index 000000000..35e9a75f1 Binary files /dev/null and b/workbench/icons/24x24/workbench-nodirs.png differ diff --git a/workbench/icons/24x24/workbench-project-error.png b/workbench/icons/24x24/workbench-project-error.png new file mode 100644 index 000000000..929157e2f Binary files /dev/null and b/workbench/icons/24x24/workbench-project-error.png differ diff --git a/workbench/icons/24x24/workbench-project.png b/workbench/icons/24x24/workbench-project.png new file mode 100644 index 000000000..62a220cca Binary files /dev/null and b/workbench/icons/24x24/workbench-project.png differ diff --git a/workbench/icons/32x32/Makefile.am b/workbench/icons/32x32/Makefile.am new file mode 100644 index 000000000..aa6fc0cf1 --- /dev/null +++ b/workbench/icons/32x32/Makefile.am @@ -0,0 +1,9 @@ +iconsdir = $(datadir)/icons/hicolor/32x32 +icons_appsdir = $(iconsdir)/apps + +dist_icons_apps_DATA = \ + workbench-bookmark.png \ + workbench-dir.png \ + workbench-nodirs.png \ + workbench-project.png \ + workbench-project-error.png diff --git a/workbench/icons/32x32/workbench-bookmark.png b/workbench/icons/32x32/workbench-bookmark.png new file mode 100644 index 000000000..0e9a93f02 Binary files /dev/null and b/workbench/icons/32x32/workbench-bookmark.png differ diff --git a/workbench/icons/32x32/workbench-dir.png b/workbench/icons/32x32/workbench-dir.png new file mode 100644 index 000000000..ca4c2e7e0 Binary files /dev/null and b/workbench/icons/32x32/workbench-dir.png differ diff --git a/workbench/icons/32x32/workbench-nodirs.png b/workbench/icons/32x32/workbench-nodirs.png new file mode 100644 index 000000000..a242361f6 Binary files /dev/null and b/workbench/icons/32x32/workbench-nodirs.png differ diff --git a/workbench/icons/32x32/workbench-project-error.png b/workbench/icons/32x32/workbench-project-error.png new file mode 100644 index 000000000..be1cc2985 Binary files /dev/null and b/workbench/icons/32x32/workbench-project-error.png differ diff --git a/workbench/icons/32x32/workbench-project.png b/workbench/icons/32x32/workbench-project.png new file mode 100644 index 000000000..05676e2de Binary files /dev/null and b/workbench/icons/32x32/workbench-project.png differ diff --git a/workbench/icons/48x48/Makefile.am b/workbench/icons/48x48/Makefile.am new file mode 100644 index 000000000..a840cc135 --- /dev/null +++ b/workbench/icons/48x48/Makefile.am @@ -0,0 +1,9 @@ +iconsdir = $(datadir)/icons/hicolor/48x48 +icons_appsdir = $(iconsdir)/apps + +dist_icons_apps_DATA = \ + workbench-bookmark.png \ + workbench-dir.png \ + workbench-nodirs.png \ + workbench-project.png \ + workbench-project-error.png diff --git a/workbench/icons/48x48/workbench-bookmark.png b/workbench/icons/48x48/workbench-bookmark.png new file mode 100644 index 000000000..5469b7297 Binary files /dev/null and b/workbench/icons/48x48/workbench-bookmark.png differ diff --git a/workbench/icons/48x48/workbench-dir.png b/workbench/icons/48x48/workbench-dir.png new file mode 100644 index 000000000..ceab69b54 Binary files /dev/null and b/workbench/icons/48x48/workbench-dir.png differ diff --git a/workbench/icons/48x48/workbench-nodirs.png b/workbench/icons/48x48/workbench-nodirs.png new file mode 100644 index 000000000..cca5804c9 Binary files /dev/null and b/workbench/icons/48x48/workbench-nodirs.png differ diff --git a/workbench/icons/48x48/workbench-project-error.png b/workbench/icons/48x48/workbench-project-error.png new file mode 100644 index 000000000..3c4deb34c Binary files /dev/null and b/workbench/icons/48x48/workbench-project-error.png differ diff --git a/workbench/icons/48x48/workbench-project.png b/workbench/icons/48x48/workbench-project.png new file mode 100644 index 000000000..704d962d4 Binary files /dev/null and b/workbench/icons/48x48/workbench-project.png differ diff --git a/workbench/icons/Makefile.am b/workbench/icons/Makefile.am new file mode 100644 index 000000000..9c08bc852 --- /dev/null +++ b/workbench/icons/Makefile.am @@ -0,0 +1,20 @@ +SUBDIRS = 16x16 24x24 32x32 48x48 scalable + +gtk_update_icon_cache = gtk-update-icon-cache -f -t + +install-data-hook: + @-if test -z "$(DESTDIR)"; then \ + echo "Updating Gtk icon cache."; \ + $(gtk_update_icon_cache) "$(datadir)/icons/hicolor"; \ + $(gtk_update_icon_cache) "$(datadir)/icons/Tango"; \ + else \ + echo "*** Icon cache not updated. Remember to run:"; \ + echo "***"; \ + echo "*** $(gtk_update_icon_cache) '$(datadir)/icons/hicolor'";\ + echo "*** $(gtk_update_icon_cache) '$(datadir)/icons/Tango'";\ + echo "***"; \ + fi + +uninstall-local: + rm -f $(DESTDIR)$(datadir)/icons/hicolor/icon-theme.cache + rm -f $(DESTDIR)$(datadir)/icons/Tango/icon-theme.cache diff --git a/workbench/icons/scalable/Makefile.am b/workbench/icons/scalable/Makefile.am new file mode 100644 index 000000000..777aa19f5 --- /dev/null +++ b/workbench/icons/scalable/Makefile.am @@ -0,0 +1,9 @@ +iconsdir = $(datadir)/icons/hicolor/scalable +icons_appsdir = $(iconsdir)/apps + +dist_icons_apps_DATA = \ + workbench-bookmark.svg \ + workbench-dir.svg \ + workbench-nodirs.svg \ + workbench-project.svg \ + workbench-project-error.svg diff --git a/workbench/icons/scalable/workbench-bookmark.svg b/workbench/icons/scalable/workbench-bookmark.svg new file mode 100644 index 000000000..4e49e3b16 --- /dev/null +++ b/workbench/icons/scalable/workbench-bookmark.svg @@ -0,0 +1,17 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + diff --git a/workbench/icons/scalable/workbench-dir.svg b/workbench/icons/scalable/workbench-dir.svg new file mode 100644 index 000000000..270a18461 --- /dev/null +++ b/workbench/icons/scalable/workbench-dir.svg @@ -0,0 +1,18 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + diff --git a/workbench/icons/scalable/workbench-nodirs.svg b/workbench/icons/scalable/workbench-nodirs.svg new file mode 100644 index 000000000..0dc04b56d --- /dev/null +++ b/workbench/icons/scalable/workbench-nodirs.svg @@ -0,0 +1,20 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + + + diff --git a/workbench/icons/scalable/workbench-project-error.svg b/workbench/icons/scalable/workbench-project-error.svg new file mode 100644 index 000000000..5c1d0b757 --- /dev/null +++ b/workbench/icons/scalable/workbench-project-error.svg @@ -0,0 +1,17 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + diff --git a/workbench/icons/scalable/workbench-project.svg b/workbench/icons/scalable/workbench-project.svg new file mode 100644 index 000000000..d5dc4592b --- /dev/null +++ b/workbench/icons/scalable/workbench-project.svg @@ -0,0 +1,19 @@ + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + + diff --git a/workbench/src/Makefile.am b/workbench/src/Makefile.am new file mode 100644 index 000000000..459bca44a --- /dev/null +++ b/workbench/src/Makefile.am @@ -0,0 +1,31 @@ +include $(top_srcdir)/build/vars.build.mk +plugin = workbench + +geanyplugins_LTLIBRARIES = workbench.la + +workbench_la_SOURCES = \ + plugin_main.c \ + wb_globals.h \ + wb_globals.c \ + workbench.h \ + workbench.c \ + wb_project.h \ + wb_project.c \ + dialogs.h \ + dialogs.c \ + menu.h \ + menu.c \ + popup_menu.h \ + popup_menu.c \ + sidebar.h \ + sidebar.c \ + utils.h \ + utils.c + +workbench_la_CPPFLAGS = $(AM_CPPFLAGS) \ + -DG_LOG_DOMAIN=\"Workbench\" +workbench_la_CFLAGS = $(AM_CFLAGS) +workbench_la_LIBADD = $(COMMONLIBS) + +include $(top_srcdir)/build/cppcheck.mk + diff --git a/workbench/src/dialogs.c b/workbench/src/dialogs.c new file mode 100644 index 000000000..2017dcaad --- /dev/null +++ b/workbench/src/dialogs.c @@ -0,0 +1,395 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * This file contains all the code for the dialogs. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wb_globals.h" +#include "dialogs.h" + +extern GeanyPlugin *geany_plugin; + +/** Shows the dialog "Create new workbench". + * + * The dialog lets the user create a new workbench file (filter *.geanywb). + * + * @return The filename + * + **/ +gchar *dialogs_create_new_workbench(void) +{ + gchar *filename = NULL; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new(_("Create new workbench"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("C_reate"), GTK_RESPONSE_ACCEPT, NULL); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "new.geanywb"); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + +/** Shows the dialog "Open workbench". + * + * The dialog lets the user choose an existing workbench file (filter *.geanywb). + * + * @return The filename + * + **/ +gchar *dialogs_open_workbench(void) +{ + gchar *filename = NULL; + GtkWidget *dialog; + GtkFileFilter *filter; + + dialog = gtk_file_chooser_dialog_new(_("Open workbench"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Open"), GTK_RESPONSE_ACCEPT, NULL); + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("Workbench files (.geanywb)")); + gtk_file_filter_add_pattern(filter, "*.geanywb"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("All Files")); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + +/** Shows the dialog "Add project". + * + * The dialog lets the user choose an existing project file + * (filter *.geany or *). + * + * @return The filename + * + **/ +gchar *dialogs_add_project(void) +{ + gchar *filename = NULL; + GtkWidget *dialog; + GtkFileFilter *filter; + + dialog = gtk_file_chooser_dialog_new(_("Add project"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Add"), GTK_RESPONSE_ACCEPT, NULL); + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("Project files (.geany)")); + gtk_file_filter_add_pattern(filter, "*.geany"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("All Files")); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + +/** Shows the dialog "Add directory". + * + * The dialog lets the user choose an existing folder. + * + * @return The filename + * + **/ +gchar *dialogs_add_directory(WB_PROJECT *project) +{ + gchar *filename = NULL; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new(_("Add directory"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Add"), GTK_RESPONSE_ACCEPT, NULL); + if (project != NULL) + { + const gchar *path; + + /* Set the current folder to the location of the project file */ + path = wb_project_get_filename(project); + if (path != NULL) + { + gchar *dirname = g_path_get_dirname(path); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dirname); + g_free(dirname); + } + } + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + +/* Split patterns in str into gchar** */ +static gchar **split_patterns(const gchar *str) +{ + GString *tmp; + gchar **ret; + gchar *input; + + input = g_strdup(str); + + g_strstrip(input); + tmp = g_string_new(input); + g_free(input); + do {} while (utils_string_replace_all(tmp, " ", " ")); + ret = g_strsplit(tmp->str, " ", -1); + g_string_free(tmp, TRUE); + return ret; +} + + +/** Shows the directory settings dialog. + * + * The dialog lets the user edit the settings for file patterns, irnored file patterns and + * ignored directories patterns. On accept the result is directly stored in @a directory. + * + * @param directory Location of WB_PROJECT_DIR to store the settings into + * @return TRUE if the settings have changed, FALSE otherwise + * + **/ +gboolean dialogs_directory_settings(WB_PROJECT_DIR *directory) +{ + GtkWidget *w_file_patterns, *w_ignored_dirs_patterns, *w_ignored_file_patterns; + GtkWidget *dialog, *label, *content_area; + GtkWidget *vbox, *hbox, *hbox1, *table; + GtkDialogFlags flags; + gchar *file_patterns_old, *ignored_file_patterns_old, *ignored_dirs_patterns_old; + gboolean changed; + + /* Create the widgets */ + flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; + dialog = gtk_dialog_new_with_buttons(_("Directory settings"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), + flags, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_OK"), GTK_RESPONSE_ACCEPT, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); + + vbox = gtk_vbox_new(FALSE, 0); + + table = gtk_table_new(5, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + + label = gtk_label_new(_("File patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + w_file_patterns = gtk_entry_new(); + ui_table_add_row(GTK_TABLE(table), 0, label, w_file_patterns, NULL); + ui_entry_add_clear_icon(GTK_ENTRY(w_file_patterns)); + gtk_widget_set_tooltip_text(w_file_patterns, + _("Space separated list of patterns that are used to identify files " + "that shall be displayed in the directory tree.")); + file_patterns_old = g_strjoinv(" ", wb_project_dir_get_file_patterns(directory)); + gtk_entry_set_text(GTK_ENTRY(w_file_patterns), file_patterns_old); + + label = gtk_label_new(_("Ignored file patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + w_ignored_file_patterns = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(w_ignored_file_patterns)); + ui_table_add_row(GTK_TABLE(table), 2, label, w_ignored_file_patterns, NULL); + gtk_widget_set_tooltip_text(w_ignored_file_patterns, + _("Space separated list of patterns that are used to identify files " + "that shall not be displayed in the directory tree.")); + ignored_file_patterns_old = g_strjoinv(" ", wb_project_dir_get_ignored_file_patterns(directory)); + gtk_entry_set_text(GTK_ENTRY(w_ignored_file_patterns), ignored_file_patterns_old); + + label = gtk_label_new(_("Ignored directory patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + w_ignored_dirs_patterns = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(w_ignored_dirs_patterns)); + ui_table_add_row(GTK_TABLE(table), 3, label, w_ignored_dirs_patterns, NULL); + gtk_widget_set_tooltip_text(w_ignored_dirs_patterns, + _("Space separated list of patterns that are used to identify directories " + "that shall not be scanned for source files.")); + ignored_dirs_patterns_old = g_strjoinv(" ", wb_project_dir_get_ignored_dirs_patterns(directory)); + gtk_entry_set_text(GTK_ENTRY(w_ignored_dirs_patterns), ignored_dirs_patterns_old); + + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 6); + + hbox1 = gtk_hbox_new(FALSE, 0); + label = gtk_label_new(_("Note: the patterns above affect only the workbench directory and are not used in the Find in Files\n" + "dialog.")); + gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 6); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6); + + /* Add the label, and show everything we’ve added */ + gtk_container_add(GTK_CONTAINER (content_area), label); + gtk_container_add(GTK_CONTAINER (content_area), hbox); + + gtk_widget_show_all(dialog); + gint result = gtk_dialog_run(GTK_DIALOG(dialog)); + changed = FALSE; + if (result == GTK_RESPONSE_ACCEPT) + { + const gchar *str; + gchar **file_patterns, **ignored_dirs_patterns, **ignored_file_patterns; + + str = gtk_entry_get_text(GTK_ENTRY(w_file_patterns)); + if (g_strcmp0(str, file_patterns_old) != 0) + { + changed = TRUE; + } + file_patterns = split_patterns(str); + + str = gtk_entry_get_text(GTK_ENTRY(w_ignored_dirs_patterns)); + if (g_strcmp0(str, ignored_dirs_patterns_old) != 0) + { + changed = TRUE; + } + ignored_dirs_patterns = split_patterns(str); + + str = gtk_entry_get_text(GTK_ENTRY(w_ignored_file_patterns)); + if (g_strcmp0(str, ignored_file_patterns_old) != 0) + { + changed = TRUE; + } + ignored_file_patterns = split_patterns(str); + + wb_project_dir_set_file_patterns(directory, file_patterns); + wb_project_dir_set_ignored_dirs_patterns(directory, ignored_dirs_patterns); + wb_project_dir_set_ignored_file_patterns(directory, ignored_file_patterns); + + g_strfreev(file_patterns); + g_strfreev(ignored_dirs_patterns); + g_strfreev(ignored_file_patterns); + } + + g_free(file_patterns_old); + g_free(ignored_file_patterns_old); + g_free(ignored_dirs_patterns_old); + gtk_widget_destroy(dialog); + + return changed; +} + + +/** Shows the workbench settings dialog. + * + * The dialog lets the user edit the settings for option "Rescan all projects on open". + * On accept the result is directly stored in @a workbench. + * + * @param workbench Location of WORKBENCH to store the settings into + * @return TRUE if the settings have changed, FALSE otherwise + * + **/ +gboolean dialogs_workbench_settings(WORKBENCH *workbench) +{ + gint result; + GtkWidget *w_rescan_projects_on_open; + GtkWidget *dialog, *label, *content_area; + GtkWidget *vbox, *hbox, *table; + GtkDialogFlags flags; + gboolean changed, rescan_projects_on_open, rescan_projects_on_open_old; + + /* Create the widgets */ + flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; + dialog = gtk_dialog_new_with_buttons(_("Workbench settings"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), + flags, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_OK"), GTK_RESPONSE_ACCEPT, + NULL); + content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); + + vbox = gtk_vbox_new(FALSE, 0); + + table = gtk_table_new(5, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + + label = gtk_label_new(_("Rescan all projects on open:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + w_rescan_projects_on_open = gtk_check_button_new(); + ui_table_add_row(GTK_TABLE(table), 0, label, w_rescan_projects_on_open, NULL); + gtk_widget_set_tooltip_text(w_rescan_projects_on_open, + _("If the option is activated (default), then all projects will be re-scanned" + " on opening of the workbench.")); + rescan_projects_on_open_old = workbench_get_rescan_projects_on_open(workbench); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_rescan_projects_on_open), rescan_projects_on_open_old); + + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 6); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6); + + /* Show everything we’ve added, run dialog */ + gtk_container_add(GTK_CONTAINER (content_area), hbox); + gtk_widget_show_all(dialog); + result = gtk_dialog_run(GTK_DIALOG(dialog)); + + changed = FALSE; + if (result == GTK_RESPONSE_ACCEPT) + { + rescan_projects_on_open = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_rescan_projects_on_open)); + if (rescan_projects_on_open != rescan_projects_on_open_old) + { + changed = TRUE; + workbench_set_rescan_projects_on_open(workbench, rescan_projects_on_open); + } + } + + gtk_widget_destroy(dialog); + + return changed; +} diff --git a/workbench/src/dialogs.h b/workbench/src/dialogs.h new file mode 100644 index 000000000..025d5d683 --- /dev/null +++ b/workbench/src/dialogs.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_DIALOGS_H__ +#define __WB_DIALOGS_H__ + +gchar *dialogs_create_new_workbench(void); +gchar *dialogs_open_workbench(void); +gchar *dialogs_add_project(void); +gchar *dialogs_add_directory(WB_PROJECT *project); +gboolean dialogs_directory_settings(WB_PROJECT_DIR *directory); +gboolean dialogs_workbench_settings(WORKBENCH *workbench); + +#endif diff --git a/workbench/src/menu.c b/workbench/src/menu.c new file mode 100644 index 000000000..3509692e0 --- /dev/null +++ b/workbench/src/menu.c @@ -0,0 +1,229 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the "Workbench" menu. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wb_globals.h" +#include "dialogs.h" +#include "menu.h" +#include "sidebar.h" + +extern GeanyPlugin *geany_plugin; + +typedef struct +{ + GtkWidget *menu; + GtkWidget *root_item; + GtkWidget *item_new; + GtkWidget *item_open; + GtkWidget *item_save; + GtkWidget *item_settings; + GtkWidget *item_close; +}WB_MENU_DATA; +static WB_MENU_DATA menu_data; + +/** Set the context of the workbench menu. + * + * The context set controls which items in the menu will be active and + * which will be deactive. + * + * @param context The context/situation in which the menu is/shall be + * + **/ +void menu_set_context(MENU_CONTEXT context) +{ + switch (context) + { + case MENU_CONTEXT_WB_CREATED: + case MENU_CONTEXT_WB_OPENED: + gtk_widget_set_sensitive(menu_data.item_new, FALSE); + gtk_widget_set_sensitive(menu_data.item_open, FALSE); + gtk_widget_set_sensitive(menu_data.item_save, TRUE); + gtk_widget_set_sensitive(menu_data.item_settings, TRUE); + gtk_widget_set_sensitive(menu_data.item_close, TRUE); + break; + case MENU_CONTEXT_WB_CLOSED: + gtk_widget_set_sensitive(menu_data.item_new, TRUE); + gtk_widget_set_sensitive(menu_data.item_open, TRUE); + gtk_widget_set_sensitive(menu_data.item_save, FALSE); + gtk_widget_set_sensitive(menu_data.item_settings, FALSE); + gtk_widget_set_sensitive(menu_data.item_close, FALSE); + break; + } +} + +/* The function handles the menu item "New workbench" */ +static void item_new_workbench_activate_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *filename; + GError *error = NULL; + + filename = dialogs_create_new_workbench(); + if (filename == NULL) + { + return; + } + wb_globals.opened_wb = workbench_new(); + workbench_set_filename(wb_globals.opened_wb, filename); + if (workbench_save(wb_globals.opened_wb, &error)) + { + menu_set_context(MENU_CONTEXT_WB_CREATED); + sidebar_update(SIDEBAR_CONTEXT_WB_CREATED, NULL); + } + else + { + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("Could not create new workbench file: %s"), error->message); + workbench_free(wb_globals.opened_wb); + wb_globals.opened_wb = NULL; + } + g_free(filename); +} + + +/* The function handles the menu item "Open workbench" */ +static void item_open_workbench_activate_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *filename; + GError *error = NULL; + + filename = dialogs_open_workbench(); + if (filename == NULL) + { + return; + } + wb_globals.opened_wb = workbench_new(); + if (workbench_load(wb_globals.opened_wb, filename, &error)) + { + menu_set_context(MENU_CONTEXT_WB_OPENED); + sidebar_update(SIDEBAR_CONTEXT_WB_OPENED, NULL); + } + else + { + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("Could not open workbench file: %s"), error->message); + workbench_free(wb_globals.opened_wb); + wb_globals.opened_wb = NULL; + } + g_free(filename); +} + + +/* The function handles the menu item "Save workbench" */ +static void item_save_workbench_activate_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GError *error = NULL; + + if (wb_globals.opened_wb != NULL) + { + if (!workbench_save(wb_globals.opened_wb, &error)) + { + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("Could not save workbench file: %s"), error->message); + } + sidebar_update(SIDEBAR_CONTEXT_WB_SAVED, NULL); + } +} + + +/* The function handles the menu item "Settings" */ +static void item_workbench_settings_activate_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + if (wb_globals.opened_wb != NULL) + { + if (dialogs_workbench_settings(wb_globals.opened_wb)) + { + sidebar_update(SIDEBAR_CONTEXT_WB_SETTINGS_CHANGED, NULL); + } + } +} + + +/* The function handles the menu item "Close workbench" */ +static void item_close_workbench_activate_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + workbench_free(wb_globals.opened_wb); + wb_globals.opened_wb = NULL; + + menu_set_context(MENU_CONTEXT_WB_CLOSED); + sidebar_update(SIDEBAR_CONTEXT_WB_CLOSED, NULL); +} + + +/** Setup the workbench menu. + * + **/ +gboolean menu_init(void) +{ + /* Create menu and root item/label */ + menu_data.menu = gtk_menu_new(); + menu_data.root_item = gtk_menu_item_new_with_label(_("Workbench")); + gtk_widget_show(menu_data.root_item); + + /* Create new menu item "New Workbench" */ + menu_data.item_new = gtk_menu_item_new_with_mnemonic(_("_New...")); + gtk_widget_show(menu_data.item_new); + gtk_menu_shell_append(GTK_MENU_SHELL (menu_data.menu), menu_data.item_new); + g_signal_connect(menu_data.item_new, "activate", + G_CALLBACK(item_new_workbench_activate_cb), NULL); + + /* Create new menu item "Open Workbench" */ + menu_data.item_open = gtk_menu_item_new_with_mnemonic(_("_Open...")); + gtk_widget_show(menu_data.item_open); + gtk_menu_shell_append(GTK_MENU_SHELL (menu_data.menu), menu_data.item_open); + g_signal_connect(menu_data.item_open, "activate", + G_CALLBACK(item_open_workbench_activate_cb), NULL); + + /* Create new menu item "Save Workbench" */ + menu_data.item_save = gtk_menu_item_new_with_mnemonic(_("_Save")); + gtk_widget_show(menu_data.item_save); + gtk_menu_shell_append(GTK_MENU_SHELL (menu_data.menu), menu_data.item_save); + g_signal_connect(menu_data.item_save, "activate", + G_CALLBACK(item_save_workbench_activate_cb), NULL); + + /* Create new menu item "Workbench Settings" */ + menu_data.item_settings = gtk_menu_item_new_with_mnemonic(_("S_ettings")); + gtk_widget_show(menu_data.item_settings); + gtk_menu_shell_append(GTK_MENU_SHELL (menu_data.menu), menu_data.item_settings); + g_signal_connect(menu_data.item_settings, "activate", + G_CALLBACK(item_workbench_settings_activate_cb), NULL); + + /* Create new menu item "Close Workbench" */ + menu_data.item_close = gtk_menu_item_new_with_mnemonic(_("_Close")); + gtk_widget_show(menu_data.item_close); + gtk_menu_shell_append(GTK_MENU_SHELL (menu_data.menu), menu_data.item_close); + g_signal_connect(menu_data.item_close, "activate", + G_CALLBACK(item_close_workbench_activate_cb), NULL); + + /* Add our menu to the main window (left of the help menu) */ + gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_data.root_item), menu_data.menu); + gtk_container_add(GTK_CONTAINER(wb_globals.geany_plugin->geany_data->main_widgets->tools_menu), menu_data.root_item); + + return TRUE; +} + + +/** Cleanup menu data/mem. + * + **/ +void menu_cleanup (void) +{ + gtk_widget_destroy(menu_data.root_item); +} diff --git a/workbench/src/menu.h b/workbench/src/menu.h new file mode 100644 index 000000000..a72897dbb --- /dev/null +++ b/workbench/src/menu.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_MENU_H__ +#define __WB_MENU_H__ + +typedef enum +{ + MENU_CONTEXT_WB_CREATED, + MENU_CONTEXT_WB_OPENED, + MENU_CONTEXT_WB_CLOSED, +}MENU_CONTEXT; + +void menu_set_context(MENU_CONTEXT context); +gboolean menu_init(void); +void menu_cleanup (void); + +#endif diff --git a/workbench/src/plugin_main.c b/workbench/src/plugin_main.c new file mode 100644 index 000000000..adfaf84b0 --- /dev/null +++ b/workbench/src/plugin_main.c @@ -0,0 +1,142 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for plugin setup/registration. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#include "sidebar.h" +#include "menu.h" +#include "popup_menu.h" + +GeanyPlugin *geany_plugin; +GeanyData *geany_data; + +/* Callback function for document open */ +static void plugin_workbench_on_doc_open(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GeanyDocument * doc, + G_GNUC_UNUSED gpointer user_data) +{ + WB_PROJECT *project; + + g_return_if_fail(doc != NULL && doc->file_name != NULL); + + project = workbench_file_is_included(wb_globals.opened_wb, doc->file_name); + if (project != NULL) + { + wb_project_remove_single_tm_file(project, doc->file_name); + } +} + + +/* Callback function for document close */ +static void plugin_workbench_on_doc_close(G_GNUC_UNUSED GObject * obj, GeanyDocument * doc, + G_GNUC_UNUSED gpointer user_data) +{ + WB_PROJECT *project; + + g_return_if_fail(doc != NULL); + + if (doc->file_name == NULL) + { + return; + } + + /* tags of open files managed by geany - when the file gets closed, + * we should take care of it */ + project = workbench_file_is_included(wb_globals.opened_wb, doc->file_name); + if (project != NULL) + { + wb_project_add_single_tm_file(project, doc->file_name); + } +} + + +/* Initialize plugin */ +static gboolean plugin_workbench_init(GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata) +{ + /* Init/Update globals */ + workbench_globals_init(); + wb_globals.geany_plugin = plugin; + geany_plugin = plugin; + geany_data = plugin->geany_data; + + menu_init(); + sidebar_init(); + popup_menu_init(); + + /* At start there is no workbench open: + deactive save and close menu item and sidebar */ + menu_set_context(MENU_CONTEXT_WB_CLOSED); + sidebar_show_intro_message(_("Create or open a workbench\nusing the workbench menu."), FALSE); + + return TRUE; +} + + +/* Cleanup plugin */ +static void plugin_workbench_cleanup(G_GNUC_UNUSED GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata) +{ + menu_cleanup(); + sidebar_cleanup(); +} + + +/* Show help */ +static void plugin_workbench_help (G_GNUC_UNUSED GeanyPlugin *plugin, G_GNUC_UNUSED gpointer pdata) +{ + utils_open_browser("http://plugins.geany.org/workbench.html"); +} + + +static PluginCallback plugin_workbench_callbacks[] = { + {"document-open", (GCallback) &plugin_workbench_on_doc_open, TRUE, NULL}, + {"document-close", (GCallback) &plugin_workbench_on_doc_close, TRUE, NULL}, + {NULL, NULL, FALSE, NULL} +}; + + +/* Load module */ +G_MODULE_EXPORT +void geany_load_module(GeanyPlugin *plugin) +{ + /* Setup translation */ + main_locale_init(LOCALEDIR, GETTEXT_PACKAGE); + + /* Set metadata */ + plugin->info->name = _("Workbench"); + plugin->info->description = _("Manage and customize multiple projects."); + plugin->info->version = "1.0"; + plugin->info->author = "LarsGit223"; + + /* Set functions */ + plugin->funcs->init = plugin_workbench_init; + plugin->funcs->cleanup = plugin_workbench_cleanup; + plugin->funcs->help = plugin_workbench_help; + plugin->funcs->callbacks = plugin_workbench_callbacks; + + /* Register! */ + GEANY_PLUGIN_REGISTER(plugin, 225); +} diff --git a/workbench/src/popup_menu.c b/workbench/src/popup_menu.c new file mode 100644 index 000000000..070f70810 --- /dev/null +++ b/workbench/src/popup_menu.c @@ -0,0 +1,468 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the popup menu. + */ +#include +#include +#include + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "wb_globals.h" +#include "dialogs.h" +#include "sidebar.h" +#include "popup_menu.h" + +static struct +{ + GtkWidget *widget; + + GtkWidget *add_project; + GtkWidget *save_project; + GtkWidget *remove_project; + GtkWidget *fold_unfold_project; + GtkWidget *add_directory; + GtkWidget *remove_directory; + GtkWidget *rescan_directory; + GtkWidget *directory_settings; + GtkWidget *fold_unfold_directory; + GtkWidget *expand_all; + GtkWidget *collapse_all; + GtkWidget *add_wb_bookmark; + GtkWidget *add_prj_bookmark; + GtkWidget *remove_bookmark; +} s_popup_menu; + + +/** Show the popup menu. + * + * The function shows the popup menu. The value of context decides which popup menu items + * are enabled and which are disabled. + * + * @param context The context/situation in which the popup menu was called + * @param event Button event. + * + **/ +void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) +{ + switch (context) + { + case POPUP_CONTEXT_PROJECT: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); + break; + case POPUP_CONTEXT_DIRECTORY: + case POPUP_CONTEXT_FOLDER: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); + break; + case POPUP_CONTEXT_FILE: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); + break; + case POPUP_CONTEXT_BACKGROUND: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); + break; + case POPUP_CONTEXT_WB_BOOKMARK: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, TRUE); + break; + case POPUP_CONTEXT_PRJ_BOOKMARK: + gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_project, TRUE); + gtk_widget_set_sensitive (s_popup_menu.add_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.rescan_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.directory_settings, FALSE); + gtk_widget_set_sensitive (s_popup_menu.fold_unfold_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_wb_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.add_prj_bookmark, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, TRUE); + break; + } + gtk_menu_popup(GTK_MENU(s_popup_menu.widget), NULL, NULL, NULL, NULL, + event->button, event->time); +} + + +/* Handle popup menu item "Add project" */ +static void popup_menu_on_add_project(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *filename; + + filename = dialogs_add_project(); + if (filename == NULL || wb_globals.opened_wb == NULL) + { + return; + } + + if (workbench_add_project(wb_globals.opened_wb, filename)) + { + sidebar_update(SIDEBAR_CONTEXT_PROJECT_ADDED, NULL); + } + else + { + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("Could not add project file: %s"), filename); + } + g_free(filename); +} + + +/* Handle popup menu item "Save project" */ +static void popup_menu_on_save_project(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GError *error = NULL; + WB_PROJECT *project; + + project = sidebar_file_view_get_selected_project(NULL); + if (project != NULL && wb_globals.opened_wb != NULL) + { + if (wb_project_save(project, &error)) + { + SIDEBAR_CONTEXT context; + + memset(&context, 0, sizeof(context)); + context.project = project; + sidebar_update(SIDEBAR_CONTEXT_PROJECT_SAVED, &context); + } + } +} + + +/* Handle popup menu item "Remove project" */ +static void popup_menu_on_remove_project(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + WB_PROJECT *project; + + project = sidebar_file_view_get_selected_project(NULL); + if (project != NULL && wb_globals.opened_wb != NULL) + { + if (workbench_remove_project_with_address(wb_globals.opened_wb, project)) + { + SIDEBAR_CONTEXT context; + + memset(&context, 0, sizeof(context)); + context.project = project; + sidebar_update(SIDEBAR_CONTEXT_PROJECT_REMOVED, &context); + } + } +} + + +/* Handle popup menu item "Expand all" */ +static void popup_menu_on_expand_all(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + sidebar_expand_all(); +} + + +/* Handle popup menu item "Collapse all" */ +static void popup_menu_on_collapse_all(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + sidebar_collapse_all(); +} + + +/* Handle popup menu item "Fold/unfold project" */ +static void popup_menu_on_fold_unfold_project(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + sidebar_toggle_selected_project_expansion(); +} + + +/* Handle popup menu item "Add directory" */ +static void popup_menu_on_add_directory(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *dirname; + WB_PROJECT *project; + + project = sidebar_file_view_get_selected_project(NULL); + if (project != NULL) + { + dirname = dialogs_add_directory(project); + if (dirname != NULL) + { + SIDEBAR_CONTEXT context; + + memset(&context, 0, sizeof(context)); + context.project = project; + wb_project_add_directory(project, dirname); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_ADDED, &context); + g_free(dirname); + } + } +} + + +/* Handle popup menu item "Remove directory" */ +static void popup_menu_on_remove_directory(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.project != NULL && context.directory != NULL) + { + wb_project_remove_directory(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_REMOVED, &context); + } +} + + +/* Handle popup menu item "Rescan directory" */ +static void popup_menu_on_rescan_directory(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.project != NULL && context.directory != NULL) + { + wb_project_dir_rescan(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_RESCANNED, &context); + } +} + + +/* Handle popup menu item "Directory settings" */ +static void popup_menu_on_directory_settings(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.project != NULL && context.directory != NULL) + { + if (dialogs_directory_settings(context.directory)) + { + wb_project_set_modified(context.project, TRUE); + wb_project_dir_rescan(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_SETTINGS_CHANGED, &context); + } + } +} + + +/* Handle popup menu item "Directory settings" */ +static void popup_menu_on_fold_unfold_directory(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + sidebar_toggle_selected_project_dir_expansion(); +} + + +/* Handle popup menu item "Add to workbench bookmarks" */ +static void popup_menu_on_add_to_workbench_bookmarks(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.file != NULL) + { + workbench_add_bookmark(wb_globals.opened_wb, context.file); + sidebar_update(SIDEBAR_CONTEXT_WB_BOOKMARK_ADDED, &context); + } +} + + +/* Handle popup menu item "Add to project bookmarks" */ +static void popup_menu_on_add_to_project_bookmarks(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.project != NULL && context.file != NULL) + { + wb_project_add_bookmark(context.project, context.file); + sidebar_update(SIDEBAR_CONTEXT_PRJ_BOOKMARK_ADDED, &context); + } +} + + +/* Handle popup menu item "Remove from bookmarks" */ +static void popup_menu_on_remove_from_bookmarks(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context) + && context.wb_bookmark != NULL) + { + workbench_remove_bookmark(wb_globals.opened_wb, context.wb_bookmark); + sidebar_update(SIDEBAR_CONTEXT_WB_BOOKMARK_REMOVED, &context); + } + if (sidebar_file_view_get_selected_context(&context) + && context.project != NULL && context.prj_bookmark != NULL) + { + wb_project_remove_bookmark(context.project, context.prj_bookmark); + sidebar_update(SIDEBAR_CONTEXT_PRJ_BOOKMARK_REMOVED, &context); + } +} + + +/** Setup/Initialize the popup menu. + * + **/ +void popup_menu_init(void) +{ + GtkWidget *item; + + s_popup_menu.widget = gtk_menu_new(); + + item = gtk_menu_item_new_with_mnemonic(_("_Add project...")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_add_project), NULL); + s_popup_menu.add_project = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Save project")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_save_project), NULL); + s_popup_menu.save_project = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Remove project")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_remove_project), NULL); + s_popup_menu.remove_project = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Fold/unfold project")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_fold_unfold_project), NULL); + s_popup_menu.fold_unfold_project = item; + + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + + item = gtk_menu_item_new_with_mnemonic(_("_Add directory...")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_add_directory), NULL); + s_popup_menu.add_directory = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Remove directory")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_remove_directory), NULL); + s_popup_menu.remove_directory = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Rescan directory")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_rescan_directory), NULL); + s_popup_menu.rescan_directory = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Directory settings")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_directory_settings), NULL); + s_popup_menu.directory_settings = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Fold/unfold directory")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_fold_unfold_directory), NULL); + s_popup_menu.fold_unfold_directory = item; + + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + + item = gtk_menu_item_new_with_mnemonic(_("_Expand all")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_expand_all), NULL); + s_popup_menu.expand_all = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Collapse all")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_collapse_all), NULL); + s_popup_menu.collapse_all = item; + + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + + item = gtk_menu_item_new_with_mnemonic(_("_Add to Workbench Bookmarks")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_add_to_workbench_bookmarks), NULL); + s_popup_menu.add_wb_bookmark = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Add to Project Bookmarks")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_add_to_project_bookmarks), NULL); + s_popup_menu.add_prj_bookmark = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Remove from Bookmarks")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_remove_from_bookmarks), NULL); + s_popup_menu.remove_bookmark = item; +} diff --git a/workbench/src/popup_menu.h b/workbench/src/popup_menu.h new file mode 100644 index 000000000..cb8b52cbd --- /dev/null +++ b/workbench/src/popup_menu.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __POPUP_MENU_H__ +#define __POPUP_MENU_H__ + +#include + +typedef enum +{ + POPUP_CONTEXT_PROJECT, + POPUP_CONTEXT_DIRECTORY, + POPUP_CONTEXT_FOLDER, + POPUP_CONTEXT_FILE, + POPUP_CONTEXT_BACKGROUND, + POPUP_CONTEXT_WB_BOOKMARK, + POPUP_CONTEXT_PRJ_BOOKMARK, +}POPUP_CONTEXT; + +void popup_menu_init(void); +void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event); + +#endif diff --git a/workbench/src/sidebar.c b/workbench/src/sidebar.c new file mode 100644 index 000000000..1170c24f1 --- /dev/null +++ b/workbench/src/sidebar.c @@ -0,0 +1,1152 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for setup and control of the sidebar. + */ +#include +#include +#include + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +#include "wb_globals.h" +#include + +#include "sidebar.h" +#include "popup_menu.h" +#include "utils.h" + +enum +{ + DATA_ID_UNSET = 0, + DATA_ID_WB_BOOKMARK, + DATA_ID_PROJECT, + DATA_ID_PRJ_BOOKMARK, + DATA_ID_DIRECTORY, + DATA_ID_NO_DIRS, + DATA_ID_FOLDER, + DATA_ID_FILE, +}; + +enum +{ + FILEVIEW_COLUMN_ICON, + FILEVIEW_COLUMN_NAME, + FILEVIEW_COLUMN_DATA_ID, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, + FILEVIEW_N_COLUMNS, +}; + +typedef enum +{ + MATCH_FULL, + MATCH_PREFIX, + MATCH_PATTERN +} MatchType; + +typedef struct +{ + GeanyProject *project; + GPtrArray *expanded_paths; +} ExpandData; + +typedef struct SIDEBAR +{ + GtkWidget *file_view_vbox; + GtkWidget *file_view; + GtkTreeStore *file_store; + GtkWidget *file_view_label; +}SIDEBAR; +static SIDEBAR sidebar = {NULL, NULL, NULL, NULL}; + +/* Remove all child nodes below parent */ +static void sidebar_remove_children(GtkTreeIter *parent) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_model_iter_children (model, &iter, parent)) + { + while (gtk_tree_store_remove (sidebar.file_store, &iter)) {} + } +} + + +/* Create a branch for a folder */ +static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList *leaf_list, GtkTreeIter *parent) +{ + GSList *dir_list = NULL; + GSList *file_list = NULL; + GSList *elem; + gchar **path_arr; + + foreach_slist (elem, leaf_list) + { + if (elem->data == NULL) + { + continue; + } + path_arr = elem->data; + + if (path_arr[level+1] != NULL) + { + dir_list = g_slist_prepend(dir_list, path_arr); + } + else + { + file_list = g_slist_prepend(file_list, path_arr); + } + } + + foreach_slist (elem, file_list) + { + GtkTreeIter iter; + gchar *part, *full; + GIcon *icon = NULL; + + path_arr = elem->data; + gchar *content_type = g_content_type_guess(path_arr[level], NULL, 0, NULL); + + if (content_type) + { + icon = g_content_type_get_icon(content_type); + if (icon) + { + GtkIconInfo *icon_info; + + icon_info = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), icon, 16, 0); + if (!icon_info) + { + g_object_unref(icon); + icon = NULL; + } + else + gtk_icon_info_free(icon_info); + } + g_free(content_type); + } + + /* Build full absolute file name to use it on row activate to + open the file. Will be assigned as data pointer, see below. */ + part = g_build_filenamev(path_arr); + full = g_build_filename(abs_base_dir, part, NULL); + g_free(part); + + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, 0, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, path_arr[level], + FILEVIEW_COLUMN_DATA_ID, DATA_ID_FILE, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, full, + -1); + + if (icon) + { + g_object_unref(icon); + } + } + + if (dir_list) + { + GSList *tmp_list = NULL; + GtkTreeIter iter; + gchar *last_dir_name; + GIcon *icon_dir = g_icon_new_for_string("folder", NULL); + + path_arr = dir_list->data; + last_dir_name = path_arr[level]; + + foreach_slist (elem, dir_list) + { + gboolean dir_changed; + + path_arr = (gchar **) elem->data; + dir_changed = g_strcmp0(last_dir_name, path_arr[level]) != 0; + + if (dir_changed) + { + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, 0, + FILEVIEW_COLUMN_ICON, icon_dir, + FILEVIEW_COLUMN_NAME, last_dir_name, + FILEVIEW_COLUMN_DATA_ID, DATA_ID_FOLDER, + -1); + + sidebar_create_branch(level+1, abs_base_dir, tmp_list, &iter); + + g_slist_free(tmp_list); + tmp_list = NULL; + last_dir_name = path_arr[level]; + } + + tmp_list = g_slist_prepend(tmp_list, path_arr); + } + + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, 0, + FILEVIEW_COLUMN_ICON, icon_dir, + FILEVIEW_COLUMN_NAME, last_dir_name, + FILEVIEW_COLUMN_DATA_ID, DATA_ID_FOLDER, + -1); + + sidebar_create_branch(level+1, abs_base_dir, tmp_list, &iter); + + g_slist_free(tmp_list); + g_slist_free(dir_list); + if (icon_dir != NULL) + { + g_object_unref(icon_dir); + } + } + + g_slist_free(file_list); +} + + +/* Reverse strcmp */ +static int rev_strcmp(const char *str1, const char *str2) +{ + return strcmp(str2, str1); +} + + +/* Insert given directory/folder into the sidebar file tree */ +static void sidebar_insert_project_directory(WB_PROJECT *prj, WB_PROJECT_DIR *directory, GtkTreeIter *parent) +{ + GSList *lst = NULL; + GSList *path_list = NULL; + GSList *elem; + GHashTableIter iter; + gpointer key, value; + gchar *abs_base_dir; + + g_hash_table_iter_init(&iter, wb_project_dir_get_file_table(directory)); + abs_base_dir = get_combined_path(wb_project_get_filename(prj), wb_project_dir_get_base_dir(directory)); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + gchar *path = get_relative_path(abs_base_dir, key); + lst = g_slist_prepend(lst, path); + } + /* sort in reverse order so we can prepend nodes to the tree store - + * the store behaves as a linked list and prepending is faster */ + lst = g_slist_sort(lst, (GCompareFunc) rev_strcmp); + + foreach_slist (elem, lst) + { + gchar **path_split; + + path_split = g_strsplit_set(elem->data, "/\\", 0); + path_list = g_slist_prepend(path_list, path_split); + } + + if (path_list != NULL) + sidebar_create_branch(0, abs_base_dir, path_list, parent); + + g_slist_free_full(lst, g_free); + g_slist_free_full(path_list, (GDestroyNotify) g_strfreev); +} + + +/* Insert all directories (WB_PROJECT_DIRs) into the sidebar file tree */ +static void sidebar_insert_project_directories (WB_PROJECT *project, GtkTreeIter *parent, gint *position) +{ + GtkTreeIter iter; + GIcon *icon; + GSList *elem, *dirs; + + if (project == NULL) + { + return; + } + + dirs = wb_project_get_directories(project); + if (dirs != NULL) + { + icon = g_icon_new_for_string("workbench-dir", NULL); + + foreach_slist (elem, dirs) + { + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, *position, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, wb_project_dir_get_name(elem->data), + FILEVIEW_COLUMN_DATA_ID, DATA_ID_DIRECTORY, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, elem->data, + -1); + (*position)++; + sidebar_insert_project_directory(project, elem->data, &iter); + } + } + else + { + icon = g_icon_new_for_string("workbench-nodirs", NULL); + + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, *position, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, _("No directories"), + FILEVIEW_COLUMN_DATA_ID, DATA_ID_NO_DIRS, + -1); + (*position)++; + } + if (icon != NULL) + { + g_object_unref(icon); + } +} + + +/* Get the GtkTreeIter for project prj */ +static gboolean sidebar_get_project_iter(WB_PROJECT *prj, GtkTreeIter *iter) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_model_get_iter_first (model, iter)) + { + WB_PROJECT *current; + + do + { + gtk_tree_model_get(model, iter, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, ¤t, -1); + if (current == prj) + { + return TRUE; + } + }while (gtk_tree_model_iter_next(model, iter)); + } + return FALSE; +} + + +/* Remove all rows from the side bar tree with the given data id */ +static void sidebar_remove_nodes_with_data_id(guint toremove, GtkTreeIter *start) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gboolean has_next; + guint dataid; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(sidebar.file_view)); + if (start == NULL) + { + if (!gtk_tree_model_get_iter_first(model, &iter)) + { + return; + } + } + else + { + iter = *start; + } + + do + { + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_DATA_ID, &dataid, -1); + if (dataid == toremove) + { + has_next = gtk_tree_store_remove(sidebar.file_store, &iter); + } + else + { + has_next = gtk_tree_model_iter_next(model, &iter); + } + } + while (has_next); +} + + +/* Insert all project bookmarks into the sidebar file tree */ +static void sidebar_insert_project_bookmarks(WB_PROJECT *project, GtkTreeIter *parent, gint *position) +{ + GIcon *icon; + guint index, max; + GtkTreeIter iter; + + if (project == NULL) + return; + + max = wb_project_get_bookmarks_count(project); + if (max == 0) + return; + + icon = g_icon_new_for_string("workbench-bookmark", NULL); + for (index = 0 ; index < max ; index++) + { + gchar *file, *name; + + file = wb_project_get_bookmark_at_index(project, index); + name = get_any_relative_path(wb_project_get_filename(project), file); + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, *position, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, name, + FILEVIEW_COLUMN_DATA_ID, DATA_ID_PRJ_BOOKMARK, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, file, + -1); + (*position)++; + } + if (icon != NULL) + { + g_object_unref(icon); + } +} + + +/* Update the sidebar for a project only */ +static void sidebar_update_project(WB_PROJECT *project, gboolean title_only) +{ + GtkTreeIter iter; + + if (wb_globals.opened_wb == NULL) + return; + + if (sidebar_get_project_iter(project, &iter)) + { + /* Update the title */ + GString *name = g_string_new(wb_project_get_name(project)); + if (wb_project_is_modified(project)) + { + g_string_append_c(name, '*'); + } + + gtk_tree_store_set(sidebar.file_store, &iter, + FILEVIEW_COLUMN_NAME, name->str, + -1); + g_string_free(name, TRUE); + + /* Update children/content to? */ + if (!title_only) + { + gint position = 0; + sidebar_remove_children(&iter); + sidebar_insert_project_bookmarks(project, &iter, &position); + sidebar_insert_project_directories(project, &iter, &position); + } + } +} + + +/* Insert all projects into the sidebar file tree */ +static void sidebar_insert_all_projects(GtkTreeIter *iter, gint *position) +{ + GIcon *icon_good, *icon_bad, *icon; + guint index, max; + + if (wb_globals.opened_wb == NULL) + return; + + icon_good = g_icon_new_for_string("workbench-project", NULL); + icon_bad = g_icon_new_for_string("workbench-project-error", NULL); + + max = workbench_get_project_count(wb_globals.opened_wb); + for (index = 0 ; index < max ; index++) + { + gint child_position; + WB_PROJECT *project; + + project = workbench_get_project_at_index(wb_globals.opened_wb, index); + if (workbench_get_project_status_at_index(wb_globals.opened_wb, index) + == + PROJECT_ENTRY_STATUS_OK) + { + icon = icon_good; + } + else + { + icon = icon_bad; + } + + GString *name = g_string_new(wb_project_get_name(project)); + if (wb_project_is_modified(project)) + { + g_string_append_c(name, '*'); + } + + gtk_tree_store_insert_with_values(sidebar.file_store, iter, NULL, *position, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, name->str, + FILEVIEW_COLUMN_DATA_ID, DATA_ID_PROJECT, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, project, + -1); + g_string_free(name, TRUE); + + child_position = 0; + /* Not required here as we build a completely new tree + sidebar_remove_children(&iter); */ + sidebar_insert_project_bookmarks(project, iter, &child_position); + sidebar_insert_project_directories(project, iter, &child_position); + } + gtk_tree_view_expand_all(GTK_TREE_VIEW(sidebar.file_view)); + + if (icon_good != NULL) + { + g_object_unref(icon_good); + } + if (icon_bad != NULL) + { + g_object_unref(icon_bad); + } +} + + +/* Insert all workbench bookmarks into the sidebar file tree */ +static void sidebar_insert_workbench_bookmarks(WORKBENCH *workbench, GtkTreeIter *iter, gint *position) +{ + GIcon *icon; + guint index, max; + + if (workbench == NULL) + { + return; + } + + sidebar_remove_nodes_with_data_id(DATA_ID_WB_BOOKMARK, NULL); + + max = workbench_get_bookmarks_count(workbench); + if (max == 0) + { + return; + } + + icon = g_icon_new_for_string("workbench-bookmark", NULL); + for (index = 0 ; index < max ; index++) + { + gchar *file, *name; + + file = workbench_get_bookmark_at_index(workbench, index); + name = get_any_relative_path(workbench_get_filename(workbench), file); + gtk_tree_store_insert_with_values(sidebar.file_store, iter, NULL, *position, + FILEVIEW_COLUMN_ICON, icon, + FILEVIEW_COLUMN_NAME, name, + FILEVIEW_COLUMN_DATA_ID, DATA_ID_WB_BOOKMARK, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, file, + -1); + (*position)++; + } + + gtk_tree_view_expand_all(GTK_TREE_VIEW(sidebar.file_view)); + if (icon != NULL) + { + g_object_unref(icon); + } +} + + +/* Reset/Clear/empty the sidebar file tree */ +static void sidebar_reset_tree_store(void) +{ + gtk_tree_store_clear(sidebar.file_store); +} + + +/* Update the workbench part of the sidebar */ +static void sidebar_update_workbench(GtkTreeIter *iter, gint *position) +{ + guint count; + + if (wb_globals.opened_wb == NULL) + { + gtk_label_set_text (GTK_LABEL(sidebar.file_view_label), _("No workbench opened.")); + gtk_tree_store_clear(sidebar.file_store); + sidebar_show_intro_message(_("Create or open a workbench\nusing the workbench menu."), FALSE); + sidebar_deactivate(); + } + else + { + gint length; + gchar text[200]; + + count = workbench_get_project_count(wb_globals.opened_wb); + length = g_snprintf(text, sizeof(text), _("%s: %u Projects"), + workbench_get_name(wb_globals.opened_wb), count); + if (length < (gint)(sizeof(text)-1) && workbench_is_modified(wb_globals.opened_wb)) + { + text [length] = '*'; + text [length+1] = '\0'; + } + gtk_label_set_text (GTK_LABEL(sidebar.file_view_label), text); + if (count == 0) + { + gtk_tree_store_clear(sidebar.file_store); + sidebar_show_intro_message(_("Add a project\nusing the context menu."), TRUE); + } + else + { + /* Add/show workbench bookmarks if any */ + if (iter != NULL) + { + sidebar_insert_workbench_bookmarks(wb_globals.opened_wb, iter, position); + } + } + } +} + + +/** Update the sidebar. + * + * Update the sidebar according to the given situation/event @a event + * and data in @a context. + * + * @param event Reason for the sidebar update + * @param context Data, e.g. actually selected project... + * + **/ +void sidebar_update (SIDEBAR_EVENT event, SIDEBAR_CONTEXT *context) +{ + GtkTreeIter iter; + gint position = 0; + + switch (event) + { + case SIDEBAR_CONTEXT_WB_CREATED: + case SIDEBAR_CONTEXT_WB_OPENED: + case SIDEBAR_CONTEXT_PROJECT_ADDED: + case SIDEBAR_CONTEXT_PROJECT_REMOVED: + sidebar_reset_tree_store(); + sidebar_update_workbench(&iter, &position); + sidebar_insert_all_projects(&iter, &position); + sidebar_activate(); + break; + case SIDEBAR_CONTEXT_WB_SAVED: + case SIDEBAR_CONTEXT_WB_SETTINGS_CHANGED: + case SIDEBAR_CONTEXT_WB_CLOSED: + sidebar_update_workbench(NULL, &position); + break; + case SIDEBAR_CONTEXT_PROJECT_SAVED: + if (context != NULL && context->project != NULL) + { + sidebar_update_project(context->project, TRUE); + } + break; + case SIDEBAR_CONTEXT_DIRECTORY_ADDED: + case SIDEBAR_CONTEXT_DIRECTORY_REMOVED: + case SIDEBAR_CONTEXT_DIRECTORY_RESCANNED: + case SIDEBAR_CONTEXT_DIRECTORY_SETTINGS_CHANGED: + case SIDEBAR_CONTEXT_PRJ_BOOKMARK_ADDED: + case SIDEBAR_CONTEXT_PRJ_BOOKMARK_REMOVED: + if (context != NULL && context->project != NULL) + { + sidebar_update_project(context->project, FALSE); + } + break; + case SIDEBAR_CONTEXT_WB_BOOKMARK_ADDED: + case SIDEBAR_CONTEXT_WB_BOOKMARK_REMOVED: + { + GtkTreeIter first; + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_model_get_iter_first (model, &first)) + { + sidebar_update_workbench(&first, &position); + } + } + break; + } +} + + +/* Callback function for clicking on a sidebar item */ +static void sidebar_filew_view_on_row_activated (GtkTreeView *treeview, + GtkTreePath *path, G_GNUC_UNUSED GtkTreeViewColumn *col, G_GNUC_UNUSED gpointer userdata) +{ + gchar *info; + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model(treeview); + + if (gtk_tree_model_get_iter(model, &iter, path)) + { + guint dataid; + gchar *name; + void *address; + + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_NAME, &name, -1); + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_DATA_ID, &dataid, -1); + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, &address, -1); + + switch (dataid) + { + case DATA_ID_PROJECT: + info = wb_project_get_info((WB_PROJECT *)address); + if (workbench_get_project_status_by_address(wb_globals.opened_wb, address) + == + PROJECT_ENTRY_STATUS_OK) + { + dialogs_show_msgbox(GTK_MESSAGE_INFO, "%s", info); + } + else + { + dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("%s\nProject file not found!"), info); + } + g_free(info); + break; + case DATA_ID_DIRECTORY: + info = wb_project_dir_get_info((WB_PROJECT_DIR *)address); + dialogs_show_msgbox(GTK_MESSAGE_INFO, "%s", info); + break; + case DATA_ID_WB_BOOKMARK: + case DATA_ID_PRJ_BOOKMARK: + case DATA_ID_FILE: + document_open_file((char *)address, FALSE, NULL, NULL); + break; + case DATA_ID_NO_DIRS: + dialogs_show_msgbox(GTK_MESSAGE_INFO, _("This project has no directories. Directories can be added to a project using the context menu.")); + break; + default: + break; + } + + g_free(name); + } +} + + +/* Callbac function for button release, used for the popup menu */ +static gboolean sidebar_file_view_on_button_release(G_GNUC_UNUSED GtkWidget * widget, GdkEventButton * event, + G_GNUC_UNUSED gpointer user_data) +{ + if (event->button == 3) + { + SIDEBAR_CONTEXT context; + POPUP_CONTEXT popup_context = POPUP_CONTEXT_BACKGROUND; + + if (sidebar_file_view_get_selected_context(&context)) + { + if (context.file != NULL) + { + popup_context = POPUP_CONTEXT_FILE; + } + else if (context.folder != NULL) + { + popup_context = POPUP_CONTEXT_FOLDER; + } + else if (context.directory != NULL) + { + popup_context = POPUP_CONTEXT_DIRECTORY; + } + else if (context.prj_bookmark != NULL) + { + popup_context = POPUP_CONTEXT_PRJ_BOOKMARK; + } + else if (context.project != NULL) + { + popup_context = POPUP_CONTEXT_PROJECT; + } + else if (context.wb_bookmark != NULL) + { + popup_context = POPUP_CONTEXT_WB_BOOKMARK; + } + } + popup_menu_show(popup_context, event); + + return TRUE; + } + + return FALSE; +} + + +/** Get the selected project and the path to it. + * + * Get the selected project and return a pointer to it. Also if @a path is not NULL then + * the path to the row containing the project is returned in *path. + * + * @param path @nullable Location to return the path or @c NULL + * + **/ +WB_PROJECT *sidebar_file_view_get_selected_project(GtkTreePath **path) +{ + gboolean has_parent; + guint dataid; + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter current, parent; + WB_PROJECT *project; + + if (path != NULL) + { + *path = NULL; + } + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_selection_get_selected(treesel, &model, ¤t)) + { + do + { + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_DATA_ID, &dataid, -1); + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, &project, -1); + if (dataid == DATA_ID_PROJECT && project != NULL) + { + if (path != NULL) + { + *path = gtk_tree_model_get_path(model, ¤t); + } + return project; + } + has_parent = gtk_tree_model_iter_parent(model, + &parent, ¤t); + current = parent; + }while (has_parent); + } + return NULL; +} + + +/** Get the selected project directory and the path to it. + * + * Get the selected project directory and return a pointer to it. Also if @a path is not NULL then + * the path to the row containing the project is returned in *path. + * + * @param path @nullable Location to return the path or @c NULL + * + **/ +static WB_PROJECT_DIR *sidebar_file_view_get_selected_project_dir(GtkTreePath **path) +{ + gboolean has_parent; + guint dataid; + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter current, parent; + WB_PROJECT_DIR *directory; + + if (path != NULL) + { + *path = NULL; + } + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_selection_get_selected(treesel, &model, ¤t)) + { + do + { + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_DATA_ID, &dataid, -1); + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, &directory, -1); + if (dataid == DATA_ID_DIRECTORY && directory != NULL) + { + if (path != NULL) + { + *path = gtk_tree_model_get_path(model, ¤t); + } + return directory; + } + has_parent = gtk_tree_model_iter_parent(model, + &parent, ¤t); + current = parent; + }while (has_parent); + } + return NULL; +} + + +/** Get data corresponding to the current selected tree view selection. + * + * The function collects all data corresponding to the current selection and stores it in + * @a context. This is e.g. the selected file and the directory and project to which it + * belongs. + * + * @param context The location to store the selection context data in. + * @return TRUE if anything in the tree is selected, FALSE otherwise. + * + **/ +gboolean sidebar_file_view_get_selected_context(SIDEBAR_CONTEXT *context) +{ + gboolean has_parent; + guint dataid; + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter current, parent; + gpointer data; + + if (context == NULL) + { + return FALSE; + } + memset (context, 0, sizeof(*context)); + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sidebar.file_view)); + if (gtk_tree_selection_get_selected(treesel, &model, ¤t)) + { + /* Search through the parents upwards until we find the project node. + Save everthing that's interesting in callers variables... */ + do + { + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_DATA_ID, &dataid, -1); + gtk_tree_model_get(model, ¤t, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, &data, -1); + if (data != NULL) + { + switch (dataid) + { + case DATA_ID_WB_BOOKMARK: + context->wb_bookmark = data; + break; + case DATA_ID_PROJECT: + context->project = data; + break; + case DATA_ID_PRJ_BOOKMARK: + context->prj_bookmark = data; + break; + case DATA_ID_DIRECTORY: + context->directory = data; + break; + case DATA_ID_NO_DIRS: + /* Has not got any data. */ + break; + case DATA_ID_FOLDER: + context->folder = data; + break; + case DATA_ID_FILE: + context->file = data; + break; + } + } + + has_parent = gtk_tree_model_iter_parent(model, + &parent, ¤t); + current = parent; + }while (has_parent); + + return TRUE; + } + return FALSE; +} + + +/** Setup the sidebar. + * + **/ +void sidebar_init(void) +{ + GtkWidget *scrollwin; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *sel; + GList *focus_chain = NULL; + + sidebar.file_view_vbox = gtk_vbox_new(FALSE, 0); + + /**** label ****/ + sidebar.file_view_label = gtk_label_new (_("No workbench opened.")); + gtk_box_pack_start(GTK_BOX(sidebar.file_view_vbox), sidebar.file_view_label, FALSE, FALSE, 0); + + /**** tree view ****/ + + sidebar.file_view = gtk_tree_view_new(); + g_signal_connect(sidebar.file_view, "row-activated", (GCallback)sidebar_filew_view_on_row_activated, NULL); + + sidebar.file_store = gtk_tree_store_new(FILEVIEW_N_COLUMNS, G_TYPE_ICON, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_POINTER); + gtk_tree_view_set_model(GTK_TREE_VIEW(sidebar.file_view), GTK_TREE_MODEL(sidebar.file_store)); + + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new(); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_add_attribute(column, renderer, "gicon", FILEVIEW_COLUMN_ICON); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_add_attribute(column, renderer, "text", FILEVIEW_COLUMN_NAME); + + gtk_tree_view_append_column(GTK_TREE_VIEW(sidebar.file_view), column); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(sidebar.file_view), FALSE); + gtk_tree_view_set_enable_search(GTK_TREE_VIEW(sidebar.file_view), TRUE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(sidebar.file_view), FILEVIEW_COLUMN_NAME); + + ui_widget_modify_font_from_string(sidebar.file_view, + wb_globals.geany_plugin->geany_data->interface_prefs->tagbar_font); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sidebar.file_view)); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(sidebar.file_view), "button-release-event", + G_CALLBACK(sidebar_file_view_on_button_release), NULL); + + sidebar_deactivate(); + + /**** the rest ****/ + focus_chain = g_list_prepend(focus_chain, sidebar.file_view); + gtk_container_set_focus_chain(GTK_CONTAINER(sidebar.file_view_vbox), focus_chain); + g_list_free(focus_chain); + scrollwin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(scrollwin), sidebar.file_view); + gtk_box_pack_start(GTK_BOX(sidebar.file_view_vbox), scrollwin, TRUE, TRUE, 0); + + gtk_widget_show_all(sidebar.file_view_vbox); + gtk_notebook_append_page(GTK_NOTEBOOK(wb_globals.geany_plugin->geany_data->main_widgets->sidebar_notebook), + sidebar.file_view_vbox, gtk_label_new(_("Workbench"))); +} + + +/** Display a text message in the sidebar. + * + * The function displays the text @a msg in the sidebar and eventually deactivates the sidebar + * if @a activate is FALSE. + * + * @param msg The text to display + * @param activate If TRUE the sidebar will be activated, if not it will be deactivated + * + **/ +void sidebar_show_intro_message(const gchar *msg, gboolean activate) +{ + GtkTreeIter iter; + + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, NULL, -1, + FILEVIEW_COLUMN_NAME, msg, -1); + if (activate) + { + sidebar_activate(); + } + else + { + sidebar_deactivate(); + } +} + + +/** Activate the sidebar. + * + **/ +void sidebar_activate(void) +{ + gtk_widget_set_sensitive(sidebar.file_view_vbox, TRUE); +} + + +/** Deactivate the sidebar. + * + **/ +void sidebar_deactivate(void) +{ + gtk_widget_set_sensitive(sidebar.file_view_vbox, FALSE); +} + + +/** Cleanup the sidebar. + * + **/ +void sidebar_cleanup(void) +{ + gtk_widget_destroy(sidebar.file_view_vbox); +} + + +/** Expand all rows in the sidebar tree. + * + **/ +void sidebar_expand_all(void) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(sidebar.file_view)); +} + + +/** Collapse all rows in the sidebar tree. + * + **/ +void sidebar_collapse_all(void) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(sidebar.file_view)); +} + + +/** Expand all rows in the sidebar tree for the selected project. + * + **/ +void sidebar_expand_selected_project(void) +{ + GtkTreePath *path; + + sidebar_file_view_get_selected_project(&path); + if (path != NULL) + { + gtk_tree_view_expand_row(GTK_TREE_VIEW(sidebar.file_view), + path, TRUE); + gtk_tree_path_free(path); + } +} + + +/** Collapse all rows in the sidebar tree for the selected project. + * + **/ +void sidebar_collapse_selected_project(void) +{ + GtkTreePath *path; + + sidebar_file_view_get_selected_project(&path); + if (path != NULL) + { + gtk_tree_view_collapse_row(GTK_TREE_VIEW(sidebar.file_view), + path); + gtk_tree_path_free(path); + } +} + + +/** Toggle state of all rows in the sidebar tree for the selected project. + * + * If the project is expanded, then it will be collapsed and vice versa. + * + **/ +void sidebar_toggle_selected_project_expansion(void) +{ + GtkTreePath *path; + + sidebar_file_view_get_selected_project(&path); + if (path != NULL) + { + if (gtk_tree_view_row_expanded + (GTK_TREE_VIEW(sidebar.file_view),path)) + { + gtk_tree_view_collapse_row(GTK_TREE_VIEW(sidebar.file_view), + path); + } + else + { + gtk_tree_view_expand_row (GTK_TREE_VIEW(sidebar.file_view), + path, TRUE); + } + gtk_tree_path_free(path); + } +} + + +/** Toggle state of all rows in the sidebar tree for the selected directory. + * + * If the directory is expanded, then it will be collapsed and vice versa. + * + **/ +void sidebar_toggle_selected_project_dir_expansion (void) +{ + GtkTreePath *path; + + sidebar_file_view_get_selected_project_dir(&path); + if (path != NULL) + { + if (gtk_tree_view_row_expanded + (GTK_TREE_VIEW(sidebar.file_view),path)) + { + gtk_tree_view_collapse_row (GTK_TREE_VIEW(sidebar.file_view), + path); + } + else + { + gtk_tree_view_expand_row (GTK_TREE_VIEW(sidebar.file_view), + path, TRUE); + } + gtk_tree_path_free(path); + } +} diff --git a/workbench/src/sidebar.h b/workbench/src/sidebar.h new file mode 100644 index 000000000..26b6265bb --- /dev/null +++ b/workbench/src/sidebar.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __SIDEBAR_H__ +#define __SIDEBAR_H__ + +#include +#include "wb_project.h" + +typedef struct +{ + WB_PROJECT *project; + WB_PROJECT_DIR *directory; + gchar *folder; + gchar *file; + gchar *wb_bookmark; + gchar *prj_bookmark; +}SIDEBAR_CONTEXT; + +typedef enum +{ + SIDEBAR_CONTEXT_WB_CREATED, + SIDEBAR_CONTEXT_WB_OPENED, + SIDEBAR_CONTEXT_WB_SAVED, + SIDEBAR_CONTEXT_WB_SETTINGS_CHANGED, + SIDEBAR_CONTEXT_WB_CLOSED, + SIDEBAR_CONTEXT_PROJECT_ADDED, + SIDEBAR_CONTEXT_PROJECT_SAVED, + SIDEBAR_CONTEXT_PROJECT_REMOVED, + SIDEBAR_CONTEXT_DIRECTORY_ADDED, + SIDEBAR_CONTEXT_DIRECTORY_REMOVED, + SIDEBAR_CONTEXT_DIRECTORY_RESCANNED, + SIDEBAR_CONTEXT_DIRECTORY_SETTINGS_CHANGED, + SIDEBAR_CONTEXT_WB_BOOKMARK_ADDED, + SIDEBAR_CONTEXT_WB_BOOKMARK_REMOVED, + SIDEBAR_CONTEXT_PRJ_BOOKMARK_ADDED, + SIDEBAR_CONTEXT_PRJ_BOOKMARK_REMOVED, +}SIDEBAR_EVENT; + +void sidebar_init(void); +void sidebar_cleanup(void); + +void sidebar_activate(void); +void sidebar_deactivate(void); + +void sidebar_show_intro_message(const gchar *msg, gboolean activate); + +void sidebar_update(SIDEBAR_EVENT event, SIDEBAR_CONTEXT *context); + +void sidebar_expand_all(void); +void sidebar_collapse_all(void); +void sidebar_expand_selected_project (void); +void sidebar_collapse_selected_project (void); +void sidebar_toggle_selected_project_expansion (void); +void sidebar_toggle_selected_project_dir_expansion (void); + +WB_PROJECT *sidebar_file_view_get_selected_project(GtkTreePath **path); +gboolean sidebar_file_view_get_selected_context(SIDEBAR_CONTEXT *context); + +#endif diff --git a/workbench/src/utils.c b/workbench/src/utils.c new file mode 100644 index 000000000..12b553908 --- /dev/null +++ b/workbench/src/utils.c @@ -0,0 +1,301 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Utility functions. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include "utils.h" + +/** Get the relative path. + * + * The function examines the relative path of @a utf8_descendant in relation to + * @a utf8_parent. + * + * @param utf8_parent Parent directory. + * @param utf8_descendant Sub directory. + * + **/ +gchar *get_relative_path(const gchar *utf8_parent, const gchar *utf8_descendant) +{ + GFile *gf_parent, *gf_descendant; + gchar *locale_parent, *locale_descendant; + gchar *locale_ret, *utf8_ret; + + locale_parent = utils_get_locale_from_utf8(utf8_parent); + locale_descendant = utils_get_locale_from_utf8(utf8_descendant); + gf_parent = g_file_new_for_path(locale_parent); + gf_descendant = g_file_new_for_path(locale_descendant); + + locale_ret = g_file_get_relative_path(gf_parent, gf_descendant); + utf8_ret = utils_get_utf8_from_locale(locale_ret); + + g_object_unref(gf_parent); + g_object_unref(gf_descendant); + g_free(locale_parent); + g_free(locale_descendant); + g_free(locale_ret); + + return utf8_ret; +} + + +/** Check if a string matches a pattern. + * + * The function checks if @a str matches pattern @a patterns. + * + * @param patterns Pattern list. + * @param str String to check + * @return TRUE if str matches the pattern, FALSE otherwise + * + **/ +gboolean patterns_match(GSList *patterns, const gchar *str) +{ + GSList *elem; + foreach_slist (elem, patterns) + { + GPatternSpec *pattern = elem->data; + if (g_pattern_match_string(pattern, str)) + return TRUE; + } + return FALSE; +} + + +/** Get precompiled patterns. + * + * The function builds the precompiled patterns for @a patterns and returns them + * as a list. + * + * @param patterns NULL terminated string array of patterns. + * @return Pointer to GSList of patterns or NULL if patterns == NULL + * + **/ +GSList *get_precompiled_patterns(gchar **patterns) +{ + guint i; + GSList *pattern_list = NULL; + + if (!patterns) + return NULL; + + for (i = 0; patterns[i] != NULL; i++) + { + GPatternSpec *pattern_spec = g_pattern_spec_new(patterns[i]); + pattern_list = g_slist_prepend(pattern_list, pattern_spec); + } + return pattern_list; +} + + +/** Combine an absolute and a relative path. + * + * The function combines the absolute path @a base with the relative path + * @a relative and retunrs it as a string. The caller needs to free the + * string with g_free(). + * + * @param base The absolute path. + * @param relative The relative path. + * @return Combined path or NULL if no memory is available + * + **/ +gchar *get_combined_path(const gchar *base, const gchar *relative) +{ + gchar *basedir, *basedir_end; + const gchar *start; + gchar *result; + gint goback; + + start = relative; + basedir = g_path_get_dirname (base); + if (relative[0] == '.') + { + if (strncmp("..", relative, sizeof("..")-1) == 0) + { + start = &(relative[sizeof("..")-1]); + } + + goback = 0; + while (*start != '\0') + { + if (strncmp("..", &(start[1]), sizeof("..")-1) == 0) + { + start += 1 + (sizeof("..")-1); + goback++; + } + else + { + break; + } + } + + basedir_end = &(basedir[strlen(basedir)]); + while (goback > 0) + { + while (basedir_end > basedir && *basedir_end != G_DIR_SEPARATOR) + { + basedir_end--; + } + if (*basedir_end == G_DIR_SEPARATOR) + { + *basedir_end = '\0'; + } + else + { + break; + } + goback--; + } + } + + result = g_strconcat(basedir, start, NULL); + return result; +} + + +/** Get the relative path. + * + * The function examines the relative path of @a target in relation to + * @a base. It is not required that target is a sub-directory of base. + * + * @param base Base directory. + * @param target Target directory or NULL in case of error. + * + **/ +gchar *get_any_relative_path (const gchar *base, const gchar *target) +{ + guint index = 0, equal, equal_index = 0, base_parts = 0, target_parts = 0, length; + GPtrArray *relative; + gchar *part; + gchar *result = NULL; + gchar **splitv_base; + gchar **splitv_target; + + /* Split up pathes into parts and count them */ + splitv_base = g_strsplit (base, G_DIR_SEPARATOR_S, -1); + index = 0; + while (splitv_base[index] != NULL) + { + if (strlen(splitv_base[index]) > 0) + { + base_parts++; + } + index++; + } + splitv_target = g_strsplit (target, G_DIR_SEPARATOR_S, -1); + index = 0;; + while (splitv_target[index] != NULL) + { + if (strlen(splitv_target[index]) > 0) + { + target_parts++; + } + index++; + } + + /* Count equal dirs */ + equal = 0; + index = 0; + while (splitv_base[index] != NULL && splitv_target[index] != NULL) + { + if (g_strcmp0 (splitv_base[index], splitv_target[index]) == 0) + { + /* We might encounter empty strings! */ + if (strlen(splitv_base[index]) > 0) + { + equal++; + equal_index = index; + } + } + else + { + break; + } + index++; + } + + length = 0; + relative = g_ptr_array_new(); + if (equal < base_parts) + { + /* Go back, add ".." */ + for (index = 0 ; index < (base_parts-equal) ; index++) + { + if (index == 0) + { + g_ptr_array_add(relative, g_strdup("..")); + length += 2; + } + else + { + length += 2 + strlen(G_DIR_SEPARATOR_S); + g_ptr_array_add(relative, g_strdup(G_DIR_SEPARATOR_S)); + g_ptr_array_add(relative, g_strdup("..")); + } + } + + /* Add directories */ + index = equal_index + 1; + while (splitv_target[index] != NULL) + { + if (strlen(splitv_target[index]) > 0) + { + length += strlen(G_DIR_SEPARATOR_S) + + strlen(splitv_target[index]); + g_ptr_array_add(relative, g_strdup(G_DIR_SEPARATOR_S)); + g_ptr_array_add(relative, g_strdup(splitv_target[index])); + } + index++; + } + } + + /* Copy it all together */ + result = g_new(char, length+1); + if (result != NULL) + { + guint strpos = 0; + + for (index = 0 ; index < relative->len ; index++) + { + part = g_ptr_array_index(relative, index); + g_strlcpy (&(result[strpos]), + part, + length+1-strpos); + strpos += strlen(part); + g_free(part); + } + } + else + { + for (index = 0 ; index < relative->len ; index++) + { + part = g_ptr_array_index(relative, index); + g_free(part); + } + result = NULL; + } + g_ptr_array_free(relative, TRUE); + + return result; +} diff --git a/workbench/src/utils.h b/workbench/src/utils.h new file mode 100644 index 000000000..9c7cfcb3c --- /dev/null +++ b/workbench/src/utils.h @@ -0,0 +1,30 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include + +gchar *get_relative_path(const gchar *utf8_parent, const gchar *utf8_descendant); +gboolean patterns_match(GSList *patterns, const gchar *str); +GSList *get_precompiled_patterns(gchar **patterns); +gchar *get_combined_path(const gchar *base, const gchar *relative); +gchar *get_any_relative_path (const gchar *base, const gchar *target); + +#endif diff --git a/workbench/src/wb_globals.c b/workbench/src/wb_globals.c new file mode 100644 index 000000000..5085f6759 --- /dev/null +++ b/workbench/src/wb_globals.c @@ -0,0 +1,30 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wb_globals.h" + +WB_GLOBALS wb_globals; + +void workbench_globals_init(void) +{ + memset(&wb_globals, 0, sizeof(wb_globals)); +} diff --git a/workbench/src/wb_globals.h b/workbench/src/wb_globals.h new file mode 100644 index 000000000..ce96060d5 --- /dev/null +++ b/workbench/src/wb_globals.h @@ -0,0 +1,35 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_GLOBALS_H__ +#define __WB_GLOBALS_H__ + +#include +#include "workbench.h" + +typedef struct +{ + GeanyPlugin *geany_plugin; + WORKBENCH *opened_wb; +}WB_GLOBALS; + +extern WB_GLOBALS wb_globals; + +void workbench_globals_init(void); + +#endif diff --git a/workbench/src/wb_project.c b/workbench/src/wb_project.c new file mode 100644 index 000000000..a6f892e13 --- /dev/null +++ b/workbench/src/wb_project.c @@ -0,0 +1,1468 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the WB_PROJECT structure. + */ +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "wb_globals.h" +#include "wb_project.h" +#include "utils.h" + +extern GeanyData *geany_data; + +typedef enum +{ + WB_PROJECT_TAG_PREFS_AUTO, + WB_PROJECT_TAG_PREFS_YES, + WB_PROJECT_TAG_PREFS_NO, +}WB_PROJECT_TAG_PREFS; + +typedef struct +{ + GKeyFile *kf; + guint dir_count; +}WB_PROJECT_ON_SAVE_USER_DATA; + +struct S_WB_PROJECT_DIR +{ + gchar *name; + gchar *base_dir; + gchar **file_patterns; /**< Array of filename extension patterns. */ + gchar **ignored_dirs_patterns; + gchar **ignored_file_patterns; + guint file_count; + guint folder_count; + GHashTable *file_table; /* contains all file names within base_dir, maps file_name->TMSourceFile */ +}; + +struct S_WB_PROJECT +{ + gchar *filename; + gchar *name; + gboolean modified; + GSList *s_idle_add_funcs; + GSList *s_idle_remove_funcs; + GSList *directories; /* list of WB_PROJECT_DIR; */ + WB_PROJECT_TAG_PREFS generate_tag_prefs; + GPtrArray *bookmarks; +}; + + +/** Set the projects modified marker. + * + * @param prj The project + * @param value The value to set + * + **/ +void wb_project_set_modified(WB_PROJECT *prj, gboolean value) +{ + if (prj != NULL) + { + prj->modified = value; + } +} + + +/** Has the project been modified since the last save? + * + * @param prj The project + * @return TRUE if project is modified, FALSE otherwise + * + **/ +gboolean wb_project_is_modified(WB_PROJECT *prj) +{ + if (prj != NULL) + { + return (prj->modified); + } + return FALSE; +} + + +/** Set the filename of a project. + * + * @param prj The project + * @param filename The filename + * + **/ +void wb_project_set_filename(WB_PROJECT *prj, const gchar *filename) +{ + if (prj != NULL) + { + guint offset; + gchar *ext; + + g_free(prj->filename); + prj->filename = g_strdup(filename); + g_free(prj->name); + prj->name = g_path_get_basename (filename); + ext = g_strrstr(prj->name, ".geany"); + if(ext != NULL) + { + offset = strlen(prj->name); + offset -= strlen(".geany"); + if (ext == prj->name + offset) + { + /* Strip of file extension by overwriting + '.' with string terminator. */ + prj->name[offset] = '\0'; + } + } + } +} + + +/** Get the filename of a project. + * + * @param prj The project + * @return The filename + * + **/ +const gchar *wb_project_get_filename(WB_PROJECT *prj) +{ + if (prj != NULL) + { + return prj->filename; + } + return NULL; +} + + +/** Get the name of a project. + * + * @param prj The project + * @return The project name + * + **/ +const gchar *wb_project_get_name(WB_PROJECT *prj) +{ + if (prj != NULL) + { + return prj->name; + } + return NULL; +} + + +/** Get the list of directories contained in the project. + * + * @param prj The project + * @return GSList of directories (WB_PROJECT_DIRs) + * + **/ +GSList *wb_project_get_directories(WB_PROJECT *prj) +{ + if (prj != NULL) + { + return prj->directories; + } + return NULL; +} + + +/* Check if filename matches filetpye patterns */ +static gboolean match_basename(gconstpointer pft, gconstpointer user_data) +{ + const GeanyFiletype *ft = pft; + const gchar *utf8_base_filename = user_data; + gint j; + gboolean ret = FALSE; + + if (G_UNLIKELY(ft->id == GEANY_FILETYPES_NONE)) + return FALSE; + + for (j = 0; ft->pattern[j] != NULL; j++) + { + GPatternSpec *pattern = g_pattern_spec_new(ft->pattern[j]); + + if (g_pattern_match_string(pattern, utf8_base_filename)) + { + ret = TRUE; + g_pattern_spec_free(pattern); + break; + } + g_pattern_spec_free(pattern); + } + return ret; +} + + +/* Clear idle queue */ +static void wb_project_clear_idle_queue(GSList **queue) +{ + if (queue == NULL || *queue == NULL) + { + return; + } + + g_slist_free_full(*queue, g_free); + *queue = NULL; +} + + +/* Get the list of files for root */ +static GSList *wb_project_dir_get_file_list(WB_PROJECT_DIR *root, const gchar *utf8_path, GSList *patterns, + GSList *ignored_dirs_patterns, GSList *ignored_file_patterns, GHashTable *visited_paths) +{ + GSList *list = NULL; + GDir *dir; + gchar *locale_path = utils_get_locale_from_utf8(utf8_path); + gchar *real_path = tm_get_real_path(locale_path); + + dir = g_dir_open(locale_path, 0, NULL); + if (!dir || !real_path || g_hash_table_lookup(visited_paths, real_path)) + { + if (dir != NULL) + { + g_dir_close(dir); + } + g_free(locale_path); + g_free(real_path); + return NULL; + } + + g_hash_table_insert(visited_paths, real_path, GINT_TO_POINTER(1)); + + while (TRUE) + { + const gchar *locale_name; + gchar *locale_filename, *utf8_filename, *utf8_name; + + locale_name = g_dir_read_name(dir); + if (!locale_name) + break; + + utf8_name = utils_get_utf8_from_locale(locale_name); + locale_filename = g_build_filename(locale_path, locale_name, NULL); + utf8_filename = utils_get_utf8_from_locale(locale_filename); + + if (g_file_test(locale_filename, G_FILE_TEST_IS_DIR)) + { + GSList *lst; + + if (!patterns_match(ignored_dirs_patterns, utf8_name)) + { + lst = wb_project_dir_get_file_list(root, utf8_filename, patterns, ignored_dirs_patterns, + ignored_file_patterns, visited_paths); + if (lst) + { + root->folder_count++; + list = g_slist_concat(list, lst); + } + } + } + else if (g_file_test(locale_filename, G_FILE_TEST_IS_REGULAR)) + { + if (patterns_match(patterns, utf8_name) && !patterns_match(ignored_file_patterns, utf8_name)) + { + root->file_count++; + list = g_slist_prepend(list, g_strdup(utf8_filename)); + } + } + + g_free(utf8_filename); + g_free(locale_filename); + g_free(utf8_name); + } + + g_dir_close(dir); + g_free(locale_path); + + return list; +} + + +/* Create a new project dir with base path "utf8_base_dir" */ +static WB_PROJECT_DIR *wb_project_dir_new(const gchar *utf8_base_dir) +{ + guint offset; + + if (utf8_base_dir == NULL) + { + return NULL; + } + WB_PROJECT_DIR *dir = g_new0(WB_PROJECT_DIR, 1); + dir->base_dir = g_strdup(utf8_base_dir); + dir->file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)tm_source_file_free); + + offset = strlen(dir->base_dir)-1; + while (offset > 0 + && dir->base_dir[offset] != '\\' + && dir->base_dir[offset] != '/') + { + offset--; + } + if (offset != 0) + { + offset++; + } + dir->name = g_strdup(&(dir->base_dir[offset])); + return dir; +} + + +/* Collect source files */ +static void wb_project_dir_collect_source_files(G_GNUC_UNUSED gchar *filename, TMSourceFile *sf, gpointer user_data) +{ + GPtrArray *array = user_data; + + if (sf != NULL) + g_ptr_array_add(array, sf); +} + + +/** Get the name of a project dir. + * + * @param directory The project dir + * @return The name + * + **/ +const gchar *wb_project_dir_get_name (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->name; + } + return NULL; +} + + +/** Get the file table for the project dir. + * + * @param directory The project dir + * @return A GHashTable of all files containing to the rpoject dir. + * Might be empty if dir has not been scanned yet. + * + **/ +GHashTable *wb_project_dir_get_file_table (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->file_table; + } + return NULL; +} + + +/** Get the base/root dir of a project dir. + * + * @param directory The project dir + * @return The base dir + * + **/ +gchar *wb_project_dir_get_base_dir (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->base_dir; + } + return NULL; +} + + +/** Get the file patterns of a project dir. + * + * @param directory The project dir + * @return String array of file patterns + * + **/ +gchar **wb_project_dir_get_file_patterns (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->file_patterns; + } + return NULL; +} + + +/** Set the file patterns of a project dir. + * + * @param directory The project dir + * @param new String array of file patterns to set + * @return FALSE if directory is NULL, TRUE otherwise + * + **/ +gboolean wb_project_dir_set_file_patterns (WB_PROJECT_DIR *directory, gchar **new) +{ + if (directory != NULL) + { + g_strfreev(directory->file_patterns); + directory->file_patterns = g_strdupv(new); + return TRUE; + } + return FALSE; +} + + +/** Get the ignored dirs patterns of a project dir. + * + * @param directory The project dir + * @return String array of ignored dirs patterns + * + **/ +gchar **wb_project_dir_get_ignored_dirs_patterns (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->ignored_dirs_patterns; + } + return NULL; +} + + +/** Set the ignored dirs patterns of a project dir. + * + * @param directory The project dir + * @param new String array of ignored dirs patterns to set + * @return FALSE if directory is NULL, TRUE otherwise + * + **/ +gboolean wb_project_dir_set_ignored_dirs_patterns (WB_PROJECT_DIR *directory, gchar **new) +{ + if (directory != NULL) + { + g_strfreev(directory->ignored_dirs_patterns); + directory->ignored_dirs_patterns = g_strdupv(new); + return TRUE; + } + return FALSE; +} + + +/** Get the ignored file patterns of a project dir. + * + * @param directory The project dir + * @return String array of ignored file patterns + * + **/ +gchar **wb_project_dir_get_ignored_file_patterns (WB_PROJECT_DIR *directory) +{ + if (directory != NULL) + { + return directory->ignored_file_patterns; + } + return NULL; +} + + +/** Set the ignored file patterns of a project dir. + * + * @param directory The project dir + * @param new String array of ignored dirs patterns to set + * @return FALSE if directory is NULL, TRUE otherwise + * + **/ +gboolean wb_project_dir_set_ignored_file_patterns (WB_PROJECT_DIR *directory, gchar **new) +{ + if (directory != NULL) + { + g_strfreev(directory->ignored_file_patterns); + directory->ignored_file_patterns = g_strdupv(new); + return TRUE; + } + return FALSE; +} + + +/* Remove all files contained in the project dir from the tm-workspace */ +static void wb_project_dir_remove_from_tm_workspace(WB_PROJECT_DIR *root) +{ + GPtrArray *source_files; + + source_files = g_ptr_array_new(); + g_hash_table_foreach(root->file_table, (GHFunc)wb_project_dir_collect_source_files, source_files); + tm_workspace_remove_source_files(source_files); + g_ptr_array_free(source_files, TRUE); +} + + +/* Free a project dir */ +static void wb_project_dir_free(WB_PROJECT_DIR *dir) +{ + wb_project_dir_remove_from_tm_workspace(dir); + + g_hash_table_destroy(dir->file_table); + g_free(dir->base_dir); + g_free(dir); +} + + +/* Compare two project dirs */ +static gint wb_project_dir_comparator(WB_PROJECT_DIR *a, WB_PROJECT_DIR *b) +{ + gchar *a_realpath, *b_realpath, *a_locale_base_dir, *b_locale_base_dir; + gint res; + + a_locale_base_dir = utils_get_locale_from_utf8(a->base_dir); + b_locale_base_dir = utils_get_locale_from_utf8(b->base_dir); + a_realpath = tm_get_real_path(a_locale_base_dir); + b_realpath = tm_get_real_path(b_locale_base_dir); + + res = g_strcmp0(a_realpath, b_realpath); + + g_free(a_realpath); + g_free(b_realpath); + g_free(a_locale_base_dir); + g_free(b_locale_base_dir); + + return res; +} + + +/* Get the file count of a project */ +static guint wb_project_get_file_count(WB_PROJECT *prj) +{ + GSList *elem; + guint filenum = 0; + + foreach_slist(elem, prj->directories) + { + filenum += ((WB_PROJECT_DIR *)elem->data)->file_count; + } + return filenum; +} + +/* Rescan/update the file list of a project dir. */ +static guint wb_project_dir_rescan_int(WB_PROJECT *prj, WB_PROJECT_DIR *root) +{ + GSList *pattern_list = NULL; + GSList *ignored_dirs_list = NULL; + GSList *ignored_file_list = NULL; + GHashTable *visited_paths; + GSList *lst; + GSList *elem; + guint filenum = 0; + gchar *searchdir; + + wb_project_dir_remove_from_tm_workspace(root); + g_hash_table_remove_all(root->file_table); + + if (!root->file_patterns || !root->file_patterns[0]) + { + const gchar *all_pattern[] = { "*", NULL }; + pattern_list = get_precompiled_patterns((gchar **)all_pattern); + } + else + { + pattern_list = get_precompiled_patterns(root->file_patterns); + } + + ignored_dirs_list = get_precompiled_patterns(root->ignored_dirs_patterns); + ignored_file_list = get_precompiled_patterns(root->ignored_file_patterns); + + visited_paths = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + searchdir = get_combined_path(prj->filename, root->base_dir); + root->file_count = 0; + root->folder_count = 0; + lst = wb_project_dir_get_file_list + (root, searchdir, pattern_list, ignored_dirs_list, ignored_file_list, visited_paths); + g_hash_table_destroy(visited_paths); + g_free(searchdir); + + foreach_slist(elem, lst) + { + char *path = elem->data; + + if (path) + { + g_hash_table_insert(root->file_table, g_strdup(path), NULL); + filenum++; + } + } + + g_slist_foreach(lst, (GFunc) g_free, NULL); + g_slist_free(lst); + + g_slist_foreach(pattern_list, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(pattern_list); + + g_slist_foreach(ignored_dirs_list, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(ignored_dirs_list); + + g_slist_foreach(ignored_file_list, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(ignored_file_list); + + return filenum; +} + + +/* Stolen and modified version from Geany. The only difference is that Geany + * first looks at shebang inside the file and then, if it fails, checks the + * file extension. Opening every file is too expensive so instead check just + * extension and only if this fails, look at the shebang */ +static GeanyFiletype *filetypes_detect(const gchar *utf8_filename) +{ + struct stat s; + GeanyFiletype *ft = NULL; + gchar *locale_filename; + + locale_filename = utils_get_locale_from_utf8(utf8_filename); + if (g_stat(locale_filename, &s) != 0 || s.st_size > 10*1024*1024) + ft = filetypes[GEANY_FILETYPES_NONE]; + else + { + guint i; + gchar *utf8_base_filename; + + /* to match against the basename of the file (because of Makefile*) */ + utf8_base_filename = g_path_get_basename(utf8_filename); +#ifdef G_OS_WIN32 + /* use lower case basename */ + SETPTR(utf8_base_filename, g_utf8_strdown(utf8_base_filename, -1)); +#endif + + for (i = 0; i < geany_data->filetypes_array->len; i++) + { + GeanyFiletype *ftype = filetypes[i]; + + if (match_basename(ftype, utf8_base_filename)) + { + ft = ftype; + break; + } + } + + if (ft == NULL) + ft = filetypes_detect_from_file(utf8_filename); + + g_free(utf8_base_filename); + } + + g_free(locale_filename); + + return ft; +} + + +/* Regenerate tags */ +static void wb_project_regenerate_tags(WB_PROJECT_DIR *root, G_GNUC_UNUSED gpointer user_data) +{ + GHashTableIter iter; + gpointer key, value; + GPtrArray *source_files; + GHashTable *file_table; + + source_files = g_ptr_array_new(); + file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)tm_source_file_free); + g_hash_table_iter_init(&iter, root->file_table); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + TMSourceFile *sf; + gchar *utf8_path = key; + gchar *locale_path = utils_get_locale_from_utf8(utf8_path); + + sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name); + if (sf && !document_find_by_filename(utf8_path)) + g_ptr_array_add(source_files, sf); + + g_hash_table_insert(file_table, g_strdup(utf8_path), sf); + g_free(locale_path); + } + g_hash_table_destroy(root->file_table); + root->file_table = file_table; + + tm_workspace_add_source_files(source_files); + g_ptr_array_free(source_files, TRUE); +} + + +/** Rescan/update the file list of a project dir. + * + * @param project The project to which directory belongs + * @param directory The project dir + * @return Number of files + * + **/ +guint wb_project_dir_rescan(WB_PROJECT *prj, WB_PROJECT_DIR *root) +{ + guint total, filenum; + + filenum = wb_project_dir_rescan_int(prj, root); + total = wb_project_get_file_count(prj); + if (prj->generate_tag_prefs == WB_PROJECT_TAG_PREFS_YES || (prj->generate_tag_prefs == WB_PROJECT_TAG_PREFS_AUTO && total < 300)) + { + g_slist_foreach(prj->directories, (GFunc)wb_project_regenerate_tags, NULL); + } + return filenum; +} + + +/** Rescan/update the file list of a project. + * + * @param project The project + * + **/ +void wb_project_rescan(WB_PROJECT *prj) +{ + GSList *elem; + guint filenum = 0; + + if (!prj) + { + return; + } + + wb_project_clear_idle_queue(&prj->s_idle_add_funcs); + wb_project_clear_idle_queue(&prj->s_idle_remove_funcs); + + foreach_slist(elem, prj->directories) + { + filenum += wb_project_dir_rescan_int(prj, elem->data); + } + + if (prj->generate_tag_prefs == WB_PROJECT_TAG_PREFS_YES || (prj->generate_tag_prefs == WB_PROJECT_TAG_PREFS_AUTO && filenum < 300)) + { + g_slist_foreach(prj->directories, (GFunc)wb_project_regenerate_tags, NULL); + } +} + + +/** Is @a filename included in the project directory? + * + * @param dir The project directory + * @param filename The file + * @return TRUE if file is included, FALSE otherwise + * + **/ +gboolean wb_project_dir_file_is_included(WB_PROJECT_DIR *dir, const gchar *filename) +{ + if (filename == NULL || dir == NULL) + { + return FALSE; + } + + if (g_hash_table_lookup_extended (dir->file_table, filename, NULL, NULL)) + { + return TRUE; + } + + return FALSE; +} + + +/** Is @a filename included in the project? + * + * @param dir The project + * @param filename The file + * @return TRUE if file is included, FALSE otherwise + * + **/ +gboolean wb_project_file_is_included(WB_PROJECT *prj, const gchar *filename) +{ + GSList *elem; + + if (prj == NULL) + { + return FALSE; + } + + foreach_slist(elem, prj->directories) + { + if (wb_project_dir_file_is_included(elem->data, filename) == TRUE) + { + return TRUE; + } + } + return FALSE; +} + + +static gboolean add_tm_idle(gpointer foo) +{ + WB_PROJECT *prj; + GSList *elem2; + + prj = (WB_PROJECT *)foo; + if (prj == NULL || prj->s_idle_add_funcs == NULL) + { + return FALSE; + } + + foreach_slist (elem2, prj->s_idle_add_funcs) + { + GSList *elem; + gchar *utf8_fname = elem2->data; + + foreach_slist (elem, prj->directories) + { + WB_PROJECT_DIR *dir = elem->data; + TMSourceFile *sf = g_hash_table_lookup(dir->file_table, utf8_fname); + + if (sf != NULL && !document_find_by_filename(utf8_fname)) + { + tm_workspace_add_source_file(sf); + break; /* single file representation in TM is enough */ + } + } + } + + wb_project_clear_idle_queue(&(prj->s_idle_add_funcs)); + + return FALSE; +} + + +/* This function gets called when document is being closed by Geany and we need + * to add the TMSourceFile from the tag manager because Geany removes it on + * document close. + * + * Additional problem: The tag removal in Geany happens after this function is called. + * To be sure, perform on idle after this happens (even though from my knowledge of TM + * this shouldn't probably matter). */ +void wb_project_add_single_tm_file(WB_PROJECT *prj, const gchar *filename) +{ + if (prj == NULL) + { + return; + } + + if (prj->s_idle_add_funcs == NULL) + { + plugin_idle_add(wb_globals.geany_plugin, (GSourceFunc)add_tm_idle, prj); + } + + prj->s_idle_add_funcs = g_slist_prepend(prj->s_idle_add_funcs, g_strdup(filename)); +} + + +static gboolean remove_tm_idle(gpointer foo) +{ + WB_PROJECT *prj; + GSList *elem2; + + prj = (WB_PROJECT *)foo; + if (prj == NULL || prj->s_idle_remove_funcs == NULL) + { + return FALSE; + } + + foreach_slist (elem2, prj->s_idle_remove_funcs) + { + GSList *elem; + gchar *utf8_fname = elem2->data; + + foreach_slist (elem, prj->directories) + { + WB_PROJECT_DIR *dir = elem->data; + TMSourceFile *sf = g_hash_table_lookup(dir->file_table, utf8_fname); + + if (sf != NULL) + { + tm_workspace_remove_source_file(sf); + } + } + } + + wb_project_clear_idle_queue(&(prj->s_idle_remove_funcs)); + return FALSE; +} + + +/* This function gets called when document is being opened by Geany and we need + * to remove the TMSourceFile from the tag manager because Geany inserts + * it for the newly open tab. Even though tag manager would handle two identical + * files, the file inserted by the plugin isn't updated automatically in TM + * so any changes wouldn't be reflected in the tags array (e.g. removed function + * from source file would still be found in TM) + * + * Additional problem: The document being opened may be caused + * by going to tag definition/declaration - tag processing is in progress + * when this function is called and if we remove the TmSourceFile now, line + * number for the searched tag won't be found. For this reason delay the tag + * TmSourceFile removal until idle */ +void wb_project_remove_single_tm_file(WB_PROJECT *prj, const gchar *utf8_filename) +{ + if (prj == NULL) + { + return; + } + + if (prj->s_idle_remove_funcs == NULL) + { + plugin_idle_add(wb_globals.geany_plugin, (GSourceFunc)remove_tm_idle, prj); + } + prj->s_idle_remove_funcs = g_slist_prepend(prj->s_idle_remove_funcs, g_strdup(utf8_filename)); +} + + +/* Add a directory to the project */ +static WB_PROJECT_DIR *wb_project_add_directory_int(WB_PROJECT *prj, const gchar *dirname, gboolean rescan) +{ + if (prj != NULL) + { + WB_PROJECT_DIR *new_dir = wb_project_dir_new(dirname); + + if (prj->directories != NULL) + { + GSList *lst = prj->directories->next; + lst = g_slist_prepend(lst, new_dir); + lst = g_slist_sort(lst, (GCompareFunc)wb_project_dir_comparator); + prj->directories->next = lst; + } + else + { + prj->directories = g_slist_append(prj->directories, new_dir); + } + + if (rescan) + { + wb_project_rescan(prj); + } + return new_dir; + } + return NULL; +} + + +/** Adds a new project dir to the project. + * + * @param project The project + * @param dirname The base dir of the new project dir + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean wb_project_add_directory(WB_PROJECT *prj, const gchar *dirname) +{ + gchar *reldirname; + + /* Convert dirname to path relative to the project file */ + reldirname = get_any_relative_path(prj->filename, dirname); + + if (wb_project_add_directory_int(prj, reldirname, TRUE) != NULL) + { + prj->modified = TRUE; + return TRUE; + } + + g_free(reldirname); + return FALSE; +} + + +/** Remove a project dir from the project. + * + * @param project The project + * @param dir The project dir to remove + * @return FALSE on NULL parameter, TRUE otherwise + * + **/ +gboolean wb_project_remove_directory (WB_PROJECT *prj, WB_PROJECT_DIR *dir) +{ + if (prj != NULL && dir != NULL) + { + prj->directories = g_slist_remove(prj->directories, dir); + wb_project_dir_free(dir); + wb_project_rescan(prj); + prj->modified = TRUE; + } + return FALSE; +} + + +/** Get an info string for the project dir. + * + * @param dir The project dir + * @return The info string + * + **/ +gchar *wb_project_dir_get_info (WB_PROJECT_DIR *dir) +{ + gchar *str; + + if (dir == NULL) + return g_strdup(""); + + GString *temp = g_string_new(NULL); + gchar *text; + g_string_append_printf(temp, _("Directory-Name: %s\n"), wb_project_dir_get_name(dir)); + g_string_append_printf(temp, _("Base-Directory: %s\n"), wb_project_dir_get_base_dir(dir)); + + g_string_append(temp, _("File Patterns:")); + str = g_strjoinv(" ", dir->file_patterns); + if (str != NULL ) + { + g_string_append_printf(temp, " %s\n", str); + g_free(str); + } + else + { + g_string_append(temp, "\n"); + } + + g_string_append(temp, _("Ignored Dir. Patterns:")); + str = g_strjoinv(" ", dir->ignored_dirs_patterns); + if (str != NULL ) + { + g_string_append_printf(temp, " %s\n", str); + g_free(str); + } + else + { + g_string_append(temp, "\n"); + } + + g_string_append(temp, _("Ignored File Patterns:")); + str = g_strjoinv(" ", dir->ignored_file_patterns); + if (str != NULL ) + { + g_string_append_printf(temp, " %s\n", str); + g_free(str); + } + else + { + g_string_append(temp, "\n"); + } + + g_string_append_printf(temp, _("Number of Sub-Folders: %u\n"), dir->folder_count); + g_string_append_printf(temp, _("Number of Files: %u\n"), dir->file_count); + + /* Steal string content */ + text = temp->str; + g_string_free (temp, FALSE); + + return text; +} + + +/** Get an info string for the project. + * + * @param prj The project + * @return The info string + * + **/ +gchar *wb_project_get_info (WB_PROJECT *prj) +{ + GString *temp = g_string_new(NULL); + gchar *text; + + if (prj == NULL) + return g_strdup(""); + + g_string_append_printf(temp, _("Project: %s\n"), wb_project_get_name(prj)); + g_string_append_printf(temp, _("File: %s\n"), wb_project_get_filename(prj)); + g_string_append_printf(temp, _("Number of Directories: %u\n"), g_slist_length(prj->directories)); + if (wb_project_is_modified(prj)) + { + g_string_append(temp, _("\nThe project contains unsafed changes!\n")); + } + + /* Steal string content */ + text = temp->str; + g_string_free (temp, FALSE); + + return text; +} + + +/* Save directories to key file */ +static void wb_project_save_directories (gpointer data, gpointer user_data) +{ + gchar key[250], *str; + WB_PROJECT_DIR *dir; + WB_PROJECT_ON_SAVE_USER_DATA *tmp; + + if (data == NULL || user_data == NULL) + { + return; + } + tmp = (WB_PROJECT_ON_SAVE_USER_DATA *)user_data; + dir = (WB_PROJECT_DIR *)data; + + g_snprintf(key, sizeof(key), "Dir%u-BaseDir", tmp->dir_count); + g_key_file_set_string(tmp->kf, "Workbench", key, dir->base_dir); + + g_snprintf(key, sizeof(key), "Dir%u-FilePatterns", tmp->dir_count); + str = g_strjoinv(";", dir->file_patterns); + g_key_file_set_string(tmp->kf, "Workbench", key, str); + g_free(str); + + g_snprintf(key, sizeof(key), "Dir%u-IgnoredDirsPatterns", tmp->dir_count); + str = g_strjoinv(";", dir->ignored_dirs_patterns); + g_key_file_set_string(tmp->kf, "Workbench", key, str); + g_free(str); + + g_snprintf(key, sizeof(key), "Dir%u-IgnoredFilePatterns", tmp->dir_count); + str = g_strjoinv(";", dir->ignored_file_patterns); + g_key_file_set_string(tmp->kf, "Workbench", key, str); + g_free(str); + + tmp->dir_count++; +} + + +/* Add a bookmark to the project */ +static gboolean wb_project_add_bookmark_int(WB_PROJECT *prj, const gchar *filename) +{ + if (prj != NULL) + { + gchar *new; + + new = g_strdup(filename); + if (new != NULL) + { + g_ptr_array_add (prj->bookmarks, new); + return TRUE; + } + } + return FALSE; +} + + +/** Add a bookmark to the project. + * + * @param prj The project + * @param filename Bookmark + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean wb_project_add_bookmark(WB_PROJECT *prj, const gchar *filename) +{ + if (wb_project_add_bookmark_int(prj, filename) == TRUE) + { + prj->modified = TRUE; + return TRUE; + } + return FALSE; +} + + +/** Remove a bookmark from the project. + * + * @param prj The project + * @param filename Bookmark + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean wb_project_remove_bookmark(WB_PROJECT *prj, const gchar *filename) +{ + if (prj != NULL) + { + guint index; + gchar *current; + + for (index = 0 ; index < prj->bookmarks->len ; index++) + { + current = g_ptr_array_index(prj->bookmarks, index); + if (current == filename) + { + g_ptr_array_remove_index (prj->bookmarks, index); + prj->modified = TRUE; + return TRUE; + } + } + } + return FALSE; +} + + +/* Free all bookmarks */ +static gboolean wb_project_free_all_bookmarks(WB_PROJECT *prj) +{ + if (prj != NULL) + { + guint index; + gchar *current; + + for (index = 0 ; index < prj->bookmarks->len ; index++) + { + current = g_ptr_array_index(prj->bookmarks, index); + g_free(current); + } + g_ptr_array_free(prj->bookmarks, TRUE); + } + return FALSE; +} + + +/** Get the bookmark of a project at index @a index. + * + * @param prj The project + * @param index The index + * @return The filename of the boomark (or NULL if prj is NULL) + * + **/ +gchar *wb_project_get_bookmark_at_index (WB_PROJECT *prj, guint index) +{ + if (prj != NULL) + { + gchar *file; + file = g_ptr_array_index(prj->bookmarks, index); + if (file == NULL) + { + return NULL; + } + return file; + } + return NULL; +} + + +/** Get the number of bookmarks of a project. + * + * @param prj The project + * @return The number of bookmarks + * + **/ +guint wb_project_get_bookmarks_count(WB_PROJECT *prj) +{ + if (prj != NULL && prj->bookmarks != NULL) + { + return prj->bookmarks->len; + } + return 0; +} + + +/** Save a project. + * + * The function saves the project config file. Only the workbench plugin info + * is changed, all other config options remain unchanged. + * + * @param prj The project + * @param error Location to store error info at + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean wb_project_save(WB_PROJECT *prj, GError **error) +{ + GKeyFile *kf; + guint index; + gchar *contents; + gsize length, boomarks_size; + gboolean success = FALSE; + WB_PROJECT_ON_SAVE_USER_DATA tmp; + + g_return_val_if_fail(prj, FALSE); + + /* Load existing data into GKeyFile */ + kf = g_key_file_new (); + if (!g_key_file_load_from_file(kf, prj->filename, G_KEY_FILE_NONE, error)) + { + return FALSE; + } + + /* Remove existing, old data from our plugin */ + g_key_file_remove_group (kf, "Workbench", NULL); + + /* Save Project bookmarks as string list */ + boomarks_size = wb_project_get_bookmarks_count(prj); + if (boomarks_size > 0) + { + gchar **bookmarks_strings, *file, *rel_path; + + bookmarks_strings = g_new0(gchar *, boomarks_size+1); + for (index = 0 ; index < boomarks_size ; index++ ) + { + file = wb_project_get_bookmark_at_index(prj, index); + rel_path = get_any_relative_path(prj->filename, file); + + bookmarks_strings[index] = rel_path; + } + g_key_file_set_string_list + (kf, "Workbench", "Bookmarks", (const gchar **)bookmarks_strings, boomarks_size); + for (index = 0 ; index < boomarks_size ; index++ ) + { + g_free (bookmarks_strings[index]); + } + g_free(bookmarks_strings); + } + + /* Init tmp data */ + tmp.kf = kf; + tmp.dir_count = 1; + + /* Store our directories */ + g_slist_foreach(prj->directories, (GFunc)wb_project_save_directories, &tmp); + + /* Get data as string */ + contents = g_key_file_to_data (kf, &length, error); + g_key_file_free(kf); + + /* Save to file */ + success = g_file_set_contents (prj->filename, contents, length, error); + if (success) + { + prj->modified = FALSE; + } + g_free (contents); + + return success; +} + + +/** Load a project. + * + * The function loads the project data from file @a filename into the + * project structure @a prj. + * + * @param prj The project + * @param filename File to load + * @param error Location to store error info at + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean wb_project_load(WB_PROJECT *prj, gchar *filename, GError **error) +{ + GKeyFile *kf; + guint index; + gchar *contents; + gchar key[100]; + gsize length; + gboolean success = FALSE; + + g_return_val_if_fail(prj, FALSE); + + if (!g_file_get_contents (filename, &contents, &length, error)) + { + return FALSE; + } + + kf = g_key_file_new (); + + if (!g_key_file_load_from_data (kf, contents, length, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, + error)) + { + g_key_file_free (kf); + g_free (contents); + return FALSE; + } + + if (g_key_file_has_group (kf, "Workbench")) + { + WB_PROJECT_DIR *new_dir; + gchar *str; + gchar **splitv, **bookmarks_strings; + + /* Load project bookmarks from string list */ + bookmarks_strings = g_key_file_get_string_list (kf, "Workbench", "Bookmarks", NULL, error); + if (bookmarks_strings != NULL) + { + gchar **file, *abs_path; + + file = bookmarks_strings; + while (*file != NULL) + { + abs_path = get_combined_path(prj->filename, *file); + if (abs_path != NULL) + { + wb_project_add_bookmark_int(prj, abs_path); + g_free(abs_path); + } + file++; + } + g_strfreev(bookmarks_strings); + } + + /* Load project dirs */ + for (index = 1 ; index < 1025 ; index++) + { + g_snprintf(key, sizeof(key), "Dir%u-BaseDir", index); + + str = g_key_file_get_string(kf, "Workbench", key, NULL); + if (str == NULL) + { + break; + } + new_dir = wb_project_add_directory_int(prj, str, FALSE); + if (new_dir == NULL) + { + break; + } + + g_snprintf(key, sizeof(key), "Dir%u-FilePatterns", index); + str = g_key_file_get_string(kf, "Workbench", key, NULL); + if (str != NULL) + { + splitv = g_strsplit (str, ";", -1); + wb_project_dir_set_file_patterns(new_dir, splitv); + } + g_free(str); + + g_snprintf(key, sizeof(key), "Dir%u-IgnoredDirsPatterns", index); + str = g_key_file_get_string(kf, "Workbench", key, NULL); + if (str != NULL) + { + splitv = g_strsplit (str, ";", -1); + wb_project_dir_set_ignored_dirs_patterns(new_dir, splitv); + } + g_free(str); + + g_snprintf(key, sizeof(key), "Dir%u-IgnoredFilePatterns", index); + str = g_key_file_get_string(kf, "Workbench", key, NULL); + if (str != NULL) + { + splitv = g_strsplit (str, ";", -1); + wb_project_dir_set_ignored_file_patterns(new_dir, splitv); + } + g_free(str); + } + } + + g_key_file_free(kf); + g_free (contents); + success = TRUE; + + return success; +} + + +/** Create a new empty project. + * + * @return Address of the new structure. + * + **/ +WB_PROJECT *wb_project_new(const gchar *filename) +{ + WB_PROJECT *new_prj; + + new_prj = g_malloc0(sizeof *new_prj); + new_prj->modified = FALSE; + wb_project_set_filename(new_prj, filename); + new_prj->bookmarks = g_ptr_array_new(); + new_prj->generate_tag_prefs = WB_PROJECT_TAG_PREFS_YES; + + return new_prj; +} + + +/** Free a project. + * + * @param prj Adress of structure to free + * + **/ +void wb_project_free(WB_PROJECT *prj) +{ + /* Free directories first */ + g_slist_free_full(prj->directories, (GDestroyNotify)wb_project_dir_free); + + /* Free all bookmarks */ + wb_project_free_all_bookmarks(prj); + + g_free(prj->filename); + g_free(prj->name); + g_free(prj); +} diff --git a/workbench/src/wb_project.h b/workbench/src/wb_project.h new file mode 100644 index 000000000..b654eec59 --- /dev/null +++ b/workbench/src/wb_project.h @@ -0,0 +1,68 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_PROJECT_H__ +#define __WB_PROJECT_H__ + +#include + +typedef struct S_WB_PROJECT WB_PROJECT; +typedef struct S_WB_PROJECT_DIR WB_PROJECT_DIR; + +WB_PROJECT *wb_project_new(const gchar *filename); +void wb_project_free(WB_PROJECT *prj); + +void wb_project_set_modified(WB_PROJECT *prj, gboolean value); +gboolean wb_project_is_modified(WB_PROJECT *prj); + +void wb_project_set_filename(WB_PROJECT *prj, const gchar *filename); +const gchar *wb_project_get_filename(WB_PROJECT *prj); +const gchar *wb_project_get_name(WB_PROJECT *prj); +GSList *wb_project_get_directories(WB_PROJECT *prj); +gboolean wb_project_add_directory(WB_PROJECT *prj, const gchar *dirname); +gboolean wb_project_remove_directory (WB_PROJECT *prj, WB_PROJECT_DIR *dir); +void wb_project_rescan(WB_PROJECT *prj); +gboolean wb_project_file_is_included(WB_PROJECT *prj, const gchar *filename); +void wb_project_add_single_tm_file(WB_PROJECT *prj, const gchar *filename); +void wb_project_remove_single_tm_file(WB_PROJECT *prj, const gchar *filename); + +const gchar *wb_project_dir_get_name (WB_PROJECT_DIR *directory); +GHashTable *wb_project_dir_get_file_table (WB_PROJECT_DIR *directory); +gchar *wb_project_dir_get_base_dir (WB_PROJECT_DIR *directory); +gchar **wb_project_dir_get_file_patterns (WB_PROJECT_DIR *directory); +gboolean wb_project_dir_set_file_patterns (WB_PROJECT_DIR *directory, gchar **new); +gchar **wb_project_dir_get_ignored_dirs_patterns (WB_PROJECT_DIR *directory); +gboolean wb_project_dir_set_ignored_dirs_patterns (WB_PROJECT_DIR *directory, gchar **new); +gchar **wb_project_dir_get_ignored_file_patterns (WB_PROJECT_DIR *directory); +gboolean wb_project_dir_set_ignored_file_patterns (WB_PROJECT_DIR *directory, gchar **new); +guint wb_project_dir_rescan(WB_PROJECT *prj, WB_PROJECT_DIR *root); +gchar *wb_project_dir_get_info (WB_PROJECT_DIR *dir); +gboolean wb_project_dir_file_is_included(WB_PROJECT_DIR *dir, const gchar *filename); + +gboolean wb_project_add_bookmark(WB_PROJECT *prj, const gchar *filename); +gboolean wb_project_remove_bookmark(WB_PROJECT *prj, const gchar *filename); +GPtrArray *wb_project_get_bookmarks(WB_PROJECT *prj); +gchar *wb_project_get_bookmark_at_index (WB_PROJECT *prj, guint index); +guint wb_project_get_bookmarks_count(WB_PROJECT *prj); + +gboolean wb_project_save(WB_PROJECT *prj, GError **error); +gboolean wb_project_load(WB_PROJECT *prj, gchar *filename, GError **error); + +gchar *wb_project_get_info (WB_PROJECT *prj); + +#endif diff --git a/workbench/src/workbench.c b/workbench/src/workbench.c new file mode 100644 index 000000000..f80831219 --- /dev/null +++ b/workbench/src/workbench.c @@ -0,0 +1,803 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the WORKBENCH structure. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include "workbench.h" +#include "wb_project.h" +#include "utils.h" + +typedef struct +{ + PROJECT_ENTRY_STATUS status; + gchar *abs_filename; + gchar *rel_filename; + gboolean use_abs; + WB_PROJECT *project; +}WB_PROJECT_ENTRY; + +struct S_WORKBENCH +{ + gchar *filename; + gchar *name; + gboolean modified; + gboolean rescan_projects_on_open; + GPtrArray *projects; + GPtrArray *bookmarks; +}; + +/* Create a new, empty workbench project entry */ +static WB_PROJECT_ENTRY *wb_project_entry_new(void) +{ + WB_PROJECT_ENTRY *new_entry; + + new_entry = g_new(WB_PROJECT_ENTRY, 1); + memset(new_entry, 0, sizeof(*new_entry)); + new_entry->status = PROJECT_ENTRY_STATUS_UNKNOWN; + + return new_entry; +} + + +/* Free a workbench entry */ +static void wb_project_entry_free(WB_PROJECT_ENTRY *entry) +{ + wb_project_free(entry->project); + g_free(entry->abs_filename); + g_free(entry->rel_filename); + g_free(entry); +} + + +/** Create a new empty workbench. + * + * @return Address of the new structure. + * + **/ +WORKBENCH *workbench_new(void) +{ + WORKBENCH *new_wb; + + new_wb = g_new(WORKBENCH, 1); + memset(new_wb, 0, sizeof(*new_wb)); + new_wb->modified = FALSE; + new_wb->rescan_projects_on_open = TRUE; + new_wb->projects = g_ptr_array_new(); + new_wb->bookmarks = g_ptr_array_new(); + + return new_wb; +} + + +/** Free a workbench. + * + * @param wb The workbench + * + **/ +void workbench_free(WORKBENCH *wb) +{ + WB_PROJECT_ENTRY *entry; + guint index; + + if (wb == NULL) + { + return; + } + + /* Free projects and project entries first */ + for (index = 0 ; index < wb->projects->len ; index++) + { + entry = g_ptr_array_index(wb->projects, index); + if (entry != NULL) + { + wb_project_entry_free(entry); + } + } + + g_ptr_array_free (wb->projects, TRUE); + g_free(wb); +} + + +/** Is the workbench empty? + * + * @param wb The workbench + * @return TRUE is workbench is empty or wb == NULL, + * FALSE otherwise. + * + **/ +gboolean workbench_is_empty(WORKBENCH *wb) +{ + if (wb != NULL) + { + return (wb->projects->len == 0); + } + return TRUE; +} + + +/** Get the project count. + * + * @param wb The workbench + * @return TRUE is workbench is empty or wb == NULL, + * FALSE otherwise. + * + **/ +guint workbench_get_project_count(WORKBENCH *wb) +{ + if (wb != NULL) + { + return wb->projects->len; + } + return 0; +} + + +/** Is the workbench modified? + * + * @param wb The workbench + * @return TRUE if the workbench is modified, + * FALSE if not or wb == NULL + * + **/ +gboolean workbench_is_modified(WORKBENCH *wb) +{ + if (wb != NULL) + { + return wb->modified; + } + return FALSE; +} + + +/** Set the "Rescan projects on open" option. + * + * @param wb The workbench + * @param value The value to set + * + **/ +void workbench_set_rescan_projects_on_open(WORKBENCH *wb, gboolean value) +{ + if (wb != NULL) + { + if (wb->rescan_projects_on_open != value) + { + wb->rescan_projects_on_open = value; + wb->modified = TRUE; + } + } +} + + +/** Get the "Rescan projects on open" option. + * + * @param wb The workbench + * @return TRUE = rescan all projects after opening the workbench, + * FALSE = don't + * + **/ +gboolean workbench_get_rescan_projects_on_open(WORKBENCH *wb) +{ + if (wb != NULL) + { + return wb->rescan_projects_on_open; + } + return FALSE; +} + + +/** Set the filename. + * + * @param wb The workbench + * @param filename Name of the workbench file + * + **/ +void workbench_set_filename(WORKBENCH *wb, const gchar *filename) +{ + if (wb != NULL) + { + guint offset; + gchar *ext; + + wb->filename = g_strdup(filename); + wb->name = g_path_get_basename (filename); + ext = g_strrstr(wb->name, ".geanywb"); + if(ext != NULL) + { + offset = strlen(wb->name); + offset -= strlen(".geanywb"); + if (ext == wb->name + offset) + { + /* Strip of file extension by overwriting + '.' with string terminator. */ + wb->name[offset] = '\0'; + } + } + } +} + + +/** Get the filename. + * + * @param wb The workbench + * @return The filename or NULL + * + **/ +const gchar *workbench_get_filename(WORKBENCH *wb) +{ + if (wb != NULL) + { + return wb->filename; + } + return NULL; +} + + +/** Get the name. + * + * @param wb The workbench + * @return The name or NULL + * + **/ +gchar *workbench_get_name(WORKBENCH *wb) +{ + if (wb != NULL) + { + return wb->name; + } + return NULL; +} + + +/** Get the project stored in the workbench at @a index. + * + * @param wb The workbench + * @param index The index + * @return Adress of the WB_PROJECT structure or NULL + * if wb == NULL or an invalid index + * + **/ +WB_PROJECT *workbench_get_project_at_index (WORKBENCH *wb, guint index) +{ + if (wb != NULL) + { + WB_PROJECT_ENTRY *entry; + entry = g_ptr_array_index(wb->projects, index); + if (entry == NULL) + { + return NULL; + } + return entry->project; + } + return NULL; +} + + +/** Get the project status in the workbench at @a index. + * + * Actually the project status just gives information about wheter + * the project file for the project at @a index was found or not. + * + * @param wb The workbench + * @param index The index + * @return the status or PROJECT_ENTRY_STATUS_UNKNOWN if wb == NULL + * + **/ +PROJECT_ENTRY_STATUS workbench_get_project_status_at_index (WORKBENCH *wb, guint index) +{ + if (wb != NULL) + { + WB_PROJECT_ENTRY *entry; + entry = g_ptr_array_index(wb->projects, index); + if (entry == NULL) + { + return PROJECT_ENTRY_STATUS_UNKNOWN; + } + return entry->status; + } + return PROJECT_ENTRY_STATUS_UNKNOWN; +} + + +/** Get the project status in the workbench by address. + * + * Actually the project status just gives information about wheter + * the project file for the project at @a index was found or not. + * + * @param wb The workbench + * @param address Location of the project + * @return the status or PROJECT_ENTRY_STATUS_UNKNOWN if wb == NULL + * + **/ +PROJECT_ENTRY_STATUS workbench_get_project_status_by_address (WORKBENCH *wb, WB_PROJECT *address) +{ + guint index; + if (wb != NULL || address == NULL) + { + WB_PROJECT_ENTRY *entry; + for (index = 0 ; index < wb->projects->len ; index++) + { + entry = g_ptr_array_index(wb->projects, index); + if (entry != NULL && entry->project == address) + { + return entry->status; + } + } + } + return PROJECT_ENTRY_STATUS_UNKNOWN; +} + + +/** Add a project to the workbench. + * + * @param wb The workbench + * @param filename Project file + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_add_project(WORKBENCH *wb, const gchar *filename) +{ + if (wb != NULL) + { + GStatBuf buf; + WB_PROJECT *project; + WB_PROJECT_ENTRY *entry; + + entry = wb_project_entry_new(); + if (entry == NULL) + { + return FALSE; + } + project = wb_project_new(filename); + if (project == NULL) + { + wb_project_entry_free(entry); + return FALSE; + } + + /* Set entry data: + - absolute and relative filename (relative to workbench file) + - per default use relative path + - check status of project file + - pointer to the project data */ + entry->abs_filename = g_strdup(filename); + entry->rel_filename = get_any_relative_path + (wb->filename, filename); + entry->use_abs = FALSE; + entry->project = project; + if (g_stat (filename, &buf) == 0) + { + entry->status = PROJECT_ENTRY_STATUS_OK; + } + else + { + entry->status = PROJECT_ENTRY_STATUS_NOT_FOUND; + } + g_ptr_array_add (wb->projects, entry); + + wb->modified = TRUE; + return TRUE; + } + return FALSE; +} + + +/** Remove a project from the workbench. + * + * @param wb The workbench + * @param project The Project + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_remove_project_with_address(WORKBENCH *wb, WB_PROJECT *project) +{ + if (wb != NULL && wb->projects != NULL) + { + guint index; + WB_PROJECT_ENTRY *current; + + for (index = 0 ; index < wb->projects->len ; index++) + { + current = g_ptr_array_index(wb->projects, index); + if (current != NULL && current->project == project) + { + g_ptr_array_remove_index (wb->projects, index); + wb_project_entry_free(current); + wb->modified = TRUE; + return TRUE; + } + } + } + return FALSE; +} + + +/** Is the file included in the workbench? + * + * @param wb The workbench + * @param filename The file + * @return Address of project in which the file is included. + * NULL if the file is not included in any workbench project. + * + **/ +WB_PROJECT *workbench_file_is_included (WORKBENCH *wb, const gchar *filename) +{ + if (wb != NULL) + { + guint index; + WB_PROJECT_ENTRY *current; + + for (index = 0 ; index < wb->projects->len ; index++) + { + current = g_ptr_array_index(wb->projects, index); + if (current != NULL && wb_project_file_is_included(current->project, filename) == TRUE) + { + return current->project; + } + } + } + return NULL; +} + + +/* Add a workbench bookmark */ +static gboolean workbench_add_bookmark_int(WORKBENCH *wb, const gchar *filename) +{ + if (wb != NULL && filename != NULL) + { + gchar *new; + + new = g_strdup(filename); + g_ptr_array_add (wb->bookmarks, new); + return TRUE; + } + return FALSE; +} + + +/** Add a bookmark to a workbench. + * + * @param wb The workbench + * @param filename File to bookmark + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_add_bookmark(WORKBENCH *wb, const gchar *filename) +{ + if (workbench_add_bookmark_int(wb, filename) == TRUE) + { + wb->modified = TRUE; + return TRUE; + } + return FALSE; +} + + +/** Remove a bookmark from a workbench by filename address. + * + * @param wb The workbench + * @param filename File to remove + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_remove_bookmark(WORKBENCH *wb, const gchar *filename) +{ + if (wb != NULL) + { + guint index; + gchar *current; + + for (index = 0 ; index < wb->bookmarks->len ; index++) + { + current = g_ptr_array_index(wb->bookmarks, index); + if (current == filename) + { + g_ptr_array_remove_index (wb->bookmarks, index); + wb->modified = TRUE; + return TRUE; + } + } + } + return FALSE; +} + + +/** Get the bookmark at @a index. + * + * @param wb The workbench + * @param index The index + * @return Address of filename or NULL + * + **/ +gchar *workbench_get_bookmark_at_index (WORKBENCH *wb, guint index) +{ + if (wb != NULL) + { + gchar *file; + file = g_ptr_array_index(wb->bookmarks, index); + if (file == NULL) + { + return NULL; + } + return file; + } + return NULL; +} + + +/** Get the number of bookmarks in a workbench. + * + * @param wb The workbench + * @return The number of bookmarks or 0 if wb == NULL + * + **/ +guint workbench_get_bookmarks_count(WORKBENCH *wb) +{ + if (wb != NULL && wb->bookmarks != NULL) + { + return wb->bookmarks->len; + } + return 0; +} + + +/** Save a workbench. + * + * @param wb The workbench + * @param error Location for returning an GError + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_save(WORKBENCH *wb, GError **error) +{ + gboolean success = FALSE; + + if (wb != NULL) + { + GKeyFile *kf; + guint index; + gchar *contents; + gchar group[20]; + gsize length, boomarks_size; + WB_PROJECT_ENTRY *entry; + + kf = g_key_file_new (); + + /* Save common, simple values */ + g_key_file_set_string(kf, "General", "filetype", "workbench"); + g_key_file_set_string(kf, "General", "version", "1.0"); + g_key_file_set_boolean(kf, "General", "RescanProjectsOnOpen", wb->rescan_projects_on_open); + + /* Save Workbench bookmarks as string list */ + boomarks_size = workbench_get_bookmarks_count(wb); + if (boomarks_size > 0) + { + gchar **bookmarks_strings, *file, *rel_path; + + bookmarks_strings = g_new0(gchar *, boomarks_size+1); + for (index = 0 ; index < boomarks_size ; index++ ) + { + file = workbench_get_bookmark_at_index(wb, index); + rel_path = get_any_relative_path(wb->filename, file); + + bookmarks_strings[index] = rel_path; + } + g_key_file_set_string_list + (kf, "General", "Bookmarks", (const gchar **)bookmarks_strings, boomarks_size); + for (index = 0 ; index < boomarks_size ; index++ ) + { + g_free (bookmarks_strings[index]); + } + g_free(bookmarks_strings); + } + + /* Save projects data */ + for (index = 0 ; index < wb->projects->len ; index++) + { + entry = g_ptr_array_index(wb->projects, index); + g_snprintf(group, sizeof(group), "Project-%u", (index+1)); + g_key_file_set_string(kf, group, "AbsFilename", entry->abs_filename); + g_key_file_set_string(kf, group, "RelFilename", entry->rel_filename); + g_key_file_set_boolean(kf, group, "UseAbsFilename", entry->use_abs); + } + contents = g_key_file_to_data (kf, &length, error); + if (contents != NULL && *error == NULL) + { + g_key_file_free(kf); + + success = g_file_set_contents (wb->filename, contents, length, error); + if (success) + { + wb->modified = FALSE; + } + g_free (contents); + } + } + else if (error != NULL) + { + g_set_error (error, 0, 0, + "Internal error: param missing (file: %s, line %d)", + __FILE__, __LINE__); + } + + return success; +} + + +/** Load a workbench file. + * + * The function loads the workbench settings from file @a filename and + * stores it into @a wb. + * + * @param wb The workbench + * @param filename File to load from + * @param error Location for returning an GError + * @return TRUE on success, FALSE otherwise + * + **/ +gboolean workbench_load(WORKBENCH *wb, const gchar *filename, GError **error) +{ + gboolean success = FALSE; + + if (wb != NULL) + { + GKeyFile *kf; + gboolean valid = TRUE; + guint index; + gchar *contents, **bookmarks_strings; + gchar group[20]; + gsize length; + WB_PROJECT_ENTRY *entry; + + if (!g_file_get_contents (filename, &contents, &length, error)) + { + return FALSE; + } + + kf = g_key_file_new (); + + if (!g_key_file_load_from_data (kf, contents, length, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, + error)) + { + g_key_file_free (kf); + g_free (contents); + return FALSE; + } + + if (g_key_file_has_key (kf, "General", "filetype", NULL) + && g_key_file_has_key (kf, "General", "version", NULL)) + { + gchar *check; + check = g_key_file_get_string (kf, "General", "filetype", error); + if (check == NULL || g_strcmp0(check, "workbench") != 0) + { + valid = FALSE; + } + g_free(check); + } + else + { + valid = FALSE; + } + + if (!valid) + { + g_set_error (error, 0, 0, + _("File %s is not a valid workbench file!"), + filename); + return FALSE; + } + workbench_set_filename(wb, filename); + wb->rescan_projects_on_open = g_key_file_get_boolean(kf, "General", "RescanProjectsOnOpen", error); + + /* Load Workbench bookmarks from string list */ + bookmarks_strings = g_key_file_get_string_list (kf, "General", "Bookmarks", NULL, error); + if (bookmarks_strings != NULL) + { + gchar **file, *abs_path; + + file = bookmarks_strings; + while (*file != NULL) + { + abs_path = get_combined_path(wb->filename, *file); + if (abs_path != NULL) + { + workbench_add_bookmark_int(wb, abs_path); + g_free(abs_path); + } + file++; + } + g_strfreev(bookmarks_strings); + } + + /* Load projects data */ + for (index = 0 ; index < 1024 ; index++) + { + g_snprintf(group, sizeof(group), "Project-%u", (index+1)); + if (g_key_file_has_key (kf, group, "AbsFilename", NULL)) + { + gchar *prj_filename; + entry = wb_project_entry_new(); + if (entry == NULL) + { + continue; + } + entry->abs_filename = g_key_file_get_string(kf, group, "AbsFilename", error); + entry->rel_filename = g_key_file_get_string(kf, group, "RelFilename", error); + entry->use_abs = g_key_file_get_boolean(kf, group, "UseAbsFilename", error); + if (entry->use_abs == TRUE) + { + prj_filename = entry->abs_filename; + } + else + { + prj_filename = get_combined_path + (wb->filename, entry->rel_filename); + } + if (prj_filename != NULL) + { + GStatBuf buf; + + entry->project = wb_project_new(prj_filename); + if (g_stat (prj_filename, &buf) == 0) + { + entry->status = PROJECT_ENTRY_STATUS_OK; + + /* ToDo: collect and handle project load errors */ + wb_project_load(entry->project, prj_filename, error); + } + else + { + entry->status = PROJECT_ENTRY_STATUS_NOT_FOUND; + } + g_ptr_array_add (wb->projects, entry); + + if (wb->rescan_projects_on_open == TRUE) + { + wb_project_rescan(entry->project); + } + } + } + else + { + break; + } + } + + g_key_file_free(kf); + g_free (contents); + success = TRUE; + } + else if (error != NULL) + { + g_set_error (error, 0, 0, + "Internal error: param missing (file: %s, line %d)", + __FILE__, __LINE__); + } + + return success; +} diff --git a/workbench/src/workbench.h b/workbench/src/workbench.h new file mode 100644 index 000000000..bfa9c0ccd --- /dev/null +++ b/workbench/src/workbench.h @@ -0,0 +1,61 @@ +/* + * Copyright 2017 LarsGit223 + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_WORKBENCH_H__ +#define __WB_WORKBENCH_H__ + +#include +#include "wb_project.h" + +typedef enum +{ + PROJECT_ENTRY_STATUS_UNKNOWN, + PROJECT_ENTRY_STATUS_OK, + PROJECT_ENTRY_STATUS_NOT_FOUND, +}PROJECT_ENTRY_STATUS; + +typedef struct S_WORKBENCH WORKBENCH; + +WORKBENCH *workbench_new(void); +void workbench_free(WORKBENCH *wb); + +gboolean workbench_is_empty(WORKBENCH *wb); +guint workbench_get_project_count(WORKBENCH *wb); +gboolean workbench_is_modified(WORKBENCH *wb); +void workbench_set_rescan_projects_on_open(WORKBENCH *wb, gboolean value); +gboolean workbench_get_rescan_projects_on_open(WORKBENCH *wb); +WB_PROJECT *workbench_get_project_at_index(WORKBENCH *wb, guint index); +PROJECT_ENTRY_STATUS workbench_get_project_status_at_index(WORKBENCH *wb, guint index); +PROJECT_ENTRY_STATUS workbench_get_project_status_by_address(WORKBENCH *wb, WB_PROJECT *address); +gboolean workbench_add_project(WORKBENCH *wb, const gchar *filename); +gboolean workbench_remove_project_with_address(WORKBENCH *wb, WB_PROJECT *project); +WB_PROJECT *workbench_file_is_included (WORKBENCH *wb, const gchar *filename); + +void workbench_set_filename(WORKBENCH *wb, const gchar *filename); +const gchar *workbench_get_filename(WORKBENCH *wb); +gchar *workbench_get_name(WORKBENCH *wb); + +gboolean workbench_save(WORKBENCH *wb, GError **error); +gboolean workbench_load(WORKBENCH *wb, const gchar *filename, GError **error); + +gboolean workbench_add_bookmark(WORKBENCH *wb, const gchar *filename); +gboolean workbench_remove_bookmark(WORKBENCH *wb, const gchar *filename); +gchar *workbench_get_bookmark_at_index (WORKBENCH *wb, guint index); +guint workbench_get_bookmarks_count(WORKBENCH *wb); + +#endif