Revision: 2087 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=2087&view=re... Author: techet Date: 2011-05-24 22:22:30 +0000 (Tue, 24 May 2011)
Log Message: ----------- Add the GProject plugin - a simple file-based extension of Geany project
Modified Paths: -------------- trunk/geany-plugins/Makefile.am trunk/geany-plugins/README trunk/geany-plugins/configure.ac trunk/geany-plugins/po/POTFILES.in
Added Paths: ----------- trunk/geany-plugins/build/gproject.m4 trunk/geany-plugins/gproject/ trunk/geany-plugins/gproject/AUTHORS trunk/geany-plugins/gproject/COPYING trunk/geany-plugins/gproject/ChangeLog trunk/geany-plugins/gproject/Makefile.am trunk/geany-plugins/gproject/NEWS trunk/geany-plugins/gproject/README trunk/geany-plugins/gproject/THANKS trunk/geany-plugins/gproject/icons/ trunk/geany-plugins/gproject/icons/Makefile.am trunk/geany-plugins/gproject/icons/gproject-collapse.png trunk/geany-plugins/gproject/icons/gproject-expand.png trunk/geany-plugins/gproject/icons/gproject-file.png trunk/geany-plugins/gproject/icons/gproject-follow.png trunk/geany-plugins/gproject/icons/gproject-header.png trunk/geany-plugins/gproject/icons/gproject-refresh.png trunk/geany-plugins/gproject/icons/gproject-source.png trunk/geany-plugins/gproject/src/ trunk/geany-plugins/gproject/src/Makefile.am trunk/geany-plugins/gproject/src/gproject-main.c trunk/geany-plugins/gproject/src/gproject-menu.c trunk/geany-plugins/gproject/src/gproject-menu.h trunk/geany-plugins/gproject/src/gproject-project.c trunk/geany-plugins/gproject/src/gproject-project.h trunk/geany-plugins/gproject/src/gproject-sidebar.c trunk/geany-plugins/gproject/src/gproject-sidebar.h trunk/geany-plugins/gproject/src/gproject-utils.c trunk/geany-plugins/gproject/src/gproject-utils.h trunk/geany-plugins/gproject/wscript_build trunk/geany-plugins/gproject/wscript_configure
Modified: trunk/geany-plugins/Makefile.am =================================================================== --- trunk/geany-plugins/Makefile.am 2011-05-24 21:55:01 UTC (rev 2086) +++ trunk/geany-plugins/Makefile.am 2011-05-24 22:22:30 UTC (rev 2087) @@ -18,6 +18,7 @@ geanyprj \ geanysendmail \ geanyvc \ + gproject \ pretty-printer \ shiftcolumn \ spellcheck \
Modified: trunk/geany-plugins/README =================================================================== --- trunk/geany-plugins/README 2011-05-24 21:55:01 UTC (rev 2086) +++ trunk/geany-plugins/README 2011-05-24 22:22:30 UTC (rev 2087) @@ -52,6 +52,7 @@ * geanyprj -- the GeanyPrj plugin * geanysendmail -- the GeanySendmail plugin * geanyvc -- the GeanyVC plugin +* gproject -- the GProject plugin * gtkspell -- GeanyVC's spell-check support * pretty_printer -- the pretty-printer plugin * shiftcolumn -- the ShiftColumn plugin
Added: trunk/geany-plugins/build/gproject.m4 =================================================================== --- trunk/geany-plugins/build/gproject.m4 (rev 0) +++ trunk/geany-plugins/build/gproject.m4 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,10 @@ +AC_DEFUN([GP_CHECK_GPROJECT], +[ + GP_ARG_DISABLE([GProject], [yes]) + GP_STATUS_PLUGIN_ADD([GProject], [$enable_gproject]) + AC_CONFIG_FILES([ + gproject/Makefile + gproject/src/Makefile + gproject/icons/Makefile + ]) +])
Modified: trunk/geany-plugins/configure.ac =================================================================== --- trunk/geany-plugins/configure.ac 2011-05-24 21:55:01 UTC (rev 2086) +++ trunk/geany-plugins/configure.ac 2011-05-24 22:22:30 UTC (rev 2087) @@ -43,6 +43,7 @@ GP_CHECK_GEANYSENDMAIL GP_CHECK_GEANYVC GP_CHECK_GEANYPG +GP_CHECK_GPROJECT GP_CHECK_PRETTYPRINTER GP_CHECK_SHIFTCOLUMN GP_CHECK_SPELLCHECK
Added: trunk/geany-plugins/gproject/AUTHORS =================================================================== --- trunk/geany-plugins/gproject/AUTHORS (rev 0) +++ trunk/geany-plugins/gproject/AUTHORS 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1 @@ +Jiří Techet techet@gmail.com
Added: trunk/geany-plugins/gproject/COPYING =================================================================== --- trunk/geany-plugins/gproject/COPYING (rev 0) +++ trunk/geany-plugins/gproject/COPYING 2011-05-24 22:22:30 UTC (rev 2087) @@ -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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 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.
Added: trunk/geany-plugins/gproject/ChangeLog =================================================================== Added: trunk/geany-plugins/gproject/Makefile.am =================================================================== --- trunk/geany-plugins/gproject/Makefile.am (rev 0) +++ trunk/geany-plugins/gproject/Makefile.am 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,8 @@ +if ENABLE_GPROJECT +include $(top_srcdir)/build/vars.auxfiles.mk +else +include $(top_srcdir)/build/vars.docs.mk +endif + +SUBDIRS = src icons +plugin = gproject
Added: trunk/geany-plugins/gproject/NEWS =================================================================== Added: trunk/geany-plugins/gproject/README =================================================================== --- trunk/geany-plugins/gproject/README (rev 0) +++ trunk/geany-plugins/gproject/README 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,199 @@ +======== +GProject +======== + +.. contents:: + +About +===== + +GProject is an extension of Geany's project management displaying a tree of files +belonging to the project in the sidebar. In addition, it enables quick swapping +between header and source files, searching project files by name and more. The plugin +was created with big projects in mind so everything works fast enough even with +projects consisting of hundreds of thousands of files. + +Why was it created? +------------------- + +A project in Geany is completely file-agnostic when it comes to the question of +what files are stored in the project. In principle the information that Geany stores +for every project is: + + * project's base directory + * build settings + * list of open files + +This approach is fine for smaller projects where most of the project files +are stored in a single directory but doesn't work very well with projects consisting +of many deeply nested directories containing thousands of files. For such projects +an expandable tree showing the project files is a better alternative making it much +easier to to navigate between different project directories. + +Why are files belonging to a project defined by patterns? +--------------------------------------------------------- + +Maintaining a list of project files is rather painful with larger projects consisting +of thousands files and many developers working on them. Files are created, deleted +and moved quite frequently and after each change the project has to be updated manually. +Instead, GProject defines a list of files belonging to the project implicitly using: + + * project's base directory + * a list of glob-like patterns + +Every file under the base directory matching the patterns is included into the project +and updating the file list is as simple as pressing the refresh button. + +What are the differences between GProject and GeanyPrj? +------------------------------------------------------- + +There is another project-management Geany plugin - GeanyPrj. GProject and GeanyPrj differ +in several aspects: + + * GProject is an extension of Geany's project so every Geany project is a GProject + at the same time and vice versa. On the other hand, GeanyPrj project is a separate + project so if you want to set build properties for a GeanyPrj project, you have to + set up a second Geany project in parallel. + * Because GeanyPrj is a separate project management plugin, it can do some things that + GProject cannot - in particular, it can manage several projects in parallel. + If you need to switch between several projects, GeanyPrj might be a better option + for you. Alternatively, you can open several Geany instances for different projects + to work on several projects in parallel using GProject. + * GProject displays full tree in the sidebar while GeanyPrj displays only two-level + tree (full directory name as a parent and a list of files under the directory). + * GProject has configurable patterns while patterns in GeanyPrj are hard-coded + * GProject offers header/source swapping + * GProject offers finding project files by name + +Usage +===== + +Project configuration +--------------------- + +Upon project creation, you should define the list of file patterns under the +Project->Properties Project tab. For instance, for a typical open source C project, +use patterns "*.c *h *.am *.ac" to see the source files together with +automake and autoconf files. After closing the dialog, the files matching the patterns +should appear in the sidebar under the Project tab (unless the GProject plugin +was loaded after the project - see Known Issues for more details). + +Additional settings is available from the GProject tab under the Project properties +dialog. You can define patterns to distinguish between header and source files for +C-like languages. This information is used for header/source swapping and also for +giving different icons to headers and sources in the sidebar (therefore, this settings +can be also used for other types of languages if you want to give different file +types different icons). + +In addition, you can define patterns for directories that should be ignored when +searching for files belonging to the project. These will typically be various +VCS or hidden directories. + +Finally, you can specify whether the tag manager should be used to index all the project +files or not. This settings is turned off by default because the indexing takes too +long when too many files are present in the project (several thousands or more). + +Sidebar +------- + +The sidebar contains a tree of files belonging to the project. Directories can be expanded +by double-clicking them; the same action is used to open files. When a sidebar item +is right-clicked, a context menu appears: + + * Expand all - recursively expands all the subdirectories of the given directory + * Find in files - opens the Find in files dialog and sets the search directory + to the clicked directory + * Find file - opens the Find file dialog and sets the search directory to the + clicked directory + +The following actions can be invoked from the sidebar's toolbar: + + * Reload all - reloads the project file tree. This is useful when files were added or + removed from the project. + * Expand all - recursively expands all the directories + * Collapse all - recursively collapses all the directories + * Follow active editor - automatically selects the current file in the sidebar + when the user switches to another file. It auto-expands the tree to reveal the selected + file. + +Project menu entries +-------------------- + +GProject adds some extra entries under the Project menu: + + * Find in Project Files - opens the Find in files dialog and sets the search directory + to the base directory of the project + * Find Project File - opens the Find file dialog and sets the search directory to the + base directory of the project + * Swap Header/Source - if the current file matches one of the source patterns from + the properties, it opens a project file with the same base name (without extension) + matching header patterns (and vice versa). If the files are already open, it + just switches the document tabs. Nothing happens if no matching file is found. + +Each of these entries can be assigned a key binding under Edit->Preferences->Keybindings. + +Find file dialog +---------------- + +The Find file dialog can be invoked either from the Project menu or from the +sidebar's context menu. Searches are performed recursively, starting from the +"Search inside" directory. All files having the searched string as a substring of their +name are displayed in the Messages window. Clicking the file name opens the file. +The following search properties are configurable: + + * Case sensitive - specifies whether the searches should be case-sensitive + * Search in full path - when not checked, the search is performed in the file + name only (excluding path); when checked, the search is performed in the full path + +Editor context menu +------------------- + +GProject adds an extra entry into the context menu of the editor: + + * Open Selected File (GProject) - contrary to the Open Selected File entry present + in Geany it also searches for the file in project files + +Known issues +============ + + * When the plugin is loaded from the Plugin Manager for the first time and a project + is already open, no files are displayed in the sidebar. The workaround is to + reload the project in this case. The issue is caused by Geany only passing the project + configuration file to a plugin when the project is loaded, which isn't the case when + the plugin is loaded. + * There might be some issues with UTF8 file names - the testing has been very + limited. + * GProject hasn't been tested under Windows so probably not everything works there. + Patches are welcome. + +License +======= + +GProject 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 +========= + +GProject is part of the combined Geany Plugins release. +For more information and downloads, please visit +http://plugins.geany.org/geany-plugins/ + +Development Code +================ + +Get the code from:: + + svn checkout http://geany-plugins.svn.sourceforge.net/svnroot/geany-plugins/trunk/geany-p... + +Ideas, questions, patches and bug reports +========================================= + +If you add something, or fix a bug, please send a patch (in 'diff -u' +format) to the geany mailing list or to one of the authors listed bellow. + +2010-2011 by Jiří Techet +techet(at)gmail(dot)com
Added: trunk/geany-plugins/gproject/THANKS =================================================================== --- trunk/geany-plugins/gproject/THANKS (rev 0) +++ trunk/geany-plugins/gproject/THANKS 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,8 @@ +What's this file about? +----------------------- +This file lists all external people that have contributed to this project. + +Testers and contributors: +------------------------- +Yura Siamashka <yurand2(at)gmail(dot)com> - author of GeanyPrj which served as a base of this plugin +People on Geany mailing list who contributed with valuable comments and suggestions
Added: trunk/geany-plugins/gproject/icons/Makefile.am =================================================================== --- trunk/geany-plugins/gproject/icons/Makefile.am (rev 0) +++ trunk/geany-plugins/gproject/icons/Makefile.am 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,30 @@ +icondir = $(datadir)/icons/hicolor/16x16/apps + +ICONS = \ + gproject-file.png \ + gproject-header.png \ + gproject-source.png \ + gproject-expand.png \ + gproject-collapse.png \ + gproject-follow.png \ + gproject-refresh.png + +EXTRA_DIST = $(ICONS) + +gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor +install-data-hook: update-icon-cache +uninstall-hook: update-icon-cache +update-icon-cache: + @-if test -z "$(DESTDIR)"; then \ + echo "Updating Gtk icon cache."; \ + $(gtk_update_icon_cache); \ + else \ + echo "*** Icon cache not updated. After (un)install, run this:"; \ + echo "*** $(gtk_update_icon_cache)"; \ + fi + +if ENABLE_GPROJECT +icon_DATA = $(ICONS) +else +EXTRA_DATA = $(ICONS) +endif
Added: trunk/geany-plugins/gproject/icons/gproject-collapse.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-collapse.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-expand.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-expand.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-file.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-file.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-follow.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-follow.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-header.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-header.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-refresh.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-refresh.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/icons/gproject-source.png =================================================================== (Binary files differ)
Property changes on: trunk/geany-plugins/gproject/icons/gproject-source.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream
Added: trunk/geany-plugins/gproject/src/Makefile.am =================================================================== --- trunk/geany-plugins/gproject/src/Makefile.am (rev 0) +++ trunk/geany-plugins/gproject/src/Makefile.am 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,23 @@ +include $(top_srcdir)/build/vars.build.mk + +if ENABLE_GPROJECT +geanyplugins_LTLIBRARIES = gproject.la +else +EXTRA_LTLIBRARIES = gproject.la +endif +gproject_la_SOURCES = \ + gproject-main.c \ + gproject-project.h \ + gproject-project.c \ + gproject-sidebar.h \ + gproject-sidebar.c \ + gproject-utils.h \ + gproject-utils.c \ + gproject-menu.h \ + gproject-menu.c + +gproject_la_CFLAGS = $(AM_CFLAGS) +gproject_la_LIBADD = $(COMMONLIBS) + +include $(top_srcdir)/build/cppcheck.mk +
Added: trunk/geany-plugins/gproject/src/gproject-main.c =================================================================== --- trunk/geany-plugins/gproject/src/gproject-main.c (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-main.c 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,171 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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. + */ + +#include <sys/time.h> +#include <string.h> + +#include <geany/geanyplugin.h> + +#include "gproject-project.h" +#include "gproject-sidebar.h" +#include "gproject-menu.h" + +PLUGIN_VERSION_CHECK(211); +PLUGIN_SET_INFO(_("GProject"), + _("Glob-pattern-based project management plugin for Geany."), + VERSION, + "Jiri Techet techet@gmail.com"); + +GeanyPlugin *geany_plugin; +GeanyData *geany_data; +GeanyFunctions *geany_functions; + + +void plugin_init(G_GNUC_UNUSED GeanyData * data); +void plugin_cleanup(void); + + +static void on_doc_open(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GeanyDocument * doc, + G_GNUC_UNUSED gpointer user_data) +{ + g_return_if_fail(doc != NULL && doc->file_name != NULL); + + //tags of open files managed by geany + if (gprj_project_is_in_project(doc->file_name)) + gprj_project_remove_file_tag(doc->file_name); + + gprj_sidebar_update(FALSE); +} + + +static void on_doc_activate(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GeanyDocument * doc, + G_GNUC_UNUSED gpointer user_data) +{ + g_return_if_fail(doc != NULL && doc->file_name != NULL); + + gprj_sidebar_update(FALSE); +} + + +static void on_doc_close(G_GNUC_UNUSED GObject * obj, GeanyDocument * doc, + G_GNUC_UNUSED gpointer user_data) +{ + g_return_if_fail(doc != NULL && doc->file_name != NULL); + + //tags of open files managed by geany - when the file gets closed, we should take care of it + if (gprj_project_is_in_project(doc->file_name)) + gprj_project_add_file_tag(doc->file_name); + + gprj_sidebar_update(FALSE); +} + + +static void on_build_start(GObject *obj, gpointer user_data) +{ + gint i; + + foreach_document(i) + { + if (gprj_project_is_in_project(documents[i]->file_name)) + document_save_file(documents[i], FALSE); + } +} + + +static void on_project_dialog_create(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, + G_GNUC_UNUSED gpointer user_data) +{ + gprj_project_add_properties_tab(notebook); +} + + +static void on_project_dialog_confirmed(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, + G_GNUC_UNUSED gpointer user_data) +{ + gprj_project_read_properties_tab(); + gprj_sidebar_update(TRUE); +} + + +static void on_project_open(G_GNUC_UNUSED GObject * obj, GKeyFile * config, + G_GNUC_UNUSED gpointer user_data) +{ + gprj_project_open(config); + gprj_sidebar_update(TRUE); + gprj_sidebar_activate(TRUE); + gprj_menu_activate_menu_items(TRUE); +} + + +static void on_project_close(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED gpointer user_data) +{ + gprj_project_close(); + gprj_sidebar_update(TRUE); + gprj_sidebar_activate(FALSE); + gprj_menu_activate_menu_items(FALSE); +} + + +static void on_project_save(G_GNUC_UNUSED GObject * obj, GKeyFile * config, + G_GNUC_UNUSED gpointer user_data) +{ + if (!g_prj) + { + //happens when the project is created + gprj_project_open(config); + gprj_sidebar_update(TRUE); + gprj_sidebar_activate(TRUE); + gprj_menu_activate_menu_items(TRUE); + } + + gprj_project_save(config); +} + + +PluginCallback plugin_callbacks[] = { + {"document-open", (GCallback) & on_doc_open, TRUE, NULL}, + {"document-activate", (GCallback) & on_doc_activate, TRUE, NULL}, + {"document-close", (GCallback) & on_doc_close, TRUE, NULL}, + {"build-start", (GCallback) & on_build_start, TRUE, NULL}, + {"project-dialog-create", (GCallback) & on_project_dialog_create, TRUE, NULL}, + {"project-dialog-confirmed", (GCallback) & on_project_dialog_confirmed, TRUE, NULL}, + {"project-open", (GCallback) & on_project_open, TRUE, NULL}, + {"project-close", (GCallback) & on_project_close, TRUE, NULL}, + {"project-save", (GCallback) & on_project_save, TRUE, NULL}, + {NULL, NULL, FALSE, NULL} +}; + + +void plugin_init(G_GNUC_UNUSED GeanyData * data) +{ + gprj_menu_init(); + gprj_sidebar_init(); +} + + +void plugin_cleanup(void) +{ + if (geany_data->app->project) + { + gprj_project_close(); + gprj_sidebar_update(TRUE); + } + + gprj_menu_cleanup(); + gprj_sidebar_cleanup(); +}
Added: trunk/geany-plugins/gproject/src/gproject-menu.c =================================================================== --- trunk/geany-plugins/gproject/src/gproject-menu.c (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-menu.c 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,406 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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. + */ + +#include <sys/time.h> +#include <gdk/gdkkeysyms.h> +#include <glib/gstdio.h> + +#include <geany/geanyplugin.h> + +#include "gproject-menu.h" +#include "gproject-project.h" +#include "gproject-utils.h" +#include "gproject-sidebar.h" + +#include <string.h> + +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + + +enum +{ + KB_SWAP_HEADER_SOURCE, + KB_FIND_IN_PROJECT, + KB_FIND_FILE, + KB_COUNT +}; + +PLUGIN_KEY_GROUP(gproject, KB_COUNT); + + +static GtkWidget *s_fif_item, *s_ff_item, *s_shs_item, *s_sep_item, *s_context_osf_item, *s_context_sep_item; + + +static gboolean try_swap_header_source(gchar *file_name, gboolean is_header, GSList *file_list, GSList *header_patterns, GSList *source_patterns) +{ + gchar *name_pattern; + gchar *base_name = NULL; + GSList *elem; + GPatternSpec *pattern; + gboolean found = FALSE; + + name_pattern = g_path_get_basename(file_name); + setptr(name_pattern, utils_remove_ext_from_filename(name_pattern)); + setptr(name_pattern, g_strconcat(name_pattern, ".*", NULL)); + pattern = g_pattern_spec_new(name_pattern); + g_free(name_pattern); + + for (elem = file_list; elem != NULL; elem = g_slist_next(elem)) + { + gchar *full_name = elem->data; + base_name = g_path_get_basename(full_name); + + if (g_pattern_match_string(pattern, base_name) && + gprj_project_is_in_project(full_name)) + { + if ((is_header && patterns_match(source_patterns, base_name)) || + (!is_header && patterns_match(header_patterns, base_name))) + { + open_file(full_name); + found = TRUE; + break; + } + } + } + + g_free(base_name); + g_pattern_spec_free(pattern); + return found; +} + + +static void get_project_file_list(char *file_name, G_GNUC_UNUSED gpointer value, GSList **list) +{ + *list = g_slist_prepend(*list, file_name); +} + + +static void on_swap_header_source(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GSList *header_patterns, *source_patterns; + GeanyDocument *doc; + gboolean known_type = TRUE; + gboolean is_header; + gchar *doc_basename; + doc = document_get_current(); + + if (!g_prj || !geany_data->app->project || !doc || !doc->file_name) + return; + + header_patterns = get_precompiled_patterns(g_prj->header_patterns); + source_patterns = get_precompiled_patterns(g_prj->source_patterns); + + doc_basename = g_path_get_basename(doc->file_name); + + if (patterns_match(header_patterns, doc_basename)) + is_header = TRUE; + else if (patterns_match(source_patterns, doc_basename)) + is_header = FALSE; + else + known_type = FALSE; + + if (known_type) + { + gboolean swapped; + GSList *elem, *list = NULL; + gint i; + + foreach_document(i) + { + gchar *filename; + + filename = document_index(i)->file_name; + if (gprj_project_is_in_project(filename)) + list = g_slist_prepend(list, filename); + } + swapped = try_swap_header_source(doc->file_name, is_header, list, header_patterns, source_patterns); + g_slist_free(list); + list = NULL; + + if (!swapped) + { + gchar *doc_dir; + + doc_dir = g_path_get_dirname(doc->file_name); + setptr(doc_dir, utils_get_locale_from_utf8(doc_dir)); + + list = utils_get_file_list(doc_dir, NULL, NULL); + for (elem = list; elem != NULL; elem = g_slist_next(elem)) + { + gchar *full_name; + + full_name = g_build_filename(doc_dir, elem->data, NULL); + setptr(full_name, utils_get_utf8_from_locale(full_name)); + setptr(elem->data, full_name); + } + swapped = try_swap_header_source(doc->file_name, is_header, list, header_patterns, source_patterns); + g_slist_foreach(list, (GFunc) g_free, NULL); + g_slist_free(list); + g_free(doc_dir); + list = NULL; + } + + if (!swapped) + { + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc) get_project_file_list, &list); + try_swap_header_source(doc->file_name, is_header, list, header_patterns, source_patterns); + g_slist_free(list); + } + } + + g_free(doc_basename); + + g_slist_foreach(header_patterns, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(header_patterns); + g_slist_foreach(source_patterns, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(source_patterns); +} + + +static void on_find_in_project(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + if (geany_data->app->project) + search_show_find_in_files_dialog(geany_data->app->project->base_path); +} + + +static void on_find_file(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + if (geany_data->app->project) + gprj_sidebar_find_file_in_active(); +} + + +static void kb_callback(guint key_id) +{ + switch (key_id) + { + case KB_SWAP_HEADER_SOURCE: + on_swap_header_source(NULL, NULL); + break; + case KB_FIND_IN_PROJECT: + on_find_in_project(NULL, NULL); + break; + case KB_FIND_FILE: + on_find_file(NULL, NULL); + break; + } +} + + +typedef struct +{ + gchar *subpath; + gchar *found_path; +} FindData; + + +static void find_name(char *file_name, G_GNUC_UNUSED gpointer value, FindData *data) +{ + gchar *pos; + + if (data->found_path) + return; + + pos = g_strrstr(file_name, data->subpath); + if (pos && (pos - file_name + strlen(data->subpath) == strlen(file_name))) + data->found_path = file_name; +} + + +static void on_open_selected_file(GtkMenuItem *menuitem, gpointer user_data) +{ + GeanyDocument *doc = document_get_current(); + gchar *sel = NULL; + gchar *filename = NULL; + gchar *path = NULL; + + g_return_if_fail(doc != NULL); + + sel = get_selection(); + + if (!sel) + return; + + setptr(sel, utils_get_locale_from_utf8(sel)); + + if (g_path_is_absolute(sel)) + { + filename = g_strdup(sel); + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + g_free(filename); + filename = NULL; + } + } + + if (!filename) + { + if (doc->file_name) + { + path = g_path_get_dirname(doc->file_name); + setptr(path, utils_get_locale_from_utf8(path)); + } + + if (!path) + path = g_get_current_dir(); + + filename = g_build_path(G_DIR_SEPARATOR_S, path, sel, NULL); + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + g_free(filename); + filename = NULL; + } + + g_free(path); + } + + if (!filename && geany_data->app->project != NULL) + { + gchar **pathv; + gint i; + + path = g_strdup(""); + pathv = g_strsplit_set(sel, "/\", -1); + for (i = g_strv_length(pathv) - 1; i >= 0; i--) + { + if (g_strcmp0(pathv[i], "..") == 0) + break; + setptr(path, g_build_filename(G_DIR_SEPARATOR_S, pathv[i], path, NULL)); + } + g_strfreev(pathv); + + if (g_strcmp0(path, "") != 0) + { + FindData data; + + data.subpath = path; + data.found_path = NULL; + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc)find_name, &data); + if (data.found_path) + { + filename = g_strdup(data.found_path); + setptr(filename, utils_get_locale_from_utf8(filename)); + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + g_free(filename); + filename = NULL; + } + } + } + g_free(path); + } + +#ifdef G_OS_UNIX + if (!filename) + { + filename = g_build_path(G_DIR_SEPARATOR_S, "/usr/local/include", sel, NULL); + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + g_free(filename); + filename = NULL; + } + } + + if (!filename) + { + filename = g_build_path(G_DIR_SEPARATOR_S, "/usr/include", sel, NULL); + if (!g_file_test(filename, G_FILE_TEST_EXISTS)) + { + g_free(filename); + filename = NULL; + } + } +#endif + + if (filename) + open_file(filename); + + g_free(filename); + g_free(sel); +} + + +void gprj_menu_init() +{ + GtkWidget *image; + + s_sep_item = gtk_separator_menu_item_new(); + gtk_widget_show(s_sep_item); + gtk_container_add(GTK_CONTAINER(geany->main_widgets->project_menu), s_sep_item); + + image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); + gtk_widget_show(image); + s_fif_item = gtk_image_menu_item_new_with_mnemonic(_("Find in Project Files")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(s_fif_item), image); + gtk_widget_show(s_fif_item); + gtk_container_add(GTK_CONTAINER(geany->main_widgets->project_menu), s_fif_item); + g_signal_connect((gpointer) s_fif_item, "activate", G_CALLBACK(on_find_in_project), NULL); + keybindings_set_item(plugin_key_group, KB_FIND_IN_PROJECT, kb_callback, + 0, 0, "find_in_project", _("Find in project files"), s_fif_item); + + image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); + gtk_widget_show(image); + s_ff_item = gtk_image_menu_item_new_with_mnemonic(_("Find Project File")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(s_ff_item), image); + gtk_widget_show(s_ff_item); + gtk_container_add(GTK_CONTAINER(geany->main_widgets->project_menu), s_ff_item); + g_signal_connect((gpointer) s_ff_item, "activate", G_CALLBACK(on_find_file), NULL); + keybindings_set_item(plugin_key_group, KB_FIND_FILE, kb_callback, + 0, 0, "find_file", _("Find project file"), s_ff_item); + + s_shs_item = gtk_menu_item_new_with_mnemonic(_("Swap Header/Source")); + gtk_widget_show(s_shs_item); + gtk_container_add(GTK_CONTAINER(geany->main_widgets->project_menu), s_shs_item); + g_signal_connect((gpointer) s_shs_item, "activate", G_CALLBACK(on_swap_header_source), NULL); + keybindings_set_item(plugin_key_group, KB_SWAP_HEADER_SOURCE, kb_callback, + 0, 0, "swap_header_source", _("Swap header/source"), s_shs_item); + + s_context_sep_item = gtk_separator_menu_item_new(); + gtk_widget_show(s_context_sep_item); + gtk_menu_shell_prepend(GTK_MENU_SHELL(geany->main_widgets->editor_menu), s_context_sep_item); + + s_context_osf_item = gtk_menu_item_new_with_mnemonic(_("Open Selected File (gproject)")); + gtk_widget_show(s_context_osf_item); + gtk_menu_shell_prepend(GTK_MENU_SHELL(geany->main_widgets->editor_menu), s_context_osf_item); + g_signal_connect((gpointer) s_context_osf_item, "activate", G_CALLBACK(on_open_selected_file), NULL); + + gprj_menu_activate_menu_items(FALSE); +} + + +void gprj_menu_activate_menu_items(gboolean activate) +{ + gtk_widget_set_sensitive(s_context_osf_item, activate); + gtk_widget_set_sensitive(s_shs_item, activate); + gtk_widget_set_sensitive(s_ff_item, activate); + gtk_widget_set_sensitive(s_fif_item, activate); +} + + +void gprj_menu_cleanup() +{ + gtk_widget_destroy(s_fif_item); + gtk_widget_destroy(s_ff_item); + gtk_widget_destroy(s_shs_item); + gtk_widget_destroy(s_sep_item); + + gtk_widget_destroy(s_context_osf_item); + gtk_widget_destroy(s_context_sep_item); +}
Added: trunk/geany-plugins/gproject/src/gproject-menu.h =================================================================== --- trunk/geany-plugins/gproject/src/gproject-menu.h (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-menu.h 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,26 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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 __GPROJECT_MENU_H__ +#define __GPROJECT_MENU_H__ + +void gprj_menu_init(void); +void gprj_menu_activate_menu_items(gboolean activate); +void gprj_menu_cleanup(void); + +#endif
Added: trunk/geany-plugins/gproject/src/gproject-project.c =================================================================== --- trunk/geany-plugins/gproject/src/gproject-project.c (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-project.c 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,406 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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. + */ + +#include <sys/time.h> +#include <gdk/gdkkeysyms.h> +#include <glib/gstdio.h> + +#include <geany/geanyplugin.h> + +#include "gproject-utils.h" +#include "gproject-project.h" + +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + +typedef struct +{ + GtkWidget *source_patterns; + GtkWidget *header_patterns; + GtkWidget *ignored_dirs_patterns; + GtkWidget *generate_tags; +} PropertyDialogElements; + +GPrj *g_prj = NULL; + +static PropertyDialogElements *e; + + +static void workspace_remove_tag(gchar *filename, TagObject *obj, gpointer foo) +{ + if (obj->tag) + { + tm_workspace_remove_object(obj->tag, TRUE, TRUE); + obj->tag = NULL; + } +} + + +static void workspace_add_tag(gchar *filename, TagObject *obj, gpointer foo) +{ + TMWorkObject *tm_obj = NULL; + + if (!document_find_by_filename(filename)) + { + gchar *locale_filename; + + locale_filename = utils_get_locale_from_utf8(filename); + tm_obj = tm_source_file_new(locale_filename, FALSE, filetypes_detect_from_file(filename)->name); + g_free(locale_filename); + + tm_workspace_add_object(tm_obj); + tm_source_file_update(tm_obj, TRUE, FALSE, TRUE); + } + + if (obj->tag) + tm_workspace_remove_object(obj->tag, TRUE, TRUE); + + obj->tag = tm_obj; +} + + +/* path - absolute path in locale, returned list in locale */ +static GSList *get_file_list(const gchar * path, GSList *patterns, GSList *ignored_dirs_patterns) +{ + GSList *list = NULL; + GDir *dir; + + dir = g_dir_open(path, 0, NULL); + if (!dir) + return NULL; + + while (TRUE) + { + const gchar *name; + gchar *filename; + + name = g_dir_read_name(dir); + if (!name) + break; + + filename = g_build_filename(path, name, NULL); + + if (g_file_test(filename, G_FILE_TEST_IS_DIR)) + { + GSList *lst; + + if (patterns_match(ignored_dirs_patterns, name)) + { + g_free(filename); + continue; + } + + lst = get_file_list(filename, patterns, ignored_dirs_patterns); + if (lst) + list = g_slist_concat(list, lst); + g_free(filename); + } + else if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + { + if (patterns_match(patterns, name)) + list = g_slist_prepend(list, filename); + else + g_free(filename); + } + } + + g_dir_close(dir); + + return list; +} + + +void gprj_project_rescan() +{ + GSList *pattern_list = NULL; + GSList *ignored_dirs_list = NULL; + GSList *lst; + GSList *elem; + + if (!g_prj) + return; + + if (g_prj->generate_tags) + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc)workspace_remove_tag, NULL); + g_hash_table_destroy(g_prj->file_tag_table); + g_prj->file_tag_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + pattern_list = get_precompiled_patterns(geany_data->app->project->file_patterns); + + ignored_dirs_list = get_precompiled_patterns(g_prj->ignored_dirs_patterns); + + lst = get_file_list(geany_data->app->project->base_path, pattern_list, ignored_dirs_list); + + for (elem = lst; elem != NULL; elem = g_slist_next(elem)) + { + char *path; + TagObject *obj; + + obj = g_new0(TagObject, 1); + obj->tag = NULL; + + path = tm_get_real_path(elem->data); + setptr(path, utils_get_utf8_from_locale(path)); + g_hash_table_insert(g_prj->file_tag_table, path, obj); + } + + if (g_prj->generate_tags) + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc)workspace_add_tag, NULL); + + 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); +} + + +static void update_project( + gchar **source_patterns, + gchar **header_patterns, + gchar **ignored_dirs_patterns, + gboolean generate_tags) +{ + if (g_prj->source_patterns) + g_strfreev(g_prj->source_patterns); + g_prj->source_patterns = g_strdupv(source_patterns); + + if (g_prj->header_patterns) + g_strfreev(g_prj->header_patterns); + g_prj->header_patterns = g_strdupv(header_patterns); + + if (g_prj->ignored_dirs_patterns) + g_strfreev(g_prj->ignored_dirs_patterns); + g_prj->ignored_dirs_patterns = g_strdupv(ignored_dirs_patterns); + + g_prj->generate_tags = generate_tags; + + gprj_project_rescan(); +} + + +void gprj_project_save(GKeyFile * key_file) +{ + if (!g_prj) + return; + + g_key_file_set_string_list(key_file, "gproject", "source_patterns", + (const gchar**) g_prj->source_patterns, g_strv_length(g_prj->source_patterns)); + g_key_file_set_string_list(key_file, "gproject", "header_patterns", + (const gchar**) g_prj->header_patterns, g_strv_length(g_prj->header_patterns)); + g_key_file_set_string_list(key_file, "gproject", "ignored_dirs_patterns", + (const gchar**) g_prj->ignored_dirs_patterns, g_strv_length(g_prj->ignored_dirs_patterns)); + g_key_file_set_boolean(key_file, "gproject", "generate_tags", g_prj->generate_tags); +} + + +void gprj_project_open(GKeyFile * key_file) +{ + gchar **source_patterns, **header_patterns, **ignored_dirs_patterns; + gboolean generate_tags; + + if (g_prj != NULL) + gprj_project_close(); + + g_prj = (GPrj *) g_new0(GPrj, 1); + + g_prj->source_patterns = NULL; + g_prj->header_patterns = NULL; + g_prj->ignored_dirs_patterns = NULL; + g_prj->generate_tags = FALSE; + + g_prj->file_tag_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + source_patterns = g_key_file_get_string_list(key_file, "gproject", "source_patterns", NULL, NULL); + if (!source_patterns) + source_patterns = g_strsplit("*.c *.C *.cpp *.cxx *.c++ *.cc", " ", -1); + header_patterns = g_key_file_get_string_list(key_file, "gproject", "header_patterns", NULL, NULL); + if (!header_patterns) + header_patterns = g_strsplit("*.h *.H *.hpp *.hxx *.h++ *.hh *.m", " ", -1); + ignored_dirs_patterns = g_key_file_get_string_list(key_file, "gproject", "ignored_dirs_patterns", NULL, NULL); + if (!ignored_dirs_patterns) + ignored_dirs_patterns = g_strsplit(".* CVS", " ", -1); + generate_tags = utils_get_setting_boolean(key_file, "gproject", "generate_tags", FALSE); + + update_project( + source_patterns, + header_patterns, + ignored_dirs_patterns, + generate_tags); + + g_free(source_patterns); + g_free(header_patterns); + g_free(ignored_dirs_patterns); +} + + +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; +} + + +void gprj_project_read_properties_tab() +{ + gchar **source_patterns, **header_patterns, **ignored_dirs_patterns; + + source_patterns = split_patterns(gtk_entry_get_text(GTK_ENTRY(e->source_patterns))); + header_patterns = split_patterns(gtk_entry_get_text(GTK_ENTRY(e->header_patterns))); + ignored_dirs_patterns = split_patterns(gtk_entry_get_text(GTK_ENTRY(e->ignored_dirs_patterns))); + + update_project( + source_patterns, header_patterns, ignored_dirs_patterns, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(e->generate_tags))); + + g_free(source_patterns); + g_free(header_patterns); + g_free(ignored_dirs_patterns); +} + + +void gprj_project_add_properties_tab(GtkWidget *notebook) +{ + GtkWidget *vbox, *hbox, *hbox1; + GtkWidget *table; + GtkWidget *label; + gchar *str; + + e = g_new0(PropertyDialogElements, 1); + + vbox = gtk_vbox_new(FALSE, 0); + + table = gtk_table_new(3, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + + label = gtk_label_new(_("Source patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + e->source_patterns = gtk_entry_new(); + ui_table_add_row(GTK_TABLE(table), 0, label, e->source_patterns, NULL); + ui_entry_add_clear_icon(GTK_ENTRY(e->source_patterns)); + ui_widget_set_tooltip_text(e->source_patterns, + _("Space separated list of patterns that are used to identify source files.")); + str = g_strjoinv(" ", g_prj->source_patterns); + gtk_entry_set_text(GTK_ENTRY(e->source_patterns), str); + g_free(str); + + label = gtk_label_new(_("Header patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + e->header_patterns = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(e->header_patterns)); + ui_table_add_row(GTK_TABLE(table), 1, label, e->header_patterns, NULL); + ui_widget_set_tooltip_text(e->header_patterns, + _("Space separated list of patterns that are used to identify headers. " + "Used mainly for header/source swapping.")); + str = g_strjoinv(" ", g_prj->header_patterns); + gtk_entry_set_text(GTK_ENTRY(e->header_patterns), str); + g_free(str); + + label = gtk_label_new(_("Ignored dirs patterns:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + e->ignored_dirs_patterns = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(e->ignored_dirs_patterns)); + ui_table_add_row(GTK_TABLE(table), 2, label, e->ignored_dirs_patterns, NULL); + ui_widget_set_tooltip_text(e->ignored_dirs_patterns, + _("Space separated list of patterns that are used to identify directories " + "that are not scanned for source files.")); + str = g_strjoinv(" ", g_prj->ignored_dirs_patterns); + gtk_entry_set_text(GTK_ENTRY(e->ignored_dirs_patterns), str); + g_free(str); + + gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 6); + + e->generate_tags = gtk_check_button_new_with_label(_("Generate tags for all project files")); + ui_widget_set_tooltip_text(e->generate_tags, + _("Generate tag list for all project files instead of only for the currently opened files. " + "Too slow for big projects (>1000 files) and should be disabled in this case.")); + gtk_box_pack_start(GTK_BOX(vbox), e->generate_tags, FALSE, FALSE, 6); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e->generate_tags), g_prj->generate_tags); + + hbox1 = gtk_hbox_new(FALSE, 0); + label = gtk_label_new(_("Note: set the patterns of files belonging to the project under the Project tab.")); + gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 6); + + label = gtk_label_new(_("GProject")); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label); +} + + +void gprj_project_close() +{ + g_return_if_fail(g_prj); + + if (g_prj->generate_tags) + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc)workspace_remove_tag, NULL); + + g_free(g_prj->source_patterns); + g_free(g_prj->header_patterns); + g_free(g_prj->ignored_dirs_patterns); + + g_hash_table_destroy(g_prj->file_tag_table); + + g_free(g_prj); + g_prj = NULL; +} + + +void gprj_project_add_file_tag(gchar *filename) +{ + TagObject *obj; + + obj = g_hash_table_lookup(g_prj->file_tag_table, filename); + if (obj) + workspace_add_tag(filename, obj, NULL); +} + + +void gprj_project_remove_file_tag(gchar *filename) +{ + TagObject *obj; + + obj = g_hash_table_lookup(g_prj->file_tag_table, filename); + if (obj) + workspace_remove_tag(filename, obj, NULL); +} + + +gboolean gprj_project_is_in_project(const gchar * filename) +{ + return filename && g_prj && geany_data->app->project && + g_hash_table_lookup(g_prj->file_tag_table, filename) != NULL; +}
Added: trunk/geany-plugins/gproject/src/gproject-project.h =================================================================== --- trunk/geany-plugins/gproject/src/gproject-project.h (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-project.h 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,58 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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 __GPROJECT_PROJECT_H__ +#define __GPROJECT_PROJECT_H__ + + +typedef struct +{ + TMWorkObject *tag; +} TagObject; + + +typedef struct +{ + gchar **source_patterns; + gchar **header_patterns; + gchar **ignored_dirs_patterns; + gboolean generate_tags; + + GHashTable *file_tag_table; +} GPrj; + +extern GPrj *g_prj; + +void gprj_project_open(GKeyFile * key_file); + +void gprj_project_add_properties_tab(GtkWidget *notebook); + +void gprj_project_close(void); + +void gprj_project_save(GKeyFile * key_file); +void gprj_project_read_properties_tab(void); +void gprj_project_rescan(void); + + +void gprj_project_add_file_tag(gchar *filename); +void gprj_project_remove_file_tag(gchar *filename); + +gboolean gprj_project_is_in_project(const gchar * filename); + + +#endif
Added: trunk/geany-plugins/gproject/src/gproject-sidebar.c =================================================================== --- trunk/geany-plugins/gproject/src/gproject-sidebar.c (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-sidebar.c 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,841 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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. + */ + +#include <sys/time.h> +#include <gdk/gdkkeysyms.h> +#include <string.h> + +#include <geany/geanyplugin.h> + +#include "gproject-utils.h" +#include "gproject-project.h" +#include "gproject-sidebar.h" + +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + +enum +{ + FILEVIEW_COLUMN_ICON, + FILEVIEW_COLUMN_NAME, + FILEVIEW_N_COLUMNS, +}; + + +static GtkWidget *s_file_view_vbox = NULL; +static GtkWidget *s_file_view = NULL; +static GtkTreeStore *s_file_store = NULL; +static gboolean s_follow_editor = FALSE; + +static struct +{ + GtkWidget *widget; + + GtkWidget *dir_label; + GtkWidget *combo; + GtkWidget *case_sensitive; + GtkWidget *full_path; +} s_fif_dialog = {NULL, NULL, NULL, NULL, NULL}; + + +static struct +{ + GtkWidget *widget; + + GtkWidget *find_in_directory; + GtkWidget *find_file; + GtkWidget *expand; +} s_popup_menu; + + +static gint show_dialog_find_file(gchar *path, gchar **pattern, gboolean *case_sensitive, gboolean *full_path) +{ + gint res; + GtkWidget *entry; + gchar *selection; + GtkSizeGroup *size_group; + + if (!s_fif_dialog.widget) + { + GtkWidget *label, *vbox, *ebox; + + s_fif_dialog.widget = gtk_dialog_new_with_buttons( + _("Find File"), GTK_WINDOW(geany->main_widgets->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + gtk_dialog_add_button(GTK_DIALOG(s_fif_dialog.widget), "gtk-find", GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response(GTK_DIALOG(s_fif_dialog.widget), GTK_RESPONSE_ACCEPT); + + vbox = ui_dialog_vbox_new(GTK_DIALOG(s_fif_dialog.widget)); + gtk_box_set_spacing(GTK_BOX(vbox), 6); + + size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + + label = gtk_label_new(_("Search for:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_size_group_add_widget(size_group, label); + s_fif_dialog.combo = gtk_combo_box_entry_new_text(); + entry = gtk_bin_get_child(GTK_BIN(s_fif_dialog.combo)); + gtk_entry_set_width_chars(GTK_ENTRY(entry), 40); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); + ui_entry_add_clear_icon(GTK_ENTRY(entry)); + gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); + + ebox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(ebox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(ebox), s_fif_dialog.combo, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), ebox, TRUE, FALSE, 0); + + label = gtk_label_new(_("Search inside:")); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_size_group_add_widget(size_group, label); + s_fif_dialog.dir_label = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(s_fif_dialog.dir_label), 0, 0.5); + + ebox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(ebox), label, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(ebox), s_fif_dialog.dir_label, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), ebox, TRUE, FALSE, 0); + + s_fif_dialog.case_sensitive = gtk_check_button_new_with_mnemonic(_("C_ase sensitive")); + gtk_button_set_focus_on_click(GTK_BUTTON(s_fif_dialog.case_sensitive), FALSE); + + s_fif_dialog.full_path = gtk_check_button_new_with_mnemonic(_("Search in full path")); + gtk_button_set_focus_on_click(GTK_BUTTON(s_fif_dialog.full_path), FALSE); + + gtk_box_pack_start(GTK_BOX(vbox), s_fif_dialog.case_sensitive, TRUE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), s_fif_dialog.full_path, TRUE, FALSE, 0); + gtk_widget_show_all(vbox); + } + + gtk_label_set_text(GTK_LABEL(s_fif_dialog.dir_label), path); + entry = gtk_bin_get_child(GTK_BIN(s_fif_dialog.combo)); + selection = get_selection(); + if (selection) + gtk_entry_set_text(GTK_ENTRY(entry), selection); + g_free(selection); + gtk_widget_grab_focus(entry); + + res = gtk_dialog_run(GTK_DIALOG(s_fif_dialog.widget)); + + if (res == GTK_RESPONSE_ACCEPT) + { + const gchar *str; + + str = gtk_entry_get_text(GTK_ENTRY(entry)); + *pattern = g_strconcat("*", str, "*", NULL); + *case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s_fif_dialog.case_sensitive)); + *full_path = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s_fif_dialog.full_path)); + ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(s_fif_dialog.combo), str, 0); + } + + gtk_widget_hide(s_fif_dialog.widget); + + return res; +} + + +static gchar *build_path(GtkTreeIter *iter) +{ + GtkTreeIter node; + GtkTreeIter parent; + gchar *path = NULL; + GtkTreeModel *model; + gchar *name; + + if (!iter) + return g_strdup(geany_data->app->project->base_path); + + node = *iter; + model = GTK_TREE_MODEL(s_file_store); + + while (gtk_tree_model_iter_parent(model, &parent, &node)) + { + gtk_tree_model_get(model, &node, FILEVIEW_COLUMN_NAME, &name, -1); + if (path == NULL) + path = g_strdup(name); + else + setptr(path, g_build_filename(name, path, NULL)); + + node = parent; + } + + gtk_tree_model_get(model, &node, FILEVIEW_COLUMN_NAME, &name, -1); + setptr(path, g_build_filename(name, path, NULL)); + + setptr(path, g_build_filename(geany_data->app->project->base_path, path, NULL)); + + return path; +} + + +static void on_expand_all(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(s_file_view)); +} + + +static void on_collapse_all(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(s_file_view)); +} + + +static void on_follow_active(GtkToggleToolButton *button, G_GNUC_UNUSED gpointer user_data) +{ + s_follow_editor = gtk_toggle_tool_button_get_active(button); + gprj_sidebar_update(FALSE); +} + + +static void find_file_recursive(GtkTreeIter *iter, gboolean case_sensitive, gboolean full_path, GPatternSpec *pattern) +{ + GtkTreeModel *model = GTK_TREE_MODEL(s_file_store); + GtkTreeIter child; + gboolean iterate; + + iterate = gtk_tree_model_iter_children(model, &child, iter); + if (iterate) + { + while (iterate) + { + find_file_recursive(&child, case_sensitive, full_path, pattern); + iterate = gtk_tree_model_iter_next(model, &child); + } + } + else + { + gchar *name; + + if (iter == NULL) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(model), iter, FILEVIEW_COLUMN_NAME, &name, -1); + + if (full_path) + { + gchar *path; + + path = build_path(iter); + name = get_file_relative_path(geany_data->app->project->base_path, path); + g_free(path); + } + else + name = g_strdup(name); + + if (!case_sensitive) + setptr(name, g_utf8_strdown(name, -1)); + + if (g_pattern_match_string(pattern, name)) + { + gchar *path, *rel_path; + + path = build_path(iter); + rel_path = get_file_relative_path(geany_data->app->project->base_path, path); + msgwin_msg_add(COLOR_BLACK, -1, NULL, "./%s", rel_path ? rel_path : path); + g_free(path); + g_free(rel_path); + } + + g_free(name); + } +} + + +static void find_file(GtkTreeIter *iter) +{ + gchar *pattern_str = NULL; + gboolean case_sensitive, full_path; + gchar *path; + + path = build_path(iter); + + if (show_dialog_find_file(path, &pattern_str, &case_sensitive, &full_path) == GTK_RESPONSE_ACCEPT) + { + GPatternSpec *pattern; + + if (!case_sensitive) + setptr(pattern_str, g_utf8_strdown(pattern_str, -1)); + + pattern = g_pattern_spec_new(pattern_str); + + msgwin_clear_tab(MSG_MESSAGE); + msgwin_set_messages_dir(geany_data->app->project->base_path); + find_file_recursive(iter, case_sensitive, full_path, pattern); + msgwin_switch_tab(MSG_MESSAGE, TRUE); + } + + g_free(pattern_str); + g_free(path); +} + + +static void on_find_file(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter iter, parent; + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + if (!gtk_tree_selection_get_selected(treesel, &model, &iter)) + return; + + if (!gtk_tree_model_iter_has_child(model, &iter)) + { + if (gtk_tree_model_iter_parent(model, &parent, &iter)) + find_file(&parent); + else + find_file(NULL); + } + else + find_file(&iter); +} + + +static void on_reload_project(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gprj_project_rescan(); + gprj_sidebar_update(TRUE); +} + + +static void on_open_clicked() +{ + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter iter; + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + + if (gtk_tree_selection_get_selected(treesel, &model, &iter)) + { + if (gtk_tree_model_iter_has_child(model, &iter)) + { + GtkTreeView *tree_view; + GtkTreePath *tree_path; + + tree_view = GTK_TREE_VIEW(s_file_view); + tree_path = gtk_tree_model_get_path (model, &iter); + + if (gtk_tree_view_row_expanded(tree_view, tree_path)) + gtk_tree_view_collapse_row(tree_view, tree_path); + else + gtk_tree_view_expand_row(tree_view, tree_path, FALSE); + } + else + { + gchar *name; + gchar *icon; + + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_ICON, &icon, -1); + + if (!icon) + { + // help string doesn't have icon + return; + } + + name = build_path(&iter); + open_file(name); + g_free(name); + } + } +} + + +static gboolean on_button_press(G_GNUC_UNUSED GtkWidget * widget, GdkEventButton * event, + G_GNUC_UNUSED gpointer user_data) +{ + if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) + on_open_clicked(); + + return FALSE; +} + + +static gboolean on_key_press(G_GNUC_UNUSED GtkWidget * widget, GdkEventKey * event, G_GNUC_UNUSED gpointer data) +{ + if (event->keyval == GDK_Return + || event->keyval == GDK_ISO_Enter + || event->keyval == GDK_KP_Enter + || event->keyval == GDK_space) + on_open_clicked(); + return FALSE; +} + + +static void expand_all(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GtkTreeSelection *treesel; + GtkTreeIter iter; + GtkTreeModel *model; + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + + if (gtk_tree_selection_get_selected(treesel, &model, &iter)) + gtk_tree_view_expand_row(GTK_TREE_VIEW(s_file_view), gtk_tree_model_get_path (model, &iter), TRUE); +} + + +static void on_find_in_files(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + GtkTreeSelection *treesel; + GtkTreeIter iter, parent; + GtkTreeModel *model; + gchar *path; + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + + if (!gtk_tree_selection_get_selected(treesel, &model, &iter)) + return; + + if (!gtk_tree_model_iter_has_child(model, &iter)) + { + if (gtk_tree_model_iter_parent(model, &parent, &iter)) + path = build_path(&parent); + else + path = build_path(NULL); + } + else + path = build_path(&iter); + + search_show_find_in_files_dialog(path); + g_free(path); +} + + +static void build_file_list(gpointer name, G_GNUC_UNUSED gpointer value, GSList **lst) +{ + gchar *item; + + item = get_file_relative_path(geany_data->app->project->base_path, name); + *lst = g_slist_prepend(*lst, item); +} + + +static void create_branch(gint level, GSList *leaf_list, GtkTreeIter *parent, + GSList *header_patterns, GSList *source_patterns) +{ + GSList *dir_list = NULL; + GSList *file_list = NULL; + GSList *elem; + + for (elem = leaf_list; elem != NULL; elem = g_slist_next(elem)) + { + gchar **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); + } + + if (dir_list) + { + GSList *tmp_list = NULL; + GtkTreeIter iter; + gchar **path_arr = dir_list->data; + gchar *last_dir_name; + + last_dir_name = path_arr[level]; + + for (elem = dir_list; elem != NULL; elem = g_slist_next(elem)) + { + 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_append(s_file_store, &iter, parent); + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_ICON, "gtk-directory", + FILEVIEW_COLUMN_NAME, last_dir_name, -1); + + create_branch(level+1, tmp_list, &iter, header_patterns, source_patterns); + + 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_append(s_file_store, &iter, parent); + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_ICON, "gtk-directory", + FILEVIEW_COLUMN_NAME, last_dir_name, -1); + + create_branch(level+1, tmp_list, &iter, header_patterns, source_patterns); + + g_slist_free(tmp_list); + g_slist_free(dir_list); + } + + for (elem = file_list; elem != NULL; elem = g_slist_next(elem)) + { + GtkTreeIter iter; + gchar **path_arr = elem->data; + + gtk_tree_store_append(s_file_store, &iter, parent); + if (patterns_match(header_patterns, path_arr[level])) + { + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_ICON, "gproject-header", + FILEVIEW_COLUMN_NAME, path_arr[level], -1); + } + else if (patterns_match(source_patterns, path_arr[level])) + { + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_ICON, "gproject-source", + FILEVIEW_COLUMN_NAME, path_arr[level], -1); + } + else + { + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_ICON, "gproject-file", + FILEVIEW_COLUMN_NAME, path_arr[level], -1); + } + } + + g_slist_free(file_list); +} + + +static void load_project() +{ + GSList *lst = NULL; + GSList *path_list = NULL; + GSList *elem, *header_patterns, *source_patterns; + GtkTreeModel *model; + + gtk_tree_store_clear(s_file_store); + + if (!g_prj || !geany_data->app->project) + return; + + header_patterns = get_precompiled_patterns(g_prj->header_patterns); + source_patterns = get_precompiled_patterns(g_prj->source_patterns); + + g_hash_table_foreach(g_prj->file_tag_table, (GHFunc)build_file_list, &lst); + lst = g_slist_sort(lst, (GCompareFunc) strcmp); + + for (elem = lst; elem != NULL; elem = g_slist_next(elem)) + { + gchar **path_split; + + path_split = g_strsplit_set(elem->data, "/\", 0); + path_list = g_slist_prepend(path_list, path_split); + } + + model = GTK_TREE_MODEL(s_file_store); + + if (path_list != NULL) + create_branch(0, path_list, NULL, header_patterns, source_patterns); + else + { + GtkTreeIter iter; + + gtk_tree_store_append(s_file_store, &iter, NULL); + gtk_tree_store_set(s_file_store, &iter, + FILEVIEW_COLUMN_NAME, "Set file patterns under Project->Properties", -1); + } + + g_slist_foreach(header_patterns, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(header_patterns); + g_slist_foreach(source_patterns, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(source_patterns); + + g_slist_foreach(lst, (GFunc) g_free, NULL); + g_slist_free(lst); + g_slist_foreach(path_list, (GFunc) g_strfreev, NULL); + g_slist_free(path_list); +} + + +static gboolean find_in_tree(GtkTreeIter *parent, gchar **path_split, gint level, GtkTreeIter *ret) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean iterate; + + model = GTK_TREE_MODEL(s_file_store); + + iterate = gtk_tree_model_iter_children(model, &iter, parent); + while (iterate) + { + gchar *name; + + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_NAME, &name, -1); + + if (g_strcmp0(name, path_split[level]) == 0) + { + GtkTreeIter foo; + if (path_split[level+1] == NULL && !gtk_tree_model_iter_children (model, &foo, &iter)) + { + *ret = iter; + return TRUE; + } + else + return find_in_tree(&iter, path_split, level + 1, ret); + } + + iterate = gtk_tree_model_iter_next(model, &iter); + } + + return FALSE; +} + + +static void follow_editor() +{ + GtkTreeIter found_iter; + gchar *path; + gchar **path_split; + GeanyDocument *doc; + + doc = document_get_current(); + + if (!doc || !doc->file_name || !geany_data->app->project) + return; + + path = get_file_relative_path(geany_data->app->project->base_path, doc->file_name); + + if (!path) + return; + + path_split = g_strsplit_set(path, "/\", 0); + + if (find_in_tree(NULL, path_split, 0, &found_iter)) + { + GtkTreePath *tree_path; + GtkTreeModel *model; + + model = GTK_TREE_MODEL(s_file_store); + tree_path = gtk_tree_model_get_path (model, &found_iter); + + gtk_tree_view_expand_to_path(GTK_TREE_VIEW(s_file_view), tree_path); + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(s_file_view), tree_path, + NULL, FALSE, 0.0, 0.0); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_file_view), tree_path, NULL, FALSE); + } +} + + +void gprj_sidebar_update(gboolean reload) +{ + if (reload) + load_project(); + if (s_follow_editor) + follow_editor(); +} + + +void gprj_sidebar_find_file_in_active() +{ + find_file(NULL); +} + + +static gboolean on_button_release(G_GNUC_UNUSED GtkWidget * widget, GdkEventButton * event, + G_GNUC_UNUSED gpointer user_data) +{ +// GeanyDocument *doc; + + if (event->button == 3) + { + GtkTreeSelection *treesel; + GtkTreeModel *model; + GtkTreeIter iter; + + treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + + if (!gtk_tree_selection_get_selected(treesel, &model, &iter)) + return FALSE; + + + gtk_widget_set_sensitive(s_popup_menu.expand, gtk_tree_model_iter_has_child(model, &iter)); + + gtk_menu_popup(GTK_MENU(s_popup_menu.widget), NULL, NULL, NULL, NULL, + event->button, event->time); + } + +// doc = document_get_current(); +// if (doc) +// gtk_widget_grab_focus(GTK_WIDGET(doc->editor->sci)); + + return FALSE; +} + + +void gprj_sidebar_init() +{ + GtkWidget *scrollwin, *toolbar, *item, *image; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *sel; + PangoFontDescription *pfd; + + s_file_view_vbox = gtk_vbox_new(FALSE, 0); + + // *** toolbar *** + + toolbar = gtk_toolbar_new(); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_MENU); + gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); + + item = GTK_WIDGET(gtk_tool_button_new(NULL, NULL)); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(item), "gproject-refresh"); + ui_widget_set_tooltip_text(item, _("Reload all")); + g_signal_connect(item, "clicked", G_CALLBACK(on_reload_project), NULL); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + item = GTK_WIDGET(gtk_separator_tool_item_new()); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + item = GTK_WIDGET(gtk_tool_button_new(NULL, NULL)); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(item), "gproject-expand"); + ui_widget_set_tooltip_text(item, _("Expand all")); + g_signal_connect(item, "clicked", G_CALLBACK(on_expand_all), NULL); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + item = GTK_WIDGET(gtk_tool_button_new(NULL, NULL)); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(item), "gproject-collapse"); + ui_widget_set_tooltip_text(item, _("Collapse all")); + g_signal_connect(item, "clicked", G_CALLBACK(on_collapse_all), NULL); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + item = GTK_WIDGET(gtk_separator_tool_item_new()); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + item = GTK_WIDGET(gtk_toggle_tool_button_new()); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(item), "gproject-follow"); + ui_widget_set_tooltip_text(item, _("Follow active editor")); + g_signal_connect(item, "clicked", G_CALLBACK(on_follow_active), NULL); + gtk_container_add(GTK_CONTAINER(toolbar), item); + + gtk_box_pack_start(GTK_BOX(s_file_view_vbox), toolbar, FALSE, FALSE, 0); + + // *** tree view *** + + s_file_view = gtk_tree_view_new(); + + s_file_store = gtk_tree_store_new(FILEVIEW_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_view_set_model(GTK_TREE_VIEW(s_file_view), GTK_TREE_MODEL(s_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_set_attributes(column, renderer, "icon-name", FILEVIEW_COLUMN_ICON, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_attributes(column, renderer, "text", FILEVIEW_COLUMN_NAME, NULL); + + gtk_tree_view_append_column(GTK_TREE_VIEW(s_file_view), column); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(s_file_view), FALSE); + gtk_tree_view_set_enable_search(GTK_TREE_VIEW(s_file_view), TRUE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(s_file_view), FILEVIEW_COLUMN_NAME); + + pfd = pango_font_description_from_string(geany_data->interface_prefs->tagbar_font); + gtk_widget_modify_font(s_file_view, pfd); + pango_font_description_free(pfd); + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view)); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + + g_signal_connect(G_OBJECT(s_file_view), "button-release-event", + G_CALLBACK(on_button_release), NULL); + g_signal_connect(G_OBJECT(s_file_view), "button-press-event", + G_CALLBACK(on_button_press), NULL); + g_signal_connect(G_OBJECT(s_file_view), "key-press-event", + G_CALLBACK(on_key_press), NULL); + + // *** popup menu *** + + s_popup_menu.widget = gtk_menu_new(); + + image = gtk_image_new_from_icon_name("gproject-expand", GTK_ICON_SIZE_MENU); + gtk_widget_show(image); + item = gtk_image_menu_item_new_with_mnemonic(_("Expand All")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect((gpointer) item, "activate", G_CALLBACK(expand_all), NULL); + s_popup_menu.expand = item; + + image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); + gtk_widget_show(image); + item = gtk_image_menu_item_new_with_mnemonic(_("Find in Files")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_find_in_files), NULL); + s_popup_menu.find_in_directory = item; + + image = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU); + gtk_widget_show(image); + item = gtk_image_menu_item_new_with_mnemonic(_("Find File")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_find_file), NULL); + s_popup_menu.find_file = item; + + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + + item = gtk_image_menu_item_new_with_mnemonic(_("H_ide Sidebar")); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), + gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect_swapped((gpointer) item, "activate", + G_CALLBACK(keybindings_send_command), + GINT_TO_POINTER(GEANY_KEYS_VIEW_SIDEBAR)); + + // *** the rest *** + + 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), s_file_view); + gtk_container_add(GTK_CONTAINER(s_file_view_vbox), scrollwin); + + gtk_widget_show_all(s_file_view_vbox); + gtk_notebook_append_page(GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook), + s_file_view_vbox, gtk_label_new(_("Project"))); +} + + +void gprj_sidebar_activate(gboolean activate) +{ + gtk_widget_set_sensitive(s_file_view_vbox, activate); +} + + +void gprj_sidebar_cleanup() +{ + gtk_widget_destroy(s_file_view_vbox); +}
Added: trunk/geany-plugins/gproject/src/gproject-sidebar.h =================================================================== --- trunk/geany-plugins/gproject/src/gproject-sidebar.h (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-sidebar.h 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,33 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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 __GPROJECT_SIDEBAR_H__ +#define __GPROJECT_SIDEBAR_H__ + + +void gprj_sidebar_init(void); +void gprj_sidebar_cleanup(void); +void gprj_sidebar_activate(gboolean activate); + +void gprj_sidebar_find_file_in_active(void); + +void gprj_sidebar_update(gboolean reload); + + + +#endif
Added: trunk/geany-plugins/gproject/src/gproject-utils.c =================================================================== --- trunk/geany-plugins/gproject/src/gproject-utils.c (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-utils.c 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,178 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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. + */ + +#include <string.h> +#include <glib.h> + +#include <geany/geanyplugin.h> + +#include "gproject-utils.h" + +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + +static gchar *relpath(const gchar *origin_dir, const gchar *dest_dir) +{ + gchar *origin, *dest; + gchar **originv, **destv; + gchar *ret = NULL; + guint i, j; + + origin = tm_get_real_path(origin_dir); + dest = tm_get_real_path(dest_dir); + + if (!NZV(origin) || !NZV(dest) || origin[0] != dest[0]) + { + g_free(origin); + g_free(dest); + return NULL; + } + + originv = g_strsplit_set(g_path_skip_root(origin), "/\", -1); + destv = g_strsplit_set(g_path_skip_root(dest), "/\", -1); + + for (i = 0; originv[i] != NULL && destv[i] != NULL; i++) + if (g_strcmp0(originv[i], destv[i]) != 0) + break; + + ret = g_strdup(""); + + for (j = i; originv[j] != NULL; j++) + setptr(ret, g_build_filename(ret, "..", NULL)); + + for (j = i; destv[j] != NULL; j++) + setptr(ret, g_build_filename(ret, destv[j], NULL)); + + if (strlen(ret) == 0) + setptr(ret, g_strdup("./")); + + g_free(origin); + g_free(dest); + g_strfreev(originv); + g_strfreev(destv); + + return ret; +} + + +gchar *get_file_relative_path(const gchar *origin_dir, const gchar *dest_file) +{ + gchar *dest_dir, *ret; + + dest_dir = g_path_get_dirname(dest_file); + ret = relpath(origin_dir, dest_dir); + if (ret) + { + gchar *dest_basename; + + dest_basename = g_path_get_basename(dest_file); + + if (g_strcmp0(ret, "./") != 0) + { + setptr(ret, g_build_filename(ret, dest_basename, NULL)); + } + else + { + setptr(ret, g_strdup(dest_basename)); + } + + g_free(dest_basename); + } + + g_free(dest_dir); + return ret; +} + + +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; +} + + +gboolean patterns_match(GSList *patterns, const gchar *str) +{ + GSList *elem; + for (elem = patterns; elem != NULL; elem = g_slist_next(elem)) + { + GPatternSpec *pattern = elem->data; + if (g_pattern_match_string(pattern, str)) + return TRUE; + } + return FALSE; +} + + +void open_file(gchar *utf8_name) +{ + gchar *name; + GeanyDocument *doc; + + name = utils_get_locale_from_utf8(utf8_name); + doc = document_find_by_filename(utf8_name); + + if (!doc) + doc = document_open_file(name, FALSE, NULL, NULL); + else + { + GtkNotebook *notebook; + gint page_num; + + notebook = GTK_NOTEBOOK(geany->main_widgets->notebook); + page_num = gtk_notebook_page_num(notebook, GTK_WIDGET(doc->editor->sci)); + + gtk_notebook_set_current_page(notebook, page_num); + } + +// if (doc) +// gtk_widget_grab_focus(GTK_WIDGET(doc->editor->sci)); + + g_free(name); +} + + +gchar *get_selection(void) +{ + GeanyDocument *doc = document_get_current(); + const gchar *wc; + +#ifdef G_OS_WIN32 + wc = GEANY_WORDCHARS "./-" "\"; +#else + wc = GEANY_WORDCHARS "./-"; +#endif + + if (!doc) + return NULL; + + if (sci_has_selection(doc->editor->sci)) + return sci_get_selection_contents(doc->editor->sci); + else + return editor_get_word_at_pos(doc->editor, -1, wc); +}
Added: trunk/geany-plugins/gproject/src/gproject-utils.h =================================================================== --- trunk/geany-plugins/gproject/src/gproject-utils.h (rev 0) +++ trunk/geany-plugins/gproject/src/gproject-utils.h 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,30 @@ +/* + * Copyright 2010 Jiri Techet techet@gmail.com + * + * 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 __GPROJECT_UTILS_H__ +#define __GPROJECT_UTILS_H__ + +gchar *get_file_relative_path(const gchar *origin_dir, const gchar *dest_file); + +gboolean patterns_match(GSList *patterns, const gchar *str); +GSList *get_precompiled_patterns(gchar **patterns); + +void open_file(gchar *utf8_name); +gchar *get_selection(void); + +#endif
Added: trunk/geany-plugins/gproject/wscript_build =================================================================== --- trunk/geany-plugins/gproject/wscript_build (rev 0) +++ trunk/geany-plugins/gproject/wscript_build 2011-05-24 22:22:30 UTC (rev 2087) @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# +# WAF build script for geany-plugins - GProject +# +# Copyright 2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> +# +# 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. +# +# $Id$ + +from build.wafutils import build_plugin + + +name = 'GProject' +includes = ['gproject/src'] + +build_plugin(bld, name, includes=includes)
Added: trunk/geany-plugins/gproject/wscript_configure =================================================================== Modified: trunk/geany-plugins/po/POTFILES.in =================================================================== --- trunk/geany-plugins/po/POTFILES.in 2011-05-24 21:55:01 UTC (rev 2086) +++ trunk/geany-plugins/po/POTFILES.in 2011-05-24 22:22:30 UTC (rev 2087) @@ -153,6 +153,12 @@ geanyvc/src/vc_svn.c geanyvc/src/utils.c
+# GProject +gproject/src/gproject-main.c +gproject/src/gproject-menu.c +gproject/src/gproject-project.c +gproject/src/gproject-sidebar.c + # Pretty-printer pretty-printer/src/PluginEntry.c pretty-printer/src/PrettyPrinter.c
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
plugins-commits@lists.geany.org