diff options
204 files changed, 46362 insertions, 0 deletions
@@ -0,0 +1 @@ +Elad Lahav <elad_lahav@users.sf.net> @@ -0,0 +1,20 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..6e6f7c9 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,408 @@ +1.6.2 (?) + +* New: Support for hidden project folders under the source root +* Bug fix: Make the configuration script sh-friendly +* Bug fix: Handle unicode characters on gcc's output +* Bug fix: KScope crashes when clicking on empty area in the tree view +* Bug fix: Do not show the "Function" column in the error list +* Bug fix: Do not close KScope when choosing "Cancel" in the "Save Files?" + message box + +1.6.1 (9-Jan-2008) + +* New: Support for case-insensitive queries +* New: Per-project Ctags command line (for advanced users only) +* Bug fix: Stop queries when their result windows are destroyed +* Bug fix: Query results sorted by line numbers are sorted numerically +* Translation: Chinese + +1.6.0 (10-Jul-2007) + +* Improved: Updated the documentation +* Improved: Implemented multiple-call nodes in the call-graph +* Improved: Workspace toolbar buttons re-arranged +* Improved: Hitting Enter in the "Open Project" dialogue's list of + recent projects opens the selected project +* Bug fix: Handle file extensions correctly in the file list +* Bug fix: Avoid hanging status bar messages when a project is closed +* Bug fix: Prevent infinite loops in the file finder in the presence of + recursive symbolic links +* Bug fix: Child windows should not disappear when dialogues are invoked +* Bug fix: Added padding to the call graph, to avoid chopped-off drawing + of nodes close to the borders +* Bug fix: Honour the preferred font when drawing the graph +* Bug fix: Delete temporary dot files used for drawing graphs +* Bug fix: Save call-tree files when a project is closed +* Bug fix: Clean-up a project's directory name after it is created + +1.5.2 (7-May-2007) + +* New: Useable global bookmarks system +* Improved: Better infrastructure for handling projects +* Improved: The soure root is set in the project properties dialogue +* Improved: When saving a new file, the user is asked whether to include + it in the project +* Improved: New toolbar layout +* Improved: Temporary projects appear in the list of recently open + projects +* Improved: Load a temporary project's cscope.files file, if it exists +* Bug fix: Enable file/project menu items only when a file/project is + open +* Bug fix: Handle column numbers in make output +* Bug fix: Do not allow multiple instances of the same command in the + make history +* Bug fix: Dropped project semaphores (too much hassle for a minor + feature) +* Compilation fix: Support for automake 1.10 + +1.5.1 (15-Feb-2007) + +* Improved: Support for recursive builds (make changing directories) +* Improved: Show build errors/warnings on a separate list +* Bug fix: The main window was not activated when requesting a source + position in a child window (call tree or the make window) +* Bug fix: Maintain Call-tree child item order (by line) +* Bug fix: Build output occasionally mixed standard output with standard + error + +1.5.0 (6-Feb-2007) + +* New: Make front-end (Rudimentary) +* New: Global bookmarks list +* New: Support for Cscope's -c and -D command-line options (-D requires + a patch to Cscope) +* Improved: Detect Cscope's executable and capabilities on each load +* Improved: Graph windows are no longer top-level (can be minimised or + hidden behind the main window) +* Improved: Do not automatically open a project if it was already loaded + by another instance of KScope +* Improved: Show #include directives in the tag list +* Bug fix: Better calculation of the area defined by a graph arrow +* Bug fix: Files could not be found in the file list when using a common + root ($) + +1.4.3 (15-Jan-2007) + +* New: Option for negating filters on query result lists +* New: Command for setting the keyboard focus to the tag list +* Improved: Restrict tag/file list navigation to current search pattern +* Improved: Show goto labels in the tag list +* Bug fix: Crash due to in-edges not being removed along with a function +* Bug fix: Connected components disappeared after filtering calling/ + called functions +* Bug fix: Use only sh-style ouput redirection in kscope_config + +1.4.2 (16-Oct-2006) + +* New: Tool-tips for the project's file list +* New: "Find Definition" entry in the query-results popup menu +* Improved: Added '*.S' (kernel assembly files) to the list of standard + file types +* Improved: Some code clean-ups in the query-results popup menu +* Bug fix: All query results following a global definition were omitted + +1.4.1 (23-Aug-2006) + +* Improved: Speed-up result list filtering +* Improved: Keyboard shortcuts for the first entries in the Window menu +* Improved: Show assmebly labels in the tag list +* Bug fix: KScope crashes when a node is removed from the graph +* Bug fix: KScope crashes when Next/Previous Result is invoked on an + empty query results list +* Bug fix: Prevent whitespace in project names +* Bug fix: Add entries to the results query list in the right order +* Bug fix: Fixed several memory leaks + +1.4.0 (9-Aug-2006) + +* New: Option for sorting the file list when a project is loaded (on by + default) +* Improved: The documentation is now up to date +* Improved: Nicer layout for the "New Project" dialogue +* Improved: Corrections to the desktop file (thanks to Tom Albers) +* Improved: Close a project automatically before a new one is created +* Bug fix: Do not show the progress dialogue if building fails to start +* Compilation fix: Include stdlib.h in graphwidget.cpp +* Compilation fix: Support for autoconf 2.6x +* Compilation fix: Removed unnecessary options from the YACC source file +* Compilation fix: Abort configuration if lex/flex and yacc/bison are not + found + +1.3.4 (14-Apr-2006) + +* New: Use graphviz from the command-line (dot). Should finally solve _all_ + licensing issues +* New: Informative welcome message +* Improved: Allow multiple files on "File->Open..." +* Improved: Better tool-tips for the tag list +* Bug fix: KScope crashes after startup when attempting to set the cursor + to a non-existing line + +1.3.3 (5-Jan-2006) + +* License changed to BSD due to incompatibility between the GPL and the CPL + (graphviz) +* New: Multiple-view call graph/tree dialogue +* Improved: Function name is displayed first (consistent behaviour for query + views and call tree widgets) +* Improved: Updated to the latest KDE 'configure' template + +1.3.2 (16-Nov-2005) + +* New: Support for graphviz 2.6 +* Improved: The 'configure' script detects he graphviz version and build flags +* Improved: Better automatic configuration script for Cscope and Ctags +* Improved: Added 'exctags' to the search for exuberant-ctags (FreeBSD) +* Bug fix: Cursor set to the end of the line when jumping to a location in the + code +* Bug fix: Draw the call graph using the current DPI settings +* Bug fix: Automatic configuration script no longer depends on "source" (which + is not available for all shells) +* Bug fix: Editor GUI not merged upon opening a project if the selected file is + the last one loaded + +1.3.1 (14-Oct-2005) + +* New: "Save All" menu command (was not included in previous release, despite + a claim to the contrary) +* New: List and filter called/calling functions in the call graph +* New: Delete graph nodes +* New: Limit graph node in/out degree (requires latest Cscope CVS snapshot) +* Improved: Redesigned node menu in the graph widget +* Improved: All query result views share the same widget +* Improved: Session management remembers file locations and last open file + (thanks to Alexander Kern) +* Bug Fix: Delete graph files when they are no longer required (i.e., after + a graph dialogue is manually closed) +* Bug fix: Do not show a border around the graph (nasty fix, but it works) +* Bug fix: Nodes are now always drawn on top of edges +* Compilation fix: Use QPtrList instead of the deprecated QList +* Compilation fix: Should now compile with gcc 4.x + +1.3.0 (29-Jun-2005) + +* New: A new call graph based on the graphviz library +* New: Use a special dialogue for executing and displaying quick + definition queries +* New: Use the project's root in the file list (root directory replaced + by a $ symbol) +* Improved: Faster compilation through the inclusion of moc files +* Improved: Better organised menu and toolbars +* Improved: Quick definition does not write into the query widget + +1.2.0 (25-May-2005) + +* New: Keyboard shortcut for setting the focus to the file list +* Improved: Documentation is now up to date +* Improved: Use standard configuration actions +* Improved: Faster loading times for projects +* Bug fix: Incorrect sorting of the symbol history combo-box +* Bug fix: Query window hidden unnecessarily on some occasions +* Bug fix: A hidden query window is shown by the "Position History" menu + command +* Bug fix: Modifying non-project files triggered a database rebuild + +1.1.1 (17-Mar-2005) + +* New: A new tab widget that displays a popup-menu with all open tabs +* New: Automatic configuration of Cscope/Ctags paths and parameters +* New: Filter query results +* New: Tag list can be hidden +* Improved: Display unique entries in the completion list +* Improved: Two options for the editor's popup menu: Cscope actions embedded + in the editor's own menu, or the old-style KScope-only menu +* Improved: The process of closing all editor windows (explicitly, when closing a + project or when exiting KScope) is much faster +* Bug fix: Do not show a hidden query window when browsing through position + history +* Bug fix: Refreshing a locked query opened a new page +* Bug fix: Possibly wrong tag-highlighting if cursor was moved while Ctags is + working +* Compilation Fix: Compiles under KDE 3.2 again + +1.1.0 (1-Feb-2005) + +* New: Cross-reference database is rebuilt automatically +* New: Symbol completion (manual and automatic) +* New: Allow multiple queries to be issued simultaneously +* New: Query dialogue with symbol hinting, history, substring search option + and and the ability to change the query type +* New: System profiles (fast/slow) determine default settings for + time-consuming operations +* New: Multiple position history paths +* New: Postion history can be saved and restored +* New: Drag&Drop support +* New: Optional warnings when file is modified outside KScope (Supports Kate + part only) +* New: Call Tree support for both Called and Calling tree modes +* New: Call Tree save/restore support within the project +* New: Unobtrusive progress information for all Cscope queries +* New: Query results popup-menu for copying and removing items +* New: Menu option for showing/hiding the toolbar +* New: Configurable keyboard shortcuts +* Improved: More command line options +* Improved: External editor can be invoked in read-write mode +* Improved: Faster project load times (file list is not sorted by default) +* Bug fix: Symbol list last entry was not found +* Bug fix: Crashed when jumping to a new position and no pages are open +* Bug fix: Synchronise splitter sizes whenever a page gains focus +* Bug fix: Query dialogue suggested text did not check current character +* Bug fix: the progress information did not work with inverted index or + regular expressions + + +1.0 (7-Dec-2004) +* Bug fix: Selecting entries in the position history dialogue messes up the + history (thanks to Fekete Gabor) +* Bug fix: Double clicking a directory name in the file system tree view opens + an editor page (thanks to Fekete Gabor) +* Bug fix: "No source file found" message not detected since error output may + be broken (fix allows Cscope restart mechanism to be re-enabled) +* Bug fix: Return file-system root as the root directory of a temporary project +* Bug fix: Handle file names without an extension in the file list (thanks to + Anton G. Alvedro) +* Bug fix: Show the main window before loading the last project (fixes + problems with the width of the tag list) +* Bug fix: Use CTRL-5 for the EGrep pattern shortcut (CTRL-6 is already used + by Kate) +* Bug fix: Do not restart Cscope when a file of the wrong format is opened as + a cscope.out file +* Bug fix: Open editor pages were not found when using relative paths in + cscope.files (thanks to Chris Mason) +* Bug fix: Cannot rebuild database when working with temporary projects, + re-run Cscope instead (thanks to Chris Mason) +* Bug fix: Do not populate file tree recursively (may significantly + increase the project loading time) (thanks to Albert Yosher) +* Bug fix: Maximise main window before displaying the welcome message (on + first time usage) +* Bug fix: Empty position history was added if jumping when no files were + open (thanks to Fekete Gabor) +* Bug fix: Editor was not set to read-write mode if the edited file changed + its permission (thanks to Albert Yosher) +* Bug fix: Clean paths from '.' and '..' before opening a file (thanks to + Albert Yosher) +* Bug fix: KScope Crashes after applying new configuration if an empty query page + exists +* Bug fix: Use Ctrl-\ for a call tree (Ctrl-- is already used by Kate) +* Improved project loading process +* Made documentation compliant with KDE's conventions + +0.9 (14-Oct-2004) +* Option for using an external editor +* File-system tree-view +* Use application icons for tabs (for consistent look across themes) +* Option for shorter query captions (thanks to Fekete Gabor) +* Store current location before jumping (fixes position history behaviour) +* Show current file path in KScope's title bar +* Handle read-only files correctly +* Show a special tab icon for a read-only file +* Vim-style quick definition +* Bug fix: ignore Cscope's "Possible references retrieved" messages + (thanks to Fekete Gabor) +* Bug fix: report Cscope is working when rebuilding the cross-reference + database + +0.8 (2-Aug-2004) +* Select word from cursor position when initiating a query +* Show cursor position in status bar +* Highlight relevant tag based on cursor position +* Allow running KScope in read-only mode +* "Fonts" preference page +* "Options" preference page +* A "refresh query" command for the query pages +* Query file format changed to include query type and text (old files will + not be loaded) +* Bug fix: restore file icon to unchanged when all undo levels have been + applied (thanks to Fekete Gabor) +* Bug fix: better handling of the tag list width +* Bug fix: accept any file name containing "ctags" as the Ctags executable + (since Gentoo is using exuberant-ctags) +* Bug fix: files could not be reopened after "Close All Windows" (thanks to + Fekete Gabor) +* Bug fix: query window may be incorrectly hidden if query returns a + single record + +0.7 (15-Jun-2004) +* Restore project session (open files and locked queries) +* Lock/unlock queries +* Prompt to save files before any file is closed +* Use KTabWidget for both the Editors window and the Query window +* Mark modified files +* Show/hide the file list and the query window (thanks to Fekete Gabor) +* Save/restore main window layout +* Better Ctags support (using native Ctags files) +* Open Cscope.out files in temporary projects, also available from the + command line (thanks to Fekete Gabor) +* Removed sort buttons (requires further consideration) +* Tag list sorting order is saved +* Query page buttons to the right of the query widget +* Bug fix: project was not closed if program was terminated from the main + window's title-bar +* Bug fix: allow ctags-exuberant as the programme name for Ctags + +0.6 (21-Apr-2004) +* Adjusted to KDE 3.2 (previous versions are no longer supported) +* Implemented standard "New File" and "Open File" commands +* Line numbers are aligned to the right +* Display the type of each file in the file list +* Use unsigned int for the entry size in Frontend (fixes compiler warnings) +* Implemented Cscope's search for file query +* Files are opened automatically if only one record was returned by a query +* Close buttons for the editor tabs +* Display Cscope error messages in a modeless dialogue +* Basic navigation through position history +* Open last project on restart +* Option to build inverted index for projects (thanks to Fekete Gabor) +* Project properties dialogue +* Bug fix: calling for an including files query prompts for an EGrep pattern + (thanks to Fekete Gabor) +* Bug fix: program crashes on including files query +* Bug fix: set keyboard focus to editor when moving between tabs + +0.5 (3-Jan-2004) +* Moved project to KDevelop 3.0 format +* A new "Window" menu displaying a list of open files +* The full path name appears as a tool-tip on each editor tab +* Close buttons for query results windows +* Fixed Tab order in dialogues + +0.4 (9-Oct-2003) +* New integrated manual +* Project files dialogue (add/remove source files) +* Prompt for files when a project is empty +* Bug fix: Error in rebuild command to cscope (string too long) +* Bug fix: Directory names in the paths configuration were mistaken as legal + executable files +* Bug fix: The directory scanner did not clean its list between consecutive + searches (thanks to Craig Graham for this fix) +* Bug fix: Initial file count in the dir scanning progress dialogue showed + '123456' instead of '0' +* Prompt the user to close the active project before creating a new one +* Prevent the user from cancelling an already-finished query (i.e., while + results are written to the query window) + +0.3 (3-Aug-2003) +* Context menu for running queries from an editor window +* A dummy progress dialogue is displayed when progress information is + unavailable (simply to indicate that KScope is working) +* Bug fix: Mix-up between the "Calling functions" and "Called functions" in + the query page titles +* Bug fix: Only ".c" and ".h" files could be added to a project +* New query type: find #including files +* Inform the user when a query ends with no results +* Menu command to close the active project +* All query pages are removed when a project is closed + +0.2 (21-Jul-2003) +* Call tree window +* High-colour icons +* Sort buttons for the tag list +* Partial fix for the cursor positioning bug in Kate + +0.1 (3-Jul-2003) +* First public release +* Front-end to most CScope features +* Basic editing environment (multiple windows) +* Tag list for each open editor +* Multiple query windows +* Basic project management diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..beead8d --- /dev/null +++ b/Doxyfile @@ -0,0 +1,259 @@ +# Doxyfile 1.4.1-KDevelop + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = KScope +PROJECT_NUMBER = 1.3.3 +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..cac2bf1 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = $(TOPSUBDIRS) + +$(top_srcdir)/configure.in: configure.in.in $(top_srcdir)/subdirs + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common configure.in ; + +$(top_srcdir)/subdirs: + cd $(top_srcdir) && $(MAKE) -f admin/Makefile.common subdirs + +$(top_srcdir)/acinclude.m4: $(top_srcdir)/admin/acinclude.m4.in $(top_srcdir)/admin/libtool.m4.in + @cd $(top_srcdir) && cat admin/acinclude.m4.in admin/libtool.m4.in > acinclude.m4 + +MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 configure.files + +package-messages: + $(MAKE) -f admin/Makefile.common package-messages + $(MAKE) -C po merge + +EXTRA_DIST = admin COPYING configure.in.in + +dist-hook: + cd $(top_distdir) && perl admin/am_edit -padmin + cd $(top_distdir) && $(MAKE) -f admin/Makefile.common subdirs @@ -0,0 +1 @@ +
\ No newline at end of file @@ -0,0 +1 @@ + @@ -0,0 +1,17 @@ +KScope TODO List +================ + +No. Problem Type Target Version +~~~ ~~~~~~~ ~~~~ ~~~~~~~~~~~~~~ + +01. Project bookmark infrastructure/GUI Feat ? + +02. "Find Next" in search lists Feat ? + +03. New call tree widget Feat ? + +04. Plugin architecture Feat ? + +05. New GUI Feat ? + * IDEAl-style main window (?) + * True MDI (?) diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..e6a6582 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,11345 @@ +## -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include <X11/Intrinsic.h>], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui <<EOT + <!DOCTYPE UI><UI version="3" stdsetdef="1"></UI> +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test $kde_qtver = 3; then + UIC_TR="tr2i18n" + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + kde_htmldir='\${datadir}/doc/HTML' + fi + if test -z "$kde_appsdir"; then + kde_appsdir='\${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='\${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='\${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='\${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='\${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='\${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='\${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='\${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='\${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='\${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='\${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='\${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='\${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='\${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='\${libdir}/kde2' + else + kde_moduledir='\${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='\${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='\${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='\${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='\${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='\${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + if test "$KDECONFIG" != "compiled"; then + if test `$KDECONFIG --version | grep KDE | sed 's/KDE: \(...\).*/\1/'` = 3.2; then + kde33ornewer= + fi + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" -a "$MEINPROC" != "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Xlinker -framework -Xlinker CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + KDE_CHECK_PIE_SUPPORT + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include <sys/time.h> +# include <crt_externs.h> +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include <strings.h> + * that defines bzero. + */ + +#if defined(_AIX) +#include <strings.h> +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include <stdarg.h> +#include <stdlib.h> +#else +#include <varargs.h> +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include <stdio.h> +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext <<EOF +#include "confdefs.h" +#include <qglobal.h> +#include <qapplication.h> +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext <<EOF +#include <qevent.h> +#include <qstring.h> +#include <qstyle.h> +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <<EOF +#if QT_VERSION < 210 +#error 1 +#endif +EOF +fi +fi + +if test "$kde_qtver" = "3"; then +cat >> conftest.$ac_ext <<EOF +#include <qcursor.h> +#include <qstylefactory.h> +#include <private/qucomextra_p.h> +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <<EOF +#error 1 +#endif + +int main() { +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext <<EOF + QStringList *t = new QStringList(); + Q_UNUSED(t); +EOF +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <<EOF + QString s; + s.setLatin1("Elvis is alive", 14); +EOF +fi +fi +if test "$kde_qtver" = "3"; then +cat >> conftest.$ac_ext <<EOF + (void)QStyleFactory::create(QString::null); + QCursor c(Qt::WhatsThisCursor); +EOF +fi +cat >> conftest.$ac_ext <<EOF + return 0; +} +EOF +]) + +AC_DEFUN([KDE_USE_QT], +[ +if test -z "$1"; then + # Current default Qt version: 3.3 + kde_qtver=3 + kde_qtsubver=3 +else + kde_qtsubver=`echo "$1" | sed -e 's#[0-9][0-9]*\.\([0-9][0-9]*\).*#\1#'` + # following is the check if subversion isnt found in passed argument + if test "$kde_qtsubver" = "$1"; then + kde_qtsubver=1 + fi + kde_qtver=`echo "$1" | sed -e 's#^\([0-9][0-9]*\)\..*#\1#'` + if test "$kde_qtver" = "1"; then + kde_qtsubver=42 + fi +fi + +if test -z "$2"; then + if test "$kde_qtver" = "2"; then + if test $kde_qtsubver -gt 0; then + kde_qt_minversion=">= Qt 2.2.2" + else + kde_qt_minversion=">= Qt 2.0.2" + fi + fi + if test "$kde_qtver" = "3"; then + if test $kde_qtsubver -gt 0; then + if test $kde_qtsubver -gt 1; then + if test $kde_qtsubver -gt 2; then + kde_qt_minversion=">= Qt 3.3 and < 4.0" + else + kde_qt_minversion=">= Qt 3.2 and < 4.0" + fi + else + kde_qt_minversion=">= Qt 3.1 (20021021) and < 4.0" + fi + else + kde_qt_minversion=">= Qt 3.0 and < 4.0" + fi + fi + if test "$kde_qtver" = "1"; then + kde_qt_minversion=">= 1.42 and < 2.0" + fi +else + kde_qt_minversion="$2" +fi + +if test -z "$3"; then + if test $kde_qtver = 3; then + if test $kde_qtsubver -gt 0; then + kde_qt_verstring="QT_VERSION >= 0x03@VER@00 && QT_VERSION < 0x040000" + qtsubver=`echo "00$kde_qtsubver" | sed -e 's,.*\(..\)$,\1,'` + kde_qt_verstring=`echo $kde_qt_verstring | sed -e "s,@VER@,$qtsubver,"` + else + kde_qt_verstring="QT_VERSION >= 300 && QT_VERSION < 0x040000" + fi + fi + if test $kde_qtver = 2; then + if test $kde_qtsubver -gt 0; then + kde_qt_verstring="QT_VERSION >= 222" + else + kde_qt_verstring="QT_VERSION >= 200" + fi + fi + if test $kde_qtver = 1; then + kde_qt_verstring="QT_VERSION >= 142 && QT_VERSION < 200" + fi +else + kde_qt_verstring="$3" +fi + +if test $kde_qtver = 4; then + kde_qt_dirs="$QTDIR /usr/lib/qt4 /usr/lib/qt /usr/share/qt4" +fi +if test $kde_qtver = 3; then + kde_qt_dirs="$QTDIR /usr/lib/qt3 /usr/lib/qt /usr/share/qt3" +fi +if test $kde_qtver = 2; then + kde_qt_dirs="$QTDIR /usr/lib/qt2 /usr/lib/qt" +fi +if test $kde_qtver = 1; then + kde_qt_dirs="$QTDIR /usr/lib/qt" +fi +]) + +AC_DEFUN([KDE_CHECK_QT_DIRECT], +[ +AC_REQUIRE([KDE_USE_QT]) +AC_MSG_CHECKING([if Qt compiles without flags]) +AC_CACHE_VAL(kde_cv_qt_direct, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_LD_LIBRARY_PATH_safe=$LD_LIBRARY_PATH +ac_LIBRARY_PATH="$LIBRARY_PATH" +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_includes" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBQT -lXext -lX11 $LIBSOCKET" +else +LIBS="$LIBQT $LIBSOCKET" +fi +LD_LIBRARY_PATH= +export LD_LIBRARY_PATH +LIBRARY_PATH= +export LIBRARY_PATH + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + kde_cv_qt_direct="yes" +else + kde_cv_qt_direct="no" + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ +if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" +else + qtlib="qt" +fi + +kde_int_qt="-l$qtlib" + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir" +done +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>NewConnectionDialog</class> +<widget class="QDialog"> + <widget class="KLineEdit"> + <property name="name"> + <cstring>testInput</cstring> + </property> + </widget> +</widget> +</UI> +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([ +you need to install kdelibs first. + +If you did install kdelibs, then the Qt version that is picked up by +this configure is not the same version you used to compile kdelibs. +The Qt Plugin installed by kdelibs is *ONLY* loadable if it is the +_same Qt version_, compiled with the _same compiler_ and the same Qt +configuration settings. +]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + case $host in + *-*-linux-gnu) + KDE_CHECK_COMPILER_FLAG([Wl,--no-undefined], + [KDE_CHECK_COMPILER_FLAG([Wl,--allow-shlib-undefined], + [KDE_NO_UNDEFINED="-Wl,--no-undefined -Wl,--allow-shlib-undefined"], + [KDE_NO_UNDEFINED=""])], + [KDE_NO_UNDEFINED=""]) + ;; + esac + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +AC_MSG_ERROR([ +I can't find the designer plugins. These are required and should have been installed +by kdelibs]) +fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test -z "$1"; then +KDE_CHECK_UIC_PLUGINS +fi + +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext <<EOF +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif +#include <stdio.h> +#include "confdefs.h" +#include <kapp.h> + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include <qdom.h> + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + +if test $kde_qtver = 3; then + case $host in + *cygwin*) lib_kded="-lkdeinit_kded" ;; + *) lib_kded="" ;; + esac + AC_SUBST(LIB_KDED, $lib_kded) + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") + AC_SUBST(LIB_KUNITTEST, "-lkunittest") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES +]) + +dnl KDE_CHECK_FUNC_EXT(<func>, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +if test "$GXX" = "yes"; then +CXXFLAGS="$CXXFLAGS -pedantic-errors" +fi +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include <stdlib.h> +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include <stdlib.h> +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include <sys/types.h> + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include <stdlib.h> +#include <unistd.h> +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include <unistd.h> +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include <stdlib.h> +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include <stdlib.h> +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include <stdlib.h> +#include <unistd.h> +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include <stdlib.h> +#include <unistd.h> +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include <stdlib.h> +#include <unistd.h> +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include <string.h> +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include <string.h> +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <netdb.h> +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[ +#ifdef __cplusplus +extern "C" { +#endif +void jpeg_CreateDecompress(); +#ifdef __cplusplus +} +#endif +], +[jpeg_CreateDecompress();], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include <qapplication.h>], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include<zlib.h> +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (zlibVersion() == ZLIB_VERSION); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include<tiffio.h> +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + +AC_DEFUN([KDE_FIND_LIBEXR], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_CACHE_VAL(ac_cv_libexr, +[ + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + AC_MSG_CHECKING([for OpenEXR libraries]) + + if test "$PKG_CONFIG" = "no" ; then + AC_MSG_RESULT(no) + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if !(`$PKG_CONFIG --exists OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=no + else + if !(`$PKG_CONFIG --atleast-version="1.1.1" OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=old + else + kde_save_LIBS="$LIBS" + LIBS="$LIBS $all_libraries $USER_LDFLAGS $LIBZ `pkg-config --libs OpenEXR`" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_CXXFLAGS="$CXXFLAGS" + EXR_FLAGS=`$PKG_CONFIG --cflags OpenEXR` + CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES $EXR_FLAGS" + + AC_TRY_LINK(dnl + [ + #include <ImfRgbaFile.h> + ], + [ + using namespace Imf; + RgbaInputFile file ("dummy"); + return 0; + ], + eval "ac_cv_libexr='`pkg-config --libs OpenEXR`'", + eval "ac_cv_libexr=no" + ) + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + if eval "test ! \"`echo $ac_cv_libexr`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_EXR, 1, [Define if you have OpenEXR]) + LIB_EXR="$ac_cv_libexr" + AC_MSG_RESULT($ac_cv_libexr) + else + AC_MSG_RESULT(no) + LIB_EXR="" + fi + fi + fi + fi + AC_SUBST(LIB_EXR) + AC_SUBST(EXR_FLAGS) +]) + + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include<png.h> + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include<jasper/jasper.h> + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include <features.h> + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + + +AC_DEFUN([KDE_CHECK_FOR_BAD_COMPILER], +[ + AC_MSG_CHECKING([whether $CC is blacklisted]) + + dnl In theory we have tu run this test against $CC and $CXX + dnl in C and in C++ mode, because its perfectly legal for + dnl the user to mix compiler versions, since C has a defined + dnl ABI. + dnl + dnl For now, we assume the user is not on crack. + + AC_TRY_COMPILE([ +#ifdef __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 0 +choke me +#endif +#endif +], , + kde_bad_compiler=no, + kde_bad_compiler=yes +) + + AC_MSG_RESULT($kde_bad_compiler) + +if test "$kde_bad_compiler" = "yes"; then + AC_MSG_ERROR([ + +This particular compiler version is blacklisted because it +is known to miscompile KDE. Please use a newer version, or +if that is not yet available, choose an older version. + +Please do not report a bug or bother us reporting this +configure error. We know about it, and we introduced +it by intention to avoid untraceable bugs or crashes in KDE. + +]) +fi + +]) + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + KDE_CHECK_FOR_BAD_COMPILER + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + dnl ### FIXME: revert for KDE 4 + KDE_CHECK_COMPILER_FLAG(Wno-non-virtual-dtor,[CXXFLAGS="$CXXFLAGS -Wno-non-virtual-dtor"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + #include <string> + int some_function( void ) __attribute__ ((visibility("default"))); + int some_function( void ) + { + std::string s("blafasel"); + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_BEFORE([AC_PATH_QT_1_3], [KDE_ENABLE_HIDDEN_VISIBILITY]) + + AC_MSG_CHECKING([grepping for visibility push/pop in headers]) + + if test "x$GXX" = "xyes"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_EGREP_CPP( + [GCC visibility push], + [ #include <exception> + ], + [ + AC_MSG_RESULT(yes) + kde_stdc_visibility_patched=yes ], + [ + AC_MSG_RESULT(no) + AC_MSG_WARN([Your libstdc++ doesn't appear to be patched for + visibility support. Disabling -fvisibility=hidden]) + + kde_stdc_visibility_patched=no ]) + + AC_LANG_RESTORE + + kde_have_gcc_visibility=no + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + kde_have_gcc_visibility=yes + dnl the whole toolchain is just a mess, gcc is just too buggy + dnl to handle STL with visibility enabled. Lets reconsider + dnl when gcc 4.2 is out or when things get fixed in the compiler. + dnl Contact mueller@kde.org for details. + AC_ARG_ENABLE(gcc-hidden-visibility, + AC_HELP_STRING([--enable-gcc-hidden-visibility],[toolchain hidden visibility [default=no]]), + [kde_have_gcc_visibility=$enableval], + [kde_have_gcc_visibility=no]) + + AC_CACHE_CHECK([if Qt is patched for -fvisibility], kde_cv_val_qt_gcc_visibility_patched, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $all_includes" + + AC_TRY_COMPILE( + [ +#include <qglobal.h> +#if Q_EXPORT - 0 != 0 +/* if this compiles, then Q_EXPORT is undefined */ +/* if Q_EXPORT is nonempty, this will break compilation */ +#endif + ], [/* elvis is alive */], + kde_cv_val_qt_gcc_visibility_patched=no, kde_cv_val_qt_gcc_visibility_patched=yes) + + CXXFLAGS=$safe_CXXFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_have_gcc_visibility = "xyes" && test x$kde_stdc_visibility_patched = "xyes" && test x$kde_cv_val_qt_gcc_visibility_patched = "xyes"; then + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + fi + ]) + fi +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# This hack ensures that libtool creates shared libs for kunittest plugins. By default check_LTLIBRARIES makes static libs. +KDE_CHECK_PLUGIN="\$(KDE_PLUGIN) -rpath \$(libdir)" +AC_SUBST(KDE_CHECK_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + kdelibsuff="$kde_libs_suffix" + if test -z "$kdelibsuff"; then + kdelibsuff=no + fi + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none[=default])]), + kdelibsuff=$enableval) + # TODO: add an auto case that compiles a little C app to check + # where the glibc is + if test "$kdelibsuff" = "no"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include <sys/types.h> + #include <sys/socket.h> + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include <sys/types.h> + #include <sys/socket.h> + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper <drepper@cygnus.com>, 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in <locale.h>. +# Ulrich Drepper <drepper@cygnus.com>, 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper <drepper@cygnus.com>, 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include <string.h> + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include <X11/xpm.h>],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries" + LIBS="-lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include <X11/Xproto.h> + #include <X11/X.h> + #include <X11/Xlib.h> + #include <X11/extensions/dpms.h> + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LIBS="-lXdpms $LIBS" + AC_TRY_LINK([ + #include <X11/Xproto.h> + #include <X11/X.h> + #include <X11/Xlib.h> + #include <X11/extensions/dpms.h> + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in <X11/extensions/dpms.h>]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include <X11/Xlib.h> + #include <X11/extensions/dpms.h>]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in <X11/extensions/dpms.h>]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include <X11/Xlib.h> + #include <X11/extensions/dpms.h>]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags=$LDFLAGS + ac_save_cxxflags=$CXXFLAGS + ac_save_libs=$LIBS + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries" + LIBS="$LIBS -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && LIBS="$LIBS -lX11" + LIBS="$LIBS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include <GL/gl.h> +#include <GL/glu.h> +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS=$ac_save_ldflags + CXXFLAGS=$ac_save_cxxflags + LIBS=$ac_save_libs + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include <pthread.h>],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include <Python.h> +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include <string> +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include <qimageio.h> +#include <qstring.h> +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include <sys/stat.h> +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext <<EOF +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif +#include <stdio.h> +#include <sys/param.h> +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + kde_libs_suffix=`$KDECONFIG --libsuffix` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$dir" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include <jni.h> + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Xlinker -framework -Xlinker JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext <<EOF +#include "confdefs.h" +#include <qpe/qpeapplication.h> +#include <qpe/version.h> + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include<bzlib.h> +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include<bzlib.h> + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext <<EOF +#include <openssl/opensslv.h> +#include <stdio.h> + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure <faure@kde.org>, attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure <faure@kde.org>, attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES($1,$2,$3,$4) +]) + + +dnl Check for PIE support in the compiler and linker +AC_DEFUN([KDE_CHECK_PIE_SUPPORT], +[ + AC_CACHE_CHECK([for PIE support], kde_cv_val_pie_support, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fpie" + LDFLAGS="$LDFLAGS -pie" + + AC_TRY_LINK([int foo;], [], [kde_cv_val_pie_support=yes], [kde_cv_val_pie_support=no]) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ]) + + AC_MSG_CHECKING(if enabling -pie/fpie support) + + AC_ARG_ENABLE(pie, + AC_HELP_STRING([--enable-pie],[platform supports PIE linking [default=detect]]), + [kde_has_pie_support=$enableval], + [kde_has_pie_support=detect]) + + if test "$kde_has_pie_support" = "detect"; then + kde_has_pie_support=$kde_cv_val_pie_support + fi + + AC_MSG_RESULT([$kde_has_pie_support]) + + KDE_USE_FPIE="" + KDE_USE_PIE="" + + AC_SUBST([KDE_USE_FPIE]) + AC_SUBST([KDE_USE_PIE]) + + if test "$kde_has_pie_support" = "yes"; then + KDE_USE_FPIE="-fpie" + KDE_USE_PIE="-pie" + fi +]) +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 47 AC_PROG_LIBTOOL + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool --silent' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([LT_AC_PROG_SED])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="[$]2" +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +[$]* +EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +AC_DIVERT_POP +])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-linux*) + # Test if the compiler is 64bit + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *"ELF 32"*) + LINUX_64_MODE="32" + ;; + *"ELF 64"*) + LINUX_64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $3" + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + if (eval $ac_compile 2>conftest.err) && test -s $ac_outfile; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + CFLAGS="$save_CFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + testring="ABCD" + + case $host_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ + = "XX$testring") >/dev/null 2>&1 && + new_result=`expr "X$testring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + testring=$testring$testring + done + testring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + cygwin* | mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + ifelse([$1],[],[save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"], + [$1],[CXX],[save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -o out/conftest2.$ac_objext"], + [$1],[GCJ],[save_GCJFLAGS="$GCJFLAGS" + GCJFLAGS="$GCJFLAGS -o out/conftest2.$ac_objext"]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + # According to Tom Tromey, Ian Lance Taylor reported there are C compilers + # that will create temporary files in the current directory regardless of + # the output directory. Thus, making CWD read-only will cause this test + # to fail, enabling locking or at least warning the user not to do parallel + # builds. + chmod -w . + + if (eval $ac_compile 2>out/conftest.err) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + # Append any errors to the config.log. + cat out/conftest.err 1>&AS_MESSAGE_LOG_FD + else + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + ifelse([$1],[],[CFLAGS="$save_CFLAGS"], + [$1],[CXX],[CXXFLAGS="$save_CXXFLAGS"], + [$1],[GCJ],[GCJFLAGS="$save_GCJFLAGS"]) + chmod u+w . + $rm conftest* out/* + rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)"; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4* | aix5*) + version_type=linux + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}.so$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + need_version=no + need_lib_prefix=no + case $GCC,$host_os in + yes,cygwin*) + library_names_spec='$libname.dll.a' + sys_lib_search_path_spec="/lib /lib/w32api /usr/lib /usr/local/lib" + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog .libs/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + ;; + yes,mingw*) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://"` + if echo "$sys_lib_search_path_spec" | [egrep ';[C-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | sed -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | sed -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + yes,pw32*) + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' + ;; + *) + library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. + library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)' + soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + if test "$host_cpu" = ia64; then + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + else + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + fi + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + libsuff= + if test "x$LINUX_64_MODE" = x64; then + # Some platforms are per default 64-bit, so there's no /lib64 + if test -d /lib64; then + libsuff=64 + fi + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags=TAGS], + [include additional configurations @<:@CXX,GCJ@:>@])], + [tagnames="$withval"], + [tagnames="CXX,GCJ" + case $host_os in + mingw*|cygwin*) tagnames="$tagnames,RC" ;; + esac]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | sed -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + AC_LIBTOOL_LANG_CXX_CONFIG + ;; + + GCJ) + AC_LIBTOOL_LANG_GCJ_CONFIG + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + available_tags="$available_tags $tagname" + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <<EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +])# AC_PROG_LD + + +# AC_PROG_LD_GNU +# -------------- +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +])# AC_PROG_LD_GNU + + +# AC_PROG_LD_RELOAD_FLAG +# ---------------------- +# find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], + lt_cv_ld_reload_flag, + [lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +])# AC_PROG_LD_RELOAD_FLAG + + +# AC_DEPLIBS_CHECK_METHOD +# ----------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_CACHE_CHECK([how to recognise dependant libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* | pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[[012]]) + lt_cv_file_magic_test_file=`/System/Library/Frameworks/System.framework/System` + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + if test "$host_cpu" = ia64; then + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + else + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + fi + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | ia64* | m68* | mips | mipsel | powerpc* | sparc* | s390* | sh* | x86_64* ) + lt_cv_deplibs_check_method=pass_all ;; + # the debian people say, arm and glibc 2.3.1 works for them with pass_all + arm* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ("$tmp_nm" -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ("$tmp_nm" -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# If this macro is not defined by Autoconf, define it here. +ifdef([AC_PROVIDE_IFELSE], + [], + [define([AC_PROVIDE_IFELSE], + [ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([AC_PROG_RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='main(){return(0);}' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | egrep -e "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C test sources. +ac_ext=cc + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int char *[]) { return(0); }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${CXX-"c++"} +set dummy $CC +compiler="[$]2" +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if eval "`$CC -print-prog-name=ld` --version 2>&1" | \ + egrep 'GNU ld' > /dev/null; then + with_gnu_ld=yes + + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + egrep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux*) + if test $with_gnu_ld = no; then + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + else + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + fi + fi + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + else + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + fi + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case $host_os in + hpux9*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + ;; + *) + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + fi + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_os in + hpux9*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + ;; + *) + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + fi + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest.so 2>&1 | egrep "ld"`; rm -f libconftest.so; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + # NetBSD uses g++ - do we need to do anything? + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='templib=`echo $lib | sed -e "s/\.so\..*/\.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | sed "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | egrep "\-R|\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | egrep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $linker_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | egrep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $linker_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | egrep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# Figure out "hidden" C++ library dependencies from verbose +# compiler output whening linking a shared library. +cat > conftest.$ac_ext <<EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +EOF + + +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd="`$echo \"X$output_verbose_link_cmd\" | $Xsed -e \"$no_glob_subst\"`" + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then + _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext|*.$libext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then + _LT_AC_TAGVAR(predep_objects, $1)="$p" + else + _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then + _LT_AC_TAGVAR(postdep_objects, $1)="$p" + else + _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out +else + echo "libtool.m4: error: problem compiling C++ test program" +fi + +$rm -f confest.$objext + +case " $_LT_AC_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; +*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes ;; +esac + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_CXX_CONFIG + + +# AC_LIBTOOL_LANG_GCJ_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)]) +AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG], +[AC_LANG_SAVE + +# Source file extension for C test sources. +ac_ext=java + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +set dummy $CC +compiler="[$]2" +_LT_AC_TAGVAR(compiler, $1)=$CC + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_GCJ_CONFIG + + +# AC_LIBTOOL_LANG_RC_CONFIG +# -------------------------- +# Ensure that the configuration vars for the Windows resource compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)]) +AC_DEFUN([_LT_AC_LANG_RC_CONFIG], +[AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +set dummy $CC +compiler="[$]2" +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_RESTORE +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_RC_CONFIG + + +# AC_LIBTOOL_CONFIG([TAGNAME]) +# ---------------------------- +# If TAGNAME is not passed, then create an initial libtool script +# with a default configuration from the untagged config vars. Otherwise +# add code to config.status for appending the configuration named by +# TAGNAME from the matching tagged config vars. +AC_DEFUN([AC_LIBTOOL_CONFIG], +[# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS RANLIB LN_S LTCC NM SED SHELL \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + _LT_AC_TAGVAR(compiler, $1) \ + _LT_AC_TAGVAR(CC, $1) \ + _LT_AC_TAGVAR(LD, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \ + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \ + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \ + _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \ + _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \ + _LT_AC_TAGVAR(old_archive_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \ + _LT_AC_TAGVAR(predep_objects, $1) \ + _LT_AC_TAGVAR(postdep_objects, $1) \ + _LT_AC_TAGVAR(predeps, $1) \ + _LT_AC_TAGVAR(postdeps, $1) \ + _LT_AC_TAGVAR(compiler_lib_search_path, $1) \ + _LT_AC_TAGVAR(archive_cmds, $1) \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) \ + _LT_AC_TAGVAR(postinstall_cmds, $1) \ + _LT_AC_TAGVAR(postuninstall_cmds, $1) \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \ + _LT_AC_TAGVAR(allow_undefined_flag, $1) \ + _LT_AC_TAGVAR(no_undefined_flag, $1) \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \ + _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \ + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \ + _LT_AC_TAGVAR(exclude_expsyms, $1) \ + _LT_AC_TAGVAR(include_expsyms, $1); do + + case $var in + _LT_AC_TAGVAR(old_archive_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \ + _LT_AC_TAGVAR(archive_cmds, $1) | \ + _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \ + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \ + _LT_AC_TAGVAR(export_symbols_cmds, $1) | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\[$]0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'` + ;; + esac + +ifelse([$1], [], + [cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + AC_MSG_NOTICE([creating $ofile])], + [cfgfile="$ofile"]) + + cat <<__EOF__ >> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A sed program that does not truncate output. +SED=$lt_SED + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + + cygwin* | mingw* | pw32* | os2*) + cat <<'EOF' >> "$cfgfile" + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments + _LT_AC_FILE_LTDLL_C + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments + _LT_AC_FILE_IMPGEN_C +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions -c conftest.$ac_ext], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $host_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[[ABCDGISTW]]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat <<EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <<EOF >> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + cygwin* | mingw* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX, but not for PA HP-UX. + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + fi + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX, but not for PA HP-UX. + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + fi + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + cygwin* | mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + if test "$CC" = "icc"; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + fi + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + if test "x$host_vendor" = xsni; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-LD' + else + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + fi + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) -DPIC], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) -DPIC" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | egrep '(GNU)' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + cygwin* | mingw* | pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an egrep regular expression of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + + extract_expsyms_cmds='test -f $output_objdir/impgen.c || \ + sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~ + test -f $output_objdir/impgen.exe || (cd $output_objdir && \ + if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \ + else $CC -o impgen impgen.c ; fi)~ + $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def' + + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib' + + # cygwin and mingw dlls have different entry points and sets of symbols + # to exclude. + # FIXME: what about values for MSVC? + dll_entry=__cygwin_dll_entry@12 + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~ + case $host_os in + mingw*) + # mingw values + dll_entry=_DllMainCRTStartup@12 + dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~ + ;; + esac + + # mingw and cygwin differ, and it's simplest to just exclude the union + # of the two symbol sets. + dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one (in ltdll.c) + if test "x$lt_cv_need_dllmain" = "xyes"; then + ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext " + ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~ + test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~' + else + ltdll_obj= + ltdll_cmds= + fi + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left by newer dlltools. + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"' + $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols' + + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is. + # If DATA tags from a recent dlltool are present, honour them! + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`head -n 1 $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname-def; + else + echo EXPORTS > $output_objdir/$soname-def; + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \[$]# in + 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done; + fi~ + '"$ltdll_cmds"' + $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~ + $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~ + $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw* | pw32*) + # dlltool doesn't understand --whole-archive et. al. + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + ;; + esac + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | egrep '(GNU)' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + ;; + + darwin* | rhapsody*) + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-undefined suppress' + ;; + *) # Darwin 1.3 on + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-flat_namespace -undefined suppress' + ;; + esac + + # FIXME: Relying on posixy $() will cause problems for + # cross-compilation, but unfortunately the echo tests do not + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + _LT_AC_TAGVAR(archive_cmds, $1)='$CC $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # We need to add '_' to the symbols in $export_symbols first + #_LT_AC_TAGVAR(archive_expsym_cmds, $1)="$_LT_AC_TAGVAR(archive_cmds, $1)"' && strip -s $export_symbols' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9* | hpux10* | hpux11*) + if test "$GCC" = yes; then + case $host_os in + hpux9*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + ;; + *) + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + esac + else + case $host_os in + hpux9*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + ;; + *) + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + ;; + esac + fi + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + else + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + fi + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + if test "x$host_vendor" = xsni; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes +if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + echo 'static int dummy;' > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac +fi +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include <windows.h> +# #undef WIN32_LEAN_AND_MEAN +# #include <stdio.h> +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include <cygwin/cygwin_dll.h> +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_FILE_IMPGEN_C +# -------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_IMPGEN_C], [ +# /* impgen.c starts here */ +# /* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include <stdio.h> /* for printf() */ +# #include <unistd.h> /* for open(), lseek(), read() */ +# #include <fcntl.h> /* for O_RDONLY, O_BINARY */ +# #include <string.h> /* for strdup() */ +# +# /* O_BINARY isn't required (or even defined sometimes) under Unix */ +# #ifndef O_BINARY +# #define O_BINARY 0 +# #endif +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (dll < 1) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i<nexp; i++) +# { +# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4); +# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i); +# } +# +# return 0; +# } +# /* impgen.c ends here */ +])# _LT_AC_FILE_IMPGEN_C + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + _sed_list="$_sed_list $as_dir/$ac_prog$ac_exec_ext" + fi + done + done +done + + # Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/sedXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/sed$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + _max=0 + _count=0 + # Add /usr/xpg4/bin/sed as it is typically found on Solaris + # along with /bin/sed that truncates output. + for _sed in $_sed_list /usr/xpg4/bin/sed; do + test ! -f ${_sed} && break + cat /dev/null > "$tmp/sed.in" + _count=0 + echo $ECHO_N "0123456789$ECHO_C" >"$tmp/sed.in" + # Check for GNU sed and select it if it is found. + if "${_sed}" --version 2>&1 < /dev/null | egrep '(GNU)' > /dev/null; then + lt_cv_path_SED=${_sed} + break; + fi + while true; do + cat "$tmp/sed.in" "$tmp/sed.in" >"$tmp/sed.tmp" + mv "$tmp/sed.tmp" "$tmp/sed.in" + cp "$tmp/sed.in" "$tmp/sed.nl" + echo >>"$tmp/sed.nl" + ${_sed} -e 's/a$//' < "$tmp/sed.nl" >"$tmp/sed.out" || break + cmp -s "$tmp/sed.out" "$tmp/sed.nl" || break + # 10000 chars as input seems more than enough + test $_count -gt 10 && break + _count=`expr $_count + 1` + if test $_count -gt $_max; then + _max=$_count + lt_cv_path_SED=$_sed + fi + done + done + rm -rf "$tmp" +]) +AC_MSG_RESULT([$SED]) +]) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..583efff --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,902 @@ +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(AC_AUTOCONF_VERSION, [2.62],, +[m4_warning([this file was generated for autoconf 2.62. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.10' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.10.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 13 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.60])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..c22241f --- /dev/null +++ b/config.h.in @@ -0,0 +1,252 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the <Carbon/Carbon.h> header file. */ +#undef HAVE_CARBON_CARBON_H + +/* Define if you have the CoreAudio API */ +#undef HAVE_COREAUDIO + +/* Define to 1 if you have the <crt_externs.h> header file. */ +#undef HAVE_CRT_EXTERNS_H + +/* Defines if your system has the crypt function */ +#undef HAVE_CRYPT + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have libjpeg */ +#undef HAVE_LIBJPEG + +/* Define if you have libpng */ +#undef HAVE_LIBPNG + +/* Define if you have a working libpthread (will enable threaded code) */ +#undef HAVE_LIBPTHREAD + +/* Define if you have libz */ +#undef HAVE_LIBZ + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if your system needs _NSGetEnviron to set up the environment */ +#undef HAVE_NSGETENVIRON + +/* Define if you have res_init */ +#undef HAVE_RES_INIT + +/* Define if you have the res_init prototype */ +#undef HAVE_RES_INIT_PROTO + +/* Define if you have a STL implementation by SGI */ +#undef HAVE_SGI_STL + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have strlcat */ +#undef HAVE_STRLCAT + +/* Define if you have the strlcat prototype */ +#undef HAVE_STRLCAT_PROTO + +/* Define if you have strlcpy */ +#undef HAVE_STRLCPY + +/* Define if you have the strlcpy prototype */ +#undef HAVE_STRLCPY_PROTO + +/* Define to 1 if you have the <sys/bitypes.h> header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Suffix for lib directories */ +#undef KDELIBSUFF + +/* Define a safe value for MAXPATHLEN */ +#undef KDEMAXPATHLEN + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char *', as computed by sizeof. */ +#undef SIZEOF_CHAR_P + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of `unsigned long', as computed by sizeof. */ +#undef SIZEOF_UNSIGNED_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Defined if compiling without arts */ +#undef WITHOUT_ARTS + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +#elif ! defined __LITTLE_ENDIAN__ +# undef WORDS_BIGENDIAN +#endif + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif + + + +/* + * AIX defines FD_SET in terms of bzero, but fails to include <strings.h> + * that defines bzero. + */ + +#if defined(_AIX) +#include <strings.h> +#endif + + + +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include <sys/time.h> +# include <crt_externs.h> +# define environ (*_NSGetEnviron()) +#endif + + + +#if !defined(HAVE_RES_INIT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +int res_init(void); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCAT_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcat(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +#if !defined(HAVE_STRLCPY_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +unsigned long strlcpy(char*, const char*, unsigned long); +#ifdef __cplusplus +} +#endif +#endif + + + +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include <stdarg.h> +#include <stdlib.h> +#else +#include <varargs.h> +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif + + + +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif + + +/* type to use in place of socklen_t if not defined */ +#undef kde_socklen_t + +/* type to use in place of socklen_t if not defined (deprecated, use + kde_socklen_t) */ +#undef ksize_t diff --git a/configure.files b/configure.files new file mode 100644 index 0000000..030bce8 --- /dev/null +++ b/configure.files @@ -0,0 +1,2 @@ +./admin/configure.in.min +configure.in.in diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..f15e1ab --- /dev/null +++ b/configure.in @@ -0,0 +1,93 @@ +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 2001 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. + +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl This ksh/zsh feature conflicts with `cd blah ; pwd` +unset CDPATH + +dnl Checking host/target/build systems, for make, install etc. +AC_CANONICAL_SYSTEM +dnl Perform program name transformation +AC_ARG_PROGRAM + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(kscope, 1.6.2) dnl searches for some needed programs + +KDE_SET_PREFIX + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +KDE_PROG_LIBTOOL + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files +AM_KDE_WITH_NLS + +KDE_USE_QT(3.3) +AC_PATH_KDE +#MIN_CONFIG(3.3) + +dnl PACKAGE set before +AC_C_BIGENDIAN +AC_CHECK_KDEMAXPATHLEN + +AM_PROG_LEX +AC_CHECK_PROG(HAVE_LEX, $LEX, yes, no) +if [[ "$HAVE_LEX" = "no" ]]; then + AC_MSG_ERROR(Lex/Flex is required in order to build KScope) +fi + +AC_PROG_YACC +AC_CHECK_PROG(HAVE_YACC, $YACC, yes, no) +if [[ "$HAVE_YACC" = "no" ]]; then + AC_MSG_ERROR(Yacc/Bison is required in order to build KScope) +fi +KDE_CREATE_SUBDIRSLIST +AC_CONFIG_FILES([ Makefile ]) +AC_CONFIG_FILES([ doc/Makefile ]) +AC_CONFIG_FILES([ doc/en/Makefile ]) +AC_CONFIG_FILES([ po/Makefile ]) +AC_CONFIG_FILES([ src/Makefile ]) +AC_OUTPUT +if test "$all_tests" = "bad"; then + if test ! "$cache_file" = "/dev/null"; then + echo "" + echo "Please remove the file $cache_file after changing your setup" + echo "so that configure will find the changes next time." + echo "" + fi +else + echo "" + echo "Good - your configure finished. Start make now" + echo "" +fi diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..032475b --- /dev/null +++ b/configure.in.in @@ -0,0 +1,17 @@ +#MIN_CONFIG(3.3) + +AM_INIT_AUTOMAKE(kscope, 1.6.2) +AC_C_BIGENDIAN +AC_CHECK_KDEMAXPATHLEN + +AM_PROG_LEX +AC_CHECK_PROG(HAVE_LEX, $LEX, yes, no) +if [[ "$HAVE_LEX" = "no" ]]; then + AC_MSG_ERROR(Lex/Flex is required in order to build KScope) +fi + +AC_PROG_YACC +AC_CHECK_PROG(HAVE_YACC, $YACC, yes, no) +if [[ "$HAVE_YACC" = "no" ]]; then + AC_MSG_ERROR(Yacc/Bison is required in order to build KScope) +fi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..7e7a4a8 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,6 @@ +# the SUBDIRS is filled automatically by am_edit. If files are +# in this directory they are installed into the english dir + +KDE_LANG = en +KDE_DOCS = kscope +SUBDIRS = $(AUTODIRS) diff --git a/doc/en/Makefile.am b/doc/en/Makefile.am new file mode 100644 index 0000000..fef2a0a --- /dev/null +++ b/doc/en/Makefile.am @@ -0,0 +1,5 @@ +KDE_DOCS = kscope +KDE_LANG = en +kde_docs_KDEDOCS = call_tree.png main_window.png pref.png project_files.png \ + project_new.png project_open.png query_dlg.png autocomp_dlg.png query_filter.png \ + call_graph.png diff --git a/doc/en/about.docbook b/doc/en/about.docbook new file mode 100644 index 0000000..1bb7173 --- /dev/null +++ b/doc/en/about.docbook @@ -0,0 +1,31 @@ +<sect1 id="about"> +<title>About &kapp;</title> + +<para> +&kapp; is a KDE-based source-editing environment for C and C-style languages. Primarily, it is a front-end to the veteran <ulink url="http://cscope.sourceforge.net">Cscope</ulink>, a source-code browser originally developed at Bell Labs. <application>Cscope</application> works by parsing a set of source files, creating a cross-reference database, and allowing the user to query this database. &kapp; extends the feature-set of <application>Cscope</application> with a contemporary user interface, editor integration, project management capabilities, multiple query result windows, call trees and graphs, and more. +</para> + +<para> +&kapp; implements (almost) all of <application>Cscope</application>'s query types. Among these are: +<itemizedlist> +<listitem><para>Browse for all references to a symbol;</para></listitem> +<listitem><para>Get the global definition of a symbol;</para></listitem> +<listitem><para>Find all functions calling to or called by a function;</para></listitem> +<listitem><para>Find a text string or an EGrep pattern;</para></listitem> +<listitem><para>and more.</para></listitem> +</itemizedlist> +</para> + +<para> +The main purpose of &kapp; is to provide developers with a rich environment for code editing and analysis. It is specifically geared towards large projects, with thousands of source files and millions of lines of code. Many traditional C/C++ IDEs do not scale well to handle projects of this magnitude, either because they do not provide adequate tools for understanding the code base, or because they are unable to efficiently digest that much information. By using <application>Cscope</application> as its underlying engine, &kapp; can easily handle projects such as the <ulink url="http://www.kernel.org">Linux kernel</ulink>, <ulink url="http://www.winehq.org">WINE</ulink>, <ulink url="http://www.postgresql.org">PostgreSQL</ulink>, etc. +</para> + +<note><para> +It has been reported by some users that &kapp; can be successfully used for C++ development. Nonetheless, &kapp; is mainly a tool for developing in pure C (either ANSI or K&R style). Most C++ features will not be recognised by the cross-reference generator. +</para></note> + +<para> +&kapp; is a part of an ongoing effort to expand the range of open source applications. It could not have been created without the previous work of many devoted developers. &kapp; is therefore freely distributed, along with its source code, for the benefit of the open source community. I hope it can be of use to others, and I would appreciate any help in the form of bug reports or improvement suggestions. +</para> + +</sect1> diff --git a/doc/en/autocomp_dlg.png b/doc/en/autocomp_dlg.png Binary files differnew file mode 100644 index 0000000..21d39e4 --- /dev/null +++ b/doc/en/autocomp_dlg.png diff --git a/doc/en/bookmarks.docbook b/doc/en/bookmarks.docbook new file mode 100644 index 0000000..8607645 --- /dev/null +++ b/doc/en/bookmarks.docbook @@ -0,0 +1,28 @@ +<sect1 id="bookmarks"> +<title>Bookmarks</title> + +<para> +Bookmarks provide an easy way to navigate through a defined set of positions in the source code. Most editors support the concept of bookmarks as tags attached to lines in a source file. &kapp; can enhance the usablity of per-file markers by enabling users to access the bookmarks currently defined in all open files. &kapp; also saves and restores these bookmarks as part of its session-management services. +</para> + +<para> +The <guilabel>Bookmarks</guilabel> dialogue is invoked by the <menuchoice><guimenu>Go</guimenu><guimenuitem>Global Bookmarks</guimenuitem></menuchoice> menu command. Once open, it displays the set bookmarks among all currently-open files. This includes the file path, the source line and the line's text (similar to other source views available in &kapp;). +</para> + +<screenshot> +<screeninfo>The Bookmarks dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="bookmarks.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Bookmarks dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> + +<para> +Navigating to a defined bookmark can be done by either double-clicking an entry in the dialogue, or by choosing the <menuchoice><guimenuitem>View Source</guimenuitem></menuchoice> item from the context menu (available by right-clicking over a bookmark entry). Other choices presented by the context menu include <menuchoice><guimenuitem>Copy [FIELD]</guimenuitem></menuchoice> for copying the contents of the current field to the clipboard, <menuchoice><guimenuitem>Filter...</guimenuitem></menuchoice> for selecting entries based on some criteria, <menuchoice><guimenuitem>Show All</guimenuitem></menuchoice> for removing all filters and <menuchoice><guimenuitem>Remove Item</guimenuitem></menuchoice> for deleting the bookmark. +</para> + +</sect1>
\ No newline at end of file diff --git a/doc/en/bookmarks.png b/doc/en/bookmarks.png Binary files differnew file mode 100644 index 0000000..2f20be7 --- /dev/null +++ b/doc/en/bookmarks.png diff --git a/doc/en/call_graph.png b/doc/en/call_graph.png Binary files differnew file mode 100644 index 0000000..719f3f7 --- /dev/null +++ b/doc/en/call_graph.png diff --git a/doc/en/call_tree.png b/doc/en/call_tree.png Binary files differnew file mode 100644 index 0000000..010be6c --- /dev/null +++ b/doc/en/call_tree.png diff --git a/doc/en/config_dlg.docbook b/doc/en/config_dlg.docbook new file mode 100644 index 0000000..ba2fed3 --- /dev/null +++ b/doc/en/config_dlg.docbook @@ -0,0 +1,206 @@ +<sect1 id="config-dlg"> +<title>The Configuration Dialogue</title> + +<para> +The configuration dialogue is the main tool for setting parameters required by &kapp;, or adjusting the user's preferences. The dialogue is displayed the first time &kapp; is run, and can be invoked later by using the <menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure KScope...</guimenuitem></menuchoice> menu command. +</para> + +<para> +The dialogue is composed of several pages, each of which handles a different set of parameters. +</para> + +<sect2 id="config-progs"> +<title>The Programmes Page</title> + +<para> +&kapp; serves as a front-end to several console-based programmes: <application>Cscope</application>, <application>Ctags</application> and <application>Dot</application> (which is part of the <application>Graphviz</application> suite). Since &kapp; invokes these programmes directly, without using a shell, it cannot determine their paths. Therefore, it is required to inform &kapp; of the paths where the relevant executable files reside. Note that &kapp; needs the full path to each programme, along with the name of the executable. +</para> + +<para> +Another parameter required by &kapp; is whether <application>Cscope</application> supports the <option>-v</option> command line option. This is a relatively new feature, added to <application>Cscope</application> in version 15.5. It allows &kapp; to display accurate progress information during time-consuming operations, such as building the cross-reference database, or running a long query. It is highly recommended that you upgrade <application>Cscope</application> to a version that supports the <option>-v</option> option, as the user experience of &kapp; is much improved with it. However, if you choose to use an older version of <application>Cscope</application>, make sure the check-box for using the <option>-v</option> option is cleared. +</para> + +<para> +You can determine whether your version of <application>Cscope</application> supports this option by running <userinput><option>cscope</option> <option>-h</option></userinput>. +</para> + +<para> +The easiest way to configure programme paths is by using the automated script provided with &kapp;. This script can be activated by clicking the <guibutton>Guess...</guibutton> button. Once invoked, the script looks for the required programmes (using the shell's <filename>which</filename> utility). The script also makes sure that the found executables adhere to the standards required by &kapp; (e.g., that <application>Ctags</application> is the one provided by <application>Exuberant-Ctags</application> and that <application>Dot</application> supports the <option>-Tplain</option> command-line option). &kapp; uses the results of the script to adjust the values in the dialogue's controls. +</para> + +<note> +<para>The script will not override paths already set by the user. Instead, it will only verify the validity of these paths. For the script to determine paths automatically, the relevant text fields in the dialogue need to be cleared.</para> +</note> + +<para> +<screenshot> +<screeninfo>The Programmes page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="pref_progs.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Programmes page</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Cscope Path</guilabel></term> +<listitem><para>The full path of the Cscope executable. The name of this executable must be <filename>cscope</filename>.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Use verbose mode (-v)</guilabel></term> +<listitem><para>Instructs Cscope to produce verbose progress output, by appending <option>-v</option> to the command line.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Ctags Path</guilabel></term> +<listitem><para>The full path of the Ctags executable. The name of this executable must contain the string <filename>ctags</filename>.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Dot Path</guilabel></term> +<listitem><para>The full path of the Dot executable. The name of this executable must be <filename>dot</filename>.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Guess</guibutton></term> +<listitem><para><action>Runs a script which attempts to determine the previous values automatically.</action> This script should work in most cases, by may fail to correctly obtain some or all of the values.</para></listitem> +</varlistentry> +</variablelist> +If the file names on your system do not conform to the limitations described above, please create symbolic links to the executables. +</para> + +</sect2> + +<sect2 id="config-clrs"> +<title>The Colours Page</title> + +<para> +<screenshot> +<screeninfo>The Colours page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="pref_clrs.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Colours page</phrase> +</textobject> +</mediaobject> +</screenshot> + +The Colours page allows you to configure &kapp; to look the way you want it to, by changing the foreground and background colours of some of &kapp;'s GUI elements. The elements that can be modified are: +<itemizedlist> +<listitem><para>The project's file list (to the right of the editing area)</para></listitem> +<listitem><para>The editor's symbol (or tag) list (to the left of each editor window)</para></listitem> +<listitem><para>The query results window</para></listitem> +<listitem><para>The call graph's background and nodes</para></listitem> +</itemizedlist> +</para> + +<para> +To change the colour of a GUI element, double-click over the element's entry in the list (or select this element and click <keycap>Enter</keycap>). +</para> + +<note> +<para>The editor's own colours are determined by the settings of the embedded editor, and are not controlled by &kapp;.</para> +</note> + +</sect2> + +<sect2 id="config-fonts"> +<title>The Fonts Page</title> + +<para> +<screenshot> +<screeninfo>The Fonts page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="pref_fonts.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Fonts page</phrase> +</textobject> +</mediaobject> +</screenshot> + +The Fonts page allows you to determine the fonts used by any of &kapp;'s windows (see <link linkend="config-clrs">The Colours Page</link> section for a description of these windows.) +</para> + +<para> +To change the colour of a GUI element, double-click over the element's entry in the list (or select this element and click <keycap>Enter</keycap>). +</para> + +<note> +<para>As with the colour scheme, the fonts used by the embedded editor are not determined by &kapp;.</para> +</note> + +</sect2> + +<sect2 id="config-opts"> +<title>The Options Page</title> + +<para> +This page allows the user to configure certain parameters that affect the behaviour of &kapp;. +</para> + +<para> +<screenshot> +<screeninfo>The Options page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="pref_opts.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Options page</phrase> +</textobject> +</mediaobject> +</screenshot> +<variablelist> +<varlistentry> +<term><guilabel>External Editor</guilabel></term> +<listitem><para>Specifies a command line for invoking an external editor application. &kapp; will replace the escape sequence %F with the file path, and the sequence %L with the current line number.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Read-Only Mode</guilabel></term> +<listitem><para>If set, the embedded editor will be work in read-only mode, i.e., &kapp; will not allow any changes to the displayed source files (but you can still use the external editor).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Open Last Project on Start-Up</guilabel></term> +<listitem><para>Determines whether &kapp; should automatically attempt to load the last active project when started.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Automatic Tag Highlighting</guilabel></term> +<listitem><para>If set, &kapp; will highlight tags in the tag list based on the current position of the text cursor.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Brief Tab Captions for Query Pages</guilabel></term> +<listitem><para>This option allows some space to be saved by using shortcuts for the page titles in the query window.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Warn When a File is Modified Outside &kapp;</guilabel></term> +<listitem><para>If set, &kapp; will issue a warning whenever a file is changed on the hard drive, while it is open for editing in &kapp;. This option will only work in conjunction with the Kate text editor).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Automatically Sort Files in the File List</guilabel></term> +<listitem><para>By default, &kapp; will sort the files in the project's file list whenever a project is loaded. However, such behaviour may not be suitable for large projects on older machines, causing &kapp; to hang for long periods when loading such projects. Uncheck this option to avoid automatic sorting.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>System Profile</guilabel></term> +<listitem><para>Allows the choice between a fast and a slow system configuration. The fast profile will take certain actions automatically which are not appropriate for a slower system (for example, automatic database rebuilds and auto-completion are enabled by default for fast systems and disabled for slow systems). Note that the terms "fast" and "slow" do not necessarily refer to the particular machine which runs &kapp;, but rather to the complete environment (e.g., a fast machine may still be using a relatively slow file server).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Editor Popup Menu</guilabel></term> +<listitem><para>Provides two choices for the embedded editor's context menu: +<itemizedlist> +<listitem><para>Embedded: A menu with Cscope actions is included as a sub-menu of the editor's own context menu.</para></listitem> +<listitem><para>&kapp; Only: Only Cscope actions are available through the context menu.</para></listitem> +</itemizedlist> +The second choice provides quicker access to Cscope commands, but the editor's menu is discarded. +</para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +</sect1> diff --git a/doc/en/editing.docbook b/doc/en/editing.docbook new file mode 100644 index 0000000..2aeeece --- /dev/null +++ b/doc/en/editing.docbook @@ -0,0 +1,138 @@ +<sect1 id="editing"> +<title>Editing Source Files</title> + +<sect2 id="editor"> +<title>The Editor</title> + +<para> +&kapp; does not provide its own editor. Instead, it utilises KDE's KTextEditor infrastructure to embed the system's default editor. This means that any editor that supports the KTextEditor interface (e.g., &kate;, <application>KVim</application>) can be used with &kapp;. The editor is defined in KDE's control centre. +</para> +<para> +In any matter related to operating or configuring the editor, please refer to the manual of the editor itself. +</para> + +</sect2> + +<sect2 id="open-file"> +<title>Opening Files for Editing</title> + +<para> +Files are usually opened for editing as part of a project. However, &kapp; enables the user to edit an occasional file that is not related to the project, through the <menuchoice><guimenu>File</guimenu><guimenuitem>Open...</guimenuitem></menuchoice> menu command. Note, however, that query results on files outside a project are meaningless. +</para> + +<para> +Once a project has been opened, the list of all project files appears in the file list, to the right of the editing area. Each file entry in the list shows the file's type, its name, and its full path. Files are opened by either double-clicking their entry in the list, or by selecting the entry, and hitting the <keycap>Enter</keycap> key. The edit-box above the list can be used to quickly search for a file. Typing in this box selects the first list entry whose file name begins with the entered text. +</para> + +<para> +Files can also be opened through the file tree, which shares its location with the project's file list (using a tabbed-window.) The file tree displays all files in the system, starting with a specific root directory. A root directory for the file tree is set on a per-project basis by using the <guibutton>Set Root...</guibutton> button. The file tree also sports a <guibutton>Find File...</guibutton> button for launching the file search <application>Cscope</application> query. +</para> + +<note> +<para> +To decrease the loading time of projects, files and directories are only added to the tree when their parent directory is expanded. Therefore directories will not be marked as expandable by default, even if they are not empty. +</para> +</note> + +<para> +For each file opened, &kapp; creates a separate editor window, inside the editing area. Each editor is associated with a tab, displaying the name of the edited file. Thus &kapp; provides a convenient multi-editor environment. You can switch between open files by selecting their respective tabs, or by using the <guimenu>Window</guimenu> menu. +</para> + +<para> +To work on a new file, the user first needs to create it using the <menuchoice><guimenu>File</guimenu><guimenuitem>New...</guimenuitem></menuchoice> menu command. This opens an empty editor, that is not associated with a file name or path. Upon saving the work in this new editor, &kapp; will prompt the user for a file name and directory. Note that this does not add the file to the project. The user still needs to invoke the <guilabel>Project Files</guilabel> dialogue and add the new file to an open project. +</para> + +</sect2> + +<sect2 id="file-tags"> +<title>File Tags</title> + +<para> +In addition to being a front-end to <application>Cscope</application>, &kapp; also uses <application>Ctags</application> to display a list of symbols defined in the current file. Each editor window is added a list of these symbols to its left. This list displays the name of a symbol, its type (as a graphic shape), and the line where it is defined. Double-clicking a symbol, or selecting it and hitting the <keycap>Enter</keycap> key, sets the cursor to the beginning of this symbol's definition line. The list of symbols is refreshed whenever a file is saved. +</para> + +<para> +The edit-box above the list of symbols can be used for quick symbol look-ups. Entering text in this box selects the first symbol whose name begins with this text. +</para> + +<para> +By default, tags are sorted by to their name in ascending order. Click on a column header to sort the tags according to that column. A triangle to the side of a column name indicates this is the sorting column, and shows the sorting order (ascending or descending.) Once a sorting order is chosen, it becomes the default, and is used for all newly created lists (though not for currently open, unmodified, editor windows.) +</para> + +</sect2> + +<sect2 id="files-other"> +<title>Other File Options</title> + +<para> +&kapp;'s <guimenu>File</guimenu> menu includes further options, such as saving, printing and closing files. In addition, specific editors can offer extended features under the <guimenu>Tools</guimenu> menu (e.g., syntax highlighting, indentation, etc.) +</para> + +</sect2> + +<sect2 id="symbol-completion"> +<title>Symbol Completion</title> + +<para> +Symbol completion is a convenient feature that enables the user to enter previously declared symbols with fewer key strokes. Since the cross-reference database keeps record of all globally declared symbols, it can be queried for a complete symbol name based on a given prefix. + +There are two types of symbol completion: manual and automatic. Manual symbol completion is always available, and can be invoked by the <menuchoice><guimenu>Edit</guimenu><guimenuitem>Complete Symbol</guimenuitem></menuchoice> menu command (or, more conveniently, by pressing <keycombo><keycap>Ctrl</keycap><keycap>Space</keycap></keycombo>). Once a completion request has been issued, &kapp; uses the characters immediately preceding the current cursor position as a prefix, and queries the database for possible completions. These completions are displayed in a list box, which can be browsed using the arrow keys. Pressing <keycap>Enter</keycap> replaces the prefix with the selected symbol. The <keycap>Esc</keycap> key hides the list without completing the symbol. +</para> + +<sect3 id="auto-symbol-completion"> +<title>Automatic Symbol Completion</title> + +<para> +In addition to manual symbol completion, &kapp; can also provide automatic completion based on changes made by the user to the edited source code. Specifically, &kapp; tracks changes to the edited file, and if certain criteria are met, initiates a symbol completion query to the cross-reference database. Once a completion list is displayed, symbol completion behaves in the same way as in the manual case. +</para> + +<para> +Automatic symbol completion is configured on a per-project basis. This feature is enabled or disabled via the <guilabel>Use Symbol Auto-Completion</guilabel> check-box in the <guilabel>New Project</guilabel> dialogue (this option can also be changed after a project has been created by invoking the <guilabel>Project Properties</guilabel> dialogue). +</para> + +<note> +<para> +For performance reasons, it is highly recommended that automatic symbol completion will be used in conjunction with the inverted-index option. +</para> +</note> + +<para> +As mentioned above, &kapp; uses several parameters to decide whether automatic symbol completion should be initiated. These parameters can be configured by clicking on the <guibutton>Options...</guibutton> button in the <guilabel>New Project</guilabel> dialogue (or, later, in the <guilabel>Project Properties</guilabel> dialogue). Clicking this button invokes the <guilabel>Auto-Completion Properties</guilabel> dialogue. + +<screenshot> +<screeninfo>The auto-completion properties dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="autocomp_dlg.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The auto-completion properties dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Minimum Characters</guilabel></term> +<listitem><para>The minimal length of a symbol for which completion is provided.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Delay (ms)</guibutton></term> +<listitem><para>Specifies a time interval that should elapse after the last change to the edited text and before the symbol completion query is executed.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Maximum Entries</guilabel></term> +<listitem><para>The symbol completion list will display at most this number of possible completions. If the number of matched symbols in the database is greater, a message will be displayed (and no symbols will be available).</para></listitem> +</varlistentry> +</variablelist> +</para> + +<para> +The main purpose of these parameters is to reduce the load on the system caused by frequent queries to the database. The default values have been tested in various scenarios, and are usually adequate. +</para> + +</sect3> + +</sect2> + +</sect1> diff --git a/doc/en/index.docbook b/doc/en/index.docbook new file mode 100644 index 0000000..705988d --- /dev/null +++ b/doc/en/index.docbook @@ -0,0 +1,174 @@ +<?xml version="1.0" ?> +<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.0//EN" "dtd/kdex.dtd" [ + <!ENTITY kscope '<application>KScope</application>'> + <!ENTITY kapp "&kscope;"><!-- replace kscope here --> + <!ENTITY about SYSTEM "about.docbook"> + <!ENTITY quick-start SYSTEM "quick_start.docbook"> + <!ENTITY main-window SYSTEM "main_window.docbook"> + <!ENTITY projects SYSTEM "projects.docbook"> + <!ENTITY editing SYSTEM "editing.docbook"> + <!ENTITY query-system SYSTEM "query_system.docbook"> + <!ENTITY position-history SYSTEM "pos_history.docbook"> + <!ENTITY bookmarks SYSTEM "bookmarks.docbook"> + <!ENTITY config-dlg SYSTEM "config_dlg.docbook"> + <!ENTITY main-menu SYSTEM "main_menu.docbook"> + <!ENTITY % addindex "IGNORE"> + <!ENTITY % English "INCLUDE"><!-- change language only here --> + + + <!-- Do not define any other entities; instead, use the entities + from kde-genent.entities and $LANG/user.entities. --> +]> + +<!-- The language must NOT be changed here. --> + +<book lang="&language;"> + +<!-- This header contains all of the meta-information for the document such +as Authors, publish date, the abstract, and Keywords --> + +<bookinfo> +<title>The &kapp; Handbook</title> + +<authorgroup> +<author> +<firstname>Elad</firstname> +<othername></othername> +<surname>Lahav</surname> +<affiliation> +<address><email>elad_lahav@users.sourceforge.net</email></address> +</affiliation> +</author> +</authorgroup> + +<!-- TRANS:ROLES_OF_TRANSLATORS --> + +<copyright> +<year>2003-2007</year> +<holder>Elad Lahav</holder> +</copyright> +<!-- Translators: put here the copyright notice of the translation --> +<!-- Put here the FDL notice. Read the explanation in fdl-notice.docbook + and in the FDL itself on how to use it. --> +<legalnotice>&FDLNotice;</legalnotice> + +<!-- Date and version information of the documentation +Don't forget to include this last date and this last revision number, we +need them for translation coordination ! +Please respect the format of the date (DD/MM/YYYY) and of the version +(V.MM.LL), it could be used by automation scripts. +Do NOT change these in the translation. --> + +<date>08/07/2007</date> +<releaseinfo>1.6.0</releaseinfo> + +<!-- Abstract about this handbook --> + +<abstract> +<para> +&kapp; is a source-editing environment for KDE, based on <application>Cscope</application>. +</para> +</abstract> + +<!-- This is a set of Keywords for indexing by search engines. +Please at least include KDE, the KDE package it is in, the name + of your application, and a few relevant keywords. --> + +<keywordset> +<keyword>KDE</keyword> +<keyword>KScope</keyword> +<keyword>Cscope</keyword> +<keyword>source</keyword> +<keyword>editor</keyword> +<keyword>browser</keyword> +</keywordset> + +</bookinfo> + +<!-- The contents of the documentation begin here. Label +each chapter so with the id attribute. This is necessary for two reasons: it +allows you to easily reference the chapter from other chapters of your +document, and if there is no ID, the name of the generated HTML files will vary +from time to time making it hard to manage for maintainers and for the CVS +system. Any chapter labelled (OPTIONAL) may be left out at the author's +discretion. Other chapters should not be left out in order to maintain a +consistent documentation style across all KDE apps. --> + +<chapter id="introduction"> +<title>Introduction</title> + +&about; +&quick-start; + +</chapter> + +<chapter id="using-kscope"> +<title>Using &kapp;</title> + +&main-window; +&projects; +&editing; +&query-system; +&position-history; +&bookmarks; + +</chapter> + +<chapter id="configuration"> +<title>Configuring &kapp;</title> + +&config-dlg; + +</chapter> + +<chapter id="commands"> +<title>Command Reference</title> + +&main-menu; + +</chapter> + +<chapter id="credits"> + +<!-- Include credits for the programmers, documentation writers, and +contributors here. The license for your software should then be included below +the credits with a reference to the appropriate license file included in the KDE +distribution. --> + +<title>Credits and License</title> + +<para> +&kapp; +</para> +<para> +Programme copyright 2003-2007 Elad Lahav <email>elad_lahav@users.sourceforge.net</email> +</para> +<para> +I would like to thank: +<itemizedlist> +<listitem><para>The <ulink url="http://www.kde.org">KDE</ulink> team</para></listitem> +<listitem><para>The <ulink url="http://www.kdevelop.org">KDevelop</ulink> team</para></listitem> +<listitem><para>Hans-Bernhard Broker, who maintains <ulink url="http://cscope.sourceforge.net">Cscope</ulink></para></listitem> +</itemizedlist> +</para> + +<para> +Documentation copyright 2007-2006 Elad Lahav <email>elad_lahav@users.sourceforge.net</email> +</para> + +<!-- TRANS:CREDIT_FOR_TRANSLATORS --> + +&underFDL; <!-- FDL: do not remove. Commercial development should --> +<!-- replace this with their copyright and either remove it or re-set this.--> + +<!-- Determine which license your application is licensed under, + and delete all the remaining licenses below: + + (NOTE: All documentation are licensed under the FDL, + regardless of what license the application uses) --> + +&underBSDLicense; <!-- BSD License --> + +</chapter> + +</book> diff --git a/doc/en/main_menu.docbook b/doc/en/main_menu.docbook new file mode 100644 index 0000000..18a4d2b --- /dev/null +++ b/doc/en/main_menu.docbook @@ -0,0 +1,465 @@ +<sect1 id="mainmenu"> +<title>&kapp;'s Main Menu</title> + +<para> +This section describes the menu entries declared by &kapp; only. Additional entries may be added to the main menu by the embedded editor (e.g., <guimenu>Edit</guimenu>, <guimenu>View</guimenu> or <guimenu>Tools</guimenu>.) Please refer to the editor's manual for a description of the commands under these sub-menus. +</para> + +<sect2> +<title>The File Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>N</keycap></keycombo> +</shortcut> +<guimenu>File</guimenu> +<guimenuitem>New</guimenuitem> +</menuchoice></term> +<listitem><para><action>Opens an empty editor window.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>O</keycap></keycombo> +</shortcut> +<guimenu>File</guimenu> +<guimenuitem>Open...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Opens a file for editing.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>W</keycap></keycombo> +</shortcut> +<guimenu>File</guimenu> +<guimenuitem>Close</guimenuitem> +</menuchoice></term> +<listitem><para><action>Closes the active editor window</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>Q</keycap></keycombo> +</shortcut> +<guimenu>File</guimenu> +<guimenuitem>Quit</guimenuitem> +</menuchoice></term> +<listitem><para><action>Quits</action> &kapp;</para></listitem> +</varlistentry> +</variablelist> +</para> +<para> +Other file operations such as <guimenuitem>Save</guimenuitem> and <guimenuitem>Print</guimenuitem> are not integral &kapp; actions, but are rather defined by the type of editor used. +</para> + +</sect2> + +<sect2> +<title>The Edit Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>E</keycap></keycombo> +</shortcut> +<guimenu>Edit</guimenu> +<guimenuitem>Edit in External Editor</guimenuitem> +</menuchoice></term> +<listitem><para><action>Launches an editor application for the current file and line number</action> </para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap><keycap>T</keycap></keycombo> +</shortcut> +<guimenu>Edit</guimenu> +<guimenuitem>Go To Tag</guimenuitem> +</menuchoice></term> +<listitem><para><action>Moves the cursor to the tag list</action>, used for browsing through the file's tags</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>Space</keycap></keycombo> +</shortcut> +<guimenu>Edit</guimenu> +<guimenuitem>Complete Symbol</guimenuitem> +</menuchoice></term> +<listitem><para><action>Generates a list of possible symbol completions for the text to the left of the cursor.</action> Note that this option is available even if automatic completion is disabled.</para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +<sect2> +<title>The View Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>/</keycap></keycombo> +</shortcut> +<guimenu>View</guimenu> +<guimenuitem>Toggle File List</guimenuitem> +</menuchoice></term> +<listitem><para><action>Shows or hides the project's file list window.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>.</keycap></keycombo> +</shortcut> +<guimenu>View</guimenu> +<guimenuitem>Toggle Query Window</guimenuitem> +</menuchoice></term> +<listitem><para><action>Shows or hides the query window.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>.</keycap></keycombo> +</shortcut> +<guimenu>View</guimenu> +<guimenuitem>Toggle Tag List</guimenuitem> +</menuchoice></term> +<listitem><para><action>Shows or hides the tag lists attached to the editor windows.</action></para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +<sect2> +<title>The Project Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>New...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the New Project dialogue box.</action>Use this dialogue to create a new project.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>Open...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Open Project dialogue box</action>, which lets you search for an existing project to open.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>Open Cscope.out...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Prompts for an existing Cscope.out</action>, which can be opened as a temporary project.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>Add/Remove Files...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Project Files dialogue box</action>, which allows you to add source files to the current project, or remove files from it.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>Properties...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Project Properties dialogue box.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>M</keycap></keycombo> +</shortcut> +<guimenu>Project</guimenu> +<guimenuitem>Make Project...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Build dialogue.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap><keycap>M</keycap></keycombo> +</shortcut> +<guimenu>Project</guimenu> +<guimenuitem>Remake Project</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Build dialogue and executes the last build command.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Project</guimenu> +<guimenuitem>Close</guimenuitem> +</menuchoice></term> +<listitem><para><action>Closes the active project</action>, along with all open editor windows.</para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +<sect2> +<title>The Cscope Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenu>Cscope</guimenu> +<guimenuitem>Rebuild Database</guimenuitem> +</menuchoice></term> +<listitem><para><action>Updates the cross-reference database for the current project</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>0</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>References...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all references to a given symbol</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>1</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Definition...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds the global definition of a symbol</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>2</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Called Functions...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all functions called by a given function</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>3</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Calling Functions...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all functions calling a given function</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>4</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Find Text...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all occurrences of a text string</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>5</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Find EGrep Pattern...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all text strings matching a regular expression</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>8</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Find Including Files...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds all files #including a given file</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>]</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Quick Definition</guimenuitem> +</menuchoice></term> +<listitem><para><action>Finds the global definition of the symbol currently under the cursor.</action> The symbol dialogue appears only if a symbol cannot be determined automatically.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>\</keycap></keycombo> +</shortcut> +<guimenu>Cscope</guimenu> +<guimenuitem>Call Graph...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays a call-graph and/or a call-tree for a given function</action></para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +<sect2> +<title>The Go Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Up Arrow</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Previous Result</guimenuitem> +</menuchoice></term> +<listitem><para><action>Selects the previous result in the current query window.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Down Arrow</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Next Result</guimenuitem> +</menuchoice></term> +<listitem><para><action>Selects the next result in the current query window.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Left Arrow</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Previous Position</guimenuitem> +</menuchoice></term> +<listitem><para><action>Jumps to the previous stored position in the active history list.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Right Arrow</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Next Position</guimenuitem> +</menuchoice></term> +<listitem><para><action>Jumps to the next stored position in the active history list.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>H</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Position History...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Selects the active position history page in the query window.</action> If the query window is hidden, it becomes visible. </para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap><keycap>G</keycap></keycombo> +</shortcut> +<guimenu>Go</guimenu> +<guimenuitem>Global Bookmarks...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Bookmarks dialogue.</action></para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect2> + +<sect2> +<title>The Window Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenu>Window</guimenu> +<guimenuitem>Close All</guimenuitem> +</menuchoice></term> +<listitem><para><action>Closes all open editor windows</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Shift</keycap><keycap>Left Arrow</keycap></keycombo> +</shortcut> +<guimenu>Window</guimenu> +<guimenuitem>Go Left</guimenuitem> +</menuchoice></term> +<listitem><para><action>Selects the editor window to the left of the current one.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<shortcut> +<keycombo><keycap>Alt</keycap><keycap>Shift</keycap><keycap>Right Arrow</keycap></keycombo> +</shortcut> +<guimenu>Window</guimenu> +<guimenuitem>Go Right</guimenuitem> +</menuchoice></term> +<listitem><para><action>Selects the editor window to the right of the current one.</action></para></listitem> +</varlistentry> +</variablelist> +</para> +<para> +This menu displays the full path of each file edited in an open window. Clicking a +file name will make its editor window active. +</para> + +</sect2> + +<sect2> +<title>The Settings Menu</title> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenu>Settings</guimenu> +<guisubmenu>Toolbars</guisubmenu> +</menuchoice></term> +<listitem><para><action>Toggles the different toolbars.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Settings</guimenu> +<guimenuitem>Configure Shortcuts...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Allows the user to assign different shortcuts to &kapp; commands.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Settings</guimenu> +<guimenuitem>Configure KScope...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the &kapp; configuration dialogue</action></para></listitem> +</varlistentry> +</variablelist> +</para> +<para> +A menu item to configure the embedded editor may also appear under this menu. +</para> + +</sect2> + +</sect1> diff --git a/doc/en/main_window.docbook b/doc/en/main_window.docbook new file mode 100644 index 0000000..ada3fd8 --- /dev/null +++ b/doc/en/main_window.docbook @@ -0,0 +1,24 @@ +<sect1 id="main-window"> +<title>The Main Window</title> + +<para> +&kapp;'s main window is divided into three. The central area is dedicated to source editing, and holds a set of editor windows, one for each source file being viewed or edited. This area is greyed-out if no files are open for editing. The window to the right is the file browser, comprised of a list of project files, and a tree-like view of the file system. The project file list will only display files after a project has been created and source files have been added to it. The bottom area contains the query windows, which hold the results of <application>Cscope</application> queries, and the history pages that display locations in the source code visited by the user. +</para> +<screenshot> +<screeninfo>The Main Window</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="main_window.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>&kapp;'s main window</phrase> +</textobject> +</mediaobject> +</screenshot> +<para> +The size of each of these sub-windows can be changed to meet the user's personal preferences. This is done by dragging the lines that separate one area from the other. The new sizes will be kept and used on the next sessions as well. +</para> +<para> +The file browser and the query window can be hidden in order to free up desktop space (especially on low resolution displays). Hiding and showing these windows is done through the <guimenu>View</guimenu> menu. A window can also be hidden by clicking on its close button, at the upper right corner. As with window sizes, the visibility status will be saved when &kapp; is closed. +</para> +</sect1> diff --git a/doc/en/main_window.png b/doc/en/main_window.png Binary files differnew file mode 100644 index 0000000..b5842af --- /dev/null +++ b/doc/en/main_window.png diff --git a/doc/en/pos_history.docbook b/doc/en/pos_history.docbook new file mode 100644 index 0000000..7bd6f74 --- /dev/null +++ b/doc/en/pos_history.docbook @@ -0,0 +1,101 @@ +<sect1 id="position-history"> +<title>Position History</title> + +<sect2 id="pos-hist-intro"> +<title>Introduction</title> + +<para> +In its capacity as a source code browser, &kapp; allows the user to quickly browse through different lines in the code base. We refer to a combination of a source file and a line number as a "position" in the project. While browsing the code, it is often required to go back to a position visited in the past, e.g., to return to the caller after visiting the callee. To achieve this task, &kapp; provides a sophisticated position history mechanism, which not only allows the user to go back and forth between visited locations, but also to save and restore snapshots of "tours" through the code, as well as other manipulations of the position history. For the sake of both consistency and ease of use, recorded position history is viewed and handled in a way similar to the query results system. +</para> + +<note> +<para> +In the context of this section, a "jump" is defined as the action taken by &kapp; after a query result record is selected for viewing (either by the user from a query page or a call-tree window, or automatically). +</para> +</note> + +<para> +Position history records appear in pages incorporated into the Query Results window. These pages can be immediately distinguished from query results by their tab labels, which always read "History X" (where X is a unique number that identifies the page). Other than that the two types of pages look very much the same: a history page is composed of a list of records, each comprised of the following fields: +<itemizedlist> +<listitem><para>File</para></listitem> +<listitem><para>Line</para></listitem> +<listitem><para>Text</para></listitem> +</itemizedlist> +</para> + +<para> +Note that the "Function" field is not provided for position history records. +</para> + +<para> +A history page behaves like a stack: entries are always added at the top of the list, and represent the most recently visited positions. The user can then go backwards in time, by moving the lower records, or forward, by moving to upper records. If the current record in the list is not the top one, all records above it are removed before new records are added at the top (the future history is thus "forgotten"). +</para> + +<para> +At any given moment, at most one history page is considered as "active". This is the page to which history position records are added as the user browses through the code, and to which position navigation commands apply. See <link linkend="pos-hist-multi">Using Multiple Histories</link> for a detailed description of the active page concept. +</para> + +<para> +A newly created project contains no position history pages. An initial page is created and set as active automatically when the first jump is made to a location in the code. +</para> + +<para> +Each jump may add up to two entries to the active history list: +<orderedlist> +<listitem><para>The current position of the cursor (before the cursor jumps to the requested position), and</para></listitem> +<listitem><para>The new position of the cursor.</para></listitem> +</orderedlist> +Duplicates never occur in the list. If the location of the cursor is the same as the location that appears at the top of the history list, only the new position of the cursor will be added. +</para> + +</sect2> + +<sect2 id="pos-hist-nav"> +<title>Navigation</title> + +<para> +The key feature of the position history mechanism is the ability to navigate through the recorded locations in the source code. There are two ways to navigate through a history list: moving back and forth through the list, and jumping directly to a specific position. +</para> + +<para> +To go back to the last position visited, select the <menuchoice><guimenu>Go</guimenu><guimenuitem>Previous Position</guimenuitem></menuchoice> menu item. This command selects the item immediately below the current one in the active history list (and moves the cursor to that position). Similarly, the menu command <menuchoice><guimenu>Go</guimenu><guimenuitem>Next Position</guimenuitem></menuchoice> selects the position record immediately above the current one in the active history page, and moves the editing cursor to the appropriate location. +</para> + +<para> +In addition to these commands, any position recorded in a history list can be accessed directly, by selecting the relevant item in the list (either by double-clicking the item, or by highlighting it and pressing the <keycap>Enter</keycap> key. This action can be applied to any history list, and not just to the active one. +</para> + +<note> +<para> +Selecting a history record from a non-active list will add the selected item to the top of the active list, similar to a jump from a query result page. +</para> +</note> + +</sect2> + +<sect2 id="pos-hist-multi"> +<title>Using Multiple Histories</title> + +<para> +The position history is a dynamic object, which changes as the user navigates through the code. In some cases, however, it is convenient to create a snapshot of a tour through the code, and keep it for later reference. &kapp; provides this feature through the availability of multiple history pages. +</para> + +<para> +As mentioned earlier, a history page is created automatically for a project when the first jump through the code is made. This page is considered as the active history page, which means that locations are added to this page, and that all navigational commands apply to the list contained in it. +</para> + +<para> +The user can decide to freeze the contents of the history recorded by the current page. This is done by locking the page, in a way similar to locking query results (see <link linkend="query-window">The Query Window</link>). Once the page is locked, its contents remain the same, even if jumps are made to other locations in the code. To record any successive jumps, &kapp; creates a new history page, which becomes the active one. A locked history page can also be activated by unlocking it. However, there can only be one unlocked history page at any given time (the active one), which means that unlocking one history page locks the previously unlocked one. +</para> + +<para> +Navigational commands (<menuchoice><guimenu>Go</guimenu><guimenuitem>Next Position</guimenuitem></menuchoice> and <menuchoice><guimenu>Go</guimenu><guimenuitem>Previous Position</guimenuitem></menuchoice>) always apply to the active history page. This is usually the unlocked history page, but may also be a locked one. This happens after the active page is locked, and before a new page is created due to a jump in the code. Other locked pages can still be used by manually selecting location records from these pages. Such a selection will move the editing cursor to the appropriate location, and hence add an entry in the active history page. +</para> + +<para> +As with query pages, locked history pages are saved when a project is closed, and restored when it is opened. +</para> + +</sect2> + +</sect1> diff --git a/doc/en/pref_clrs.png b/doc/en/pref_clrs.png Binary files differnew file mode 100644 index 0000000..31e2f24 --- /dev/null +++ b/doc/en/pref_clrs.png diff --git a/doc/en/pref_fonts.png b/doc/en/pref_fonts.png Binary files differnew file mode 100644 index 0000000..c2272d3 --- /dev/null +++ b/doc/en/pref_fonts.png diff --git a/doc/en/pref_opts.png b/doc/en/pref_opts.png Binary files differnew file mode 100644 index 0000000..8dcf3c9 --- /dev/null +++ b/doc/en/pref_opts.png diff --git a/doc/en/pref_progs.png b/doc/en/pref_progs.png Binary files differnew file mode 100644 index 0000000..7ea262a --- /dev/null +++ b/doc/en/pref_progs.png diff --git a/doc/en/project_details.png b/doc/en/project_details.png Binary files differnew file mode 100644 index 0000000..33d60cd --- /dev/null +++ b/doc/en/project_details.png diff --git a/doc/en/project_files.png b/doc/en/project_files.png Binary files differnew file mode 100644 index 0000000..94fdb32 --- /dev/null +++ b/doc/en/project_files.png diff --git a/doc/en/project_make.png b/doc/en/project_make.png Binary files differnew file mode 100644 index 0000000..1db4500 --- /dev/null +++ b/doc/en/project_make.png diff --git a/doc/en/project_open.png b/doc/en/project_open.png Binary files differnew file mode 100644 index 0000000..e6f26f8 --- /dev/null +++ b/doc/en/project_open.png diff --git a/doc/en/project_opts.png b/doc/en/project_opts.png Binary files differnew file mode 100644 index 0000000..9500b67 --- /dev/null +++ b/doc/en/project_opts.png diff --git a/doc/en/project_types.png b/doc/en/project_types.png Binary files differnew file mode 100644 index 0000000..8998f03 --- /dev/null +++ b/doc/en/project_types.png diff --git a/doc/en/projects.docbook b/doc/en/projects.docbook new file mode 100644 index 0000000..c39e3aa --- /dev/null +++ b/doc/en/projects.docbook @@ -0,0 +1,394 @@ +<sect1 id="projects"> +<title>Working with Projects</title> + +<para> +Before any significant work can be done with &kapp;, the user needs to define a project. A &kapp; project is a set of source files, which <application>Cscope</application> uses to create its cross-reference database. Unlike many other project-based environments, &kapp; is not intrusive: it only uses three files to define the project (with additional two files if the inverted index option is used). These files reside on a user-specified folder that does not have to be related to the location of the source files. Thus, &kapp; does not require any source files to be moved, and does not affect the structure of the source tree. +</para> +<para> +The files used by a &kapp; project are: +<variablelist> +<varlistentry> +<term><filename>cscope.proj</filename></term> +<listitem><para>The project's configuration file</para></listitem> +</varlistentry> +<varlistentry> +<term><filename>cscope.files</filename></term> +<listitem><para>A list of all source files included in the project</para></listitem> +</varlistentry> +<varlistentry> +<term><filename>cscope.out</filename></term> +<listitem><para><application>Cscope</application>'s cross-reference database</para></listitem> +</varlistentry> +<varlistentry> +<term><filename>cscope.in.out</filename></term> +<listitem><para>An inverted index file (optional)</para></listitem> +</varlistentry> +<varlistentry> +<term><filename>cscope.po.out</filename></term> +<listitem><para>An inverted index file (optional)</para></listitem> +</varlistentry> +</variablelist> +</para> + +<para> +The only limitation imposed by &kapp; is that these files have to reside in the same directory, referred to as the project's directory. The project's directory has the same name as the project (which means that project names should conform to the file-system conventions), and can be placed by the user under any directory. Normally, a user will create a <filename>projects</filename> sub-directory under his or her home directory, and create all projects there. However, this is only a convention, and, as explained above, the user can choose any other method he or she prefers. Furthermore, the project's directory can later be moved to another parent directory, without any risk of data loss. +</para> + +<sect2 id="project-create"> +<title>Creating a New Project</title> + +<para> +The first step in working with projects is to create a new one. This is done by choosing the <menuchoice><guimenu>Projects</guimenu><guimenuitem>New...</guimenuitem></menuchoice> command from the main menu. Issuing this command opens the <guilabel>New Project</guilabel> dialogue. The dialogue consists of three pages: <guilabel>Details</guilabel>, <guilabel>File Types</guilabel> and <guilabel>Options</guilabel>. +</para> +<para> +Note that this dialogue is intended for creating an empty project only, and has nothing to do with the actual source files of the project. This task is left to the <guilabel>Project Files</guilabel> dialogue. +</para> + +<sect3> +<title>Details</title> + +<screenshot> +<screeninfo>The Project Details page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_details.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Project Details page</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Name</guilabel></term> +<listitem><para>The name of the project. Note that this name will be given to the project's directory, and should therefore comply with the file-system convention for directory names (e.g., no spaces).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Path</guilabel></term> +<listitem><para>The full path of the directory under which the new project will be created. &kapp; will create a new directory under this one, and name it after the project. Thus this path does not need to point directly to the project's directory, but rather to the project's parent directory. For example, if a user wants to create a project called "my_project" under his local <filename>projects</filename> directory, the project's name should be set to "my_project" and the path to <filename>/home/my_username/projects</filename>. This will set the project's directory to <filename>/home/my_username/projects/my_project</filename>.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Source Root (Optional)</guilabel></term> +<listitem><para>The top-level directory that contains the source files to be included in the project. This path only serves as a hint to &kapp;, as files may later be added from different directories as well By default, this value is set to the root directory.</para></listitem> +</varlistentry> +</variablelist> +</sect3> + +<sect3> +<title>File Types</title> + +<screenshot> +<screeninfo>The File Types page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_types.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The File Types page</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>This Project</guilabel></term> +<listitem><para>A list of file name patterns that are used to define the type of source files to be included in the project. By default, C source files (<filename>.c</filename>) and C header files (<filename>.h</filename>) are included, but other types (including Lex's <filename>.l</filename> files and Yacc's <filename>.y</filename> files) can be added.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Available Types</guilabel></term> +<listitem><para>A list of standard file types that can be included in a project. To add a type, highlight its entry in the list, and click the <guibutton>Add</guibutton> button. Custom types can also be added, by typing in shell-style patterns in the edit-box at the top of the list.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Add</guibutton></term> +<listitem><para><action>Adds the currently selected file type to the project.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Remove</guibutton></term> +<listitem><para><action>Removes the currently selected file types from the project.</action> The file type is added to the list of available types.</para></listitem> +</varlistentry> +</variablelist> +</sect3> + +<sect3> +<title>Options</title> + +<screenshot> +<screeninfo>The Project Options page</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_opts.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Project Options page</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Kernel project</guilabel></term> +<listitem><para>Mark this check-box if the project is designated to be a kernel-style project. For kernel projects, <application>Cscope</application> ignores the system's include files when building the cross-reference database (i.e., <symbol>printf</symbol> will not be found in <filename>/usr/include/stdio.h</filename>).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Build inverted index</guilabel></term> +<listitem><para><application>Cscope</application> can build an inverted index for the project to speed up queries (though at the expense of more time spent on building and refreshing the database).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Do not compress the database</guilabel></term> +<listitem><para>Builds cross-reference database without compression. This will create a larger, but human-readable database.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Slower, but more accurate, function definition detection</guilabel></term> +<listitem><para>Applies a huristic that can overcome <application>Cscope</application>'s inability to detect function declarations with function pointers as parameters. Requires a patch to <application>Cscope</application>.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Refresh database automatically</guilabel></term> +<listitem><para>&kapp; can rebuild the cross-reference database automatically, a process which is triggered when a source file is saved. If this option is selected, the user needs to specify the time (in seconds) that should elapse after each file save operation and before the database is rebuilt.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Use symbol auto-completion</guilabel></term> +<listitem><para>Enables automatic "as-you-type" symbol completion. Note that manual symbol completion is always available, regardless of whether this option is selected.</para> +<note><para>If you choose to enable this option, it is recommended that you also select the inverted index option.</para></note></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Options...</guibutton></term> +<listitem><para><action>Displays the symbol auto-completion configuration dialogue.</action> This button is only enabled if the symbol auto-completion is selected (see <link linkend="auto-symbol-completion">Automatic Symbol Completion</link> for a description of this dialogue).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Override default tab width (Kate only)</guilabel></term> +<listitem><para>Use a per-project tab-width (overriding the editor's settings). Helps when browsing code bases that use different styles than the user's preferred one.</para></listitem> +</varlistentry> +</variablelist> +</sect3> + +<sect3> +<title>Common Buttons</title> +<variablelist> +<varlistentry> +<term><guibutton>OK</guibutton></term> +<listitem><para><action>Accepts the values entered in the dialogue, and creates a new project.</action> If any mandatory values were omitted, or not entered correctly, the user is prompted.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Cancel</guibutton></term> +<listitem><para><action>Closes the dialogue without creating a new project.</action></para></listitem> +</varlistentry> +</variablelist> +</sect3> +</sect2> + +<sect2 id="project-files"> +<title>Adding and Removing Project Files</title> + +<para> +The project's list of source files is maintained by the <guilabel>Project Files</guilabel> dialogue. This dialogue allows the user to add source files to a project, or remove files currently included in it. The dialogue is invoked automatically after a new project has been created, or manually by selecting the <menuchoice><guimenu>Project</guimenu><guimenuitem>Add/Remove Files...</guimenuitem></menuchoice> command from the main menu. +</para> + +<screenshot> +<screeninfo>The Project Files dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_files.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Project Files dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> + + +<variablelist> +<varlistentry> +<term><guilabel>File Path</guilabel></term> +<listitem><para>Displays a list of all source files included in the project. Note that when adding and removing files, the project itself is not modified until the <guibutton>OK</guibutton> button is clicked.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Filter</guibutton></term> +<listitem><para>Hides all files whose path names do not include the text entered in the edit-box to the left of the button. This can simplify the task of finding files in the project. The filter text can be any simplified regular expression (as given to file commands in a shell).</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Show All</guibutton></term> +<listitem><para>Reveals any files formerly hidden with the <guibutton>Filter</guibutton> button.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Add</guilabel></term> +<listitem><para>All buttons in this group add files to the current project.</para> +<variablelist> +<varlistentry> +<term><guibutton>Files...</guibutton></term> +<listitem><para><action>Adds user-selected files to the current project.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Directory...</guibutton></term> +<listitem><para><action>Adds all source files in a directory to the current project.</action> Source files are scanned according to the file-types associated with the project. Note that sub-directories are not scanned for files.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Tree...</guibutton></term> +<listitem><para><action>Adds all source files in a selected directory and its sub-directories to the current project.</action> Source files are scanned according to the file-types associated with the project.</para></listitem> +</varlistentry> +</variablelist> +</listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Remove</guilabel></term> +<listitem><para>All buttons in this group remove files from the current project.</para> +<variablelist> +<varlistentry> +<term><guibutton>Selected</guibutton></term> +<listitem><para><action>Removes all selected files from the current project.</action> Files can be selected for removal by clicking their path name in the file list. The <keycap>Ctrl</keycap> key can be used to select multiple files, and the <keycap>Shift</keycap> key can be used to select ranges of files.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Directory...</guibutton></term> +<listitem><para><action>Removes all source files in a directory from the current project.</action> Note that sub-directories are not included.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Tree...</guibutton></term> +<listitem><para><action>Removes all source files in a directory and any of its sub-directories from the current project.</action></para></listitem> +</varlistentry> +</variablelist> +</listitem> +</varlistentry> +<varlistentry> +<term><guibutton>OK</guibutton></term> +<listitem><para><action>Accepts the new list of source files, and updates the project.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Cancel</guibutton></term> +<listitem><para><action>Closes the dialogue without modifying the list of project files.</action></para></listitem> +</varlistentry> +</variablelist> + + +<para> +Once the list of project files changes (either when files are first added to the project, or upon any subsequent modification), &kapp; informs <application>Cscope</application> to rebuild the cross-reference database. +</para> + +</sect2> + +<sect2 id="project-open"> +<title>Opening an Existing Project</title> + +<para> +Existing projects can be opened using the <menuchoice><guimenu>Project</guimenu><guimenuitem>Open...</guimenuitem></menuchoice> menu command. Choosing this command invokes the <guilabel>Open Project</guilabel> dialogue, which allows the user to select the project to open. +</para> + +<screenshot> +<screeninfo>The Open Project dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_open.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Open Project dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Project Path</guilabel></term> +<listitem><para>The full path of the project directory. Use the browser button to locate a project by its configuration file (<filename>cscope.proj</filename>).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Recent Projects</guilabel></term> +<listitem><para>Displays a list of recently-opened projects. Clicking a list item copies its path to the Project Path edit-box, while double-clicking an item opens the project.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Remove</guibutton></term> +<listitem><para><action>Removes an entry from the list of recently-opened projects.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Open</guibutton></term> +<listitem><para><action>Opens the project whose directory is set in the Project Path edit-box.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Cancel</guibutton></term> +<listitem><para><action>Closes the dialogue without opening a project.</action></para></listitem> +</varlistentry> +</variablelist> + +<para> +When a project is closed, it saves session information, such as source files being edited and the contents of locked queries. The session is restored when that project is opened again. +</para> + +<para> +After the project has been opened, &kapp; will invoke <application>Cscope</application>, which, in turn, will check whether any files have been modified since the last time the project had been closed. If any files have changed, <application>Cscope</application> will rebuild the cross-reference database. +</para> + +</sect2> + +<sect2 id="project-prop"> +<title>Changing Project Properties</title> + +<para> +The properties of an open project can be changed by choosing the <menuchoice><guimenu>Project</guimenu><guimenuitem>Properties...</guimenuitem></menuchoice> menu command. This command invokes the <guilabel>Project Properties</guilabel> dialogue, which is similar to the <guilabel>New Project</guilabel> dialogue, except that the name and path of the project cannot be changed. +</para> + +<para> +See the <link linkend="project-create">New Project dialogue</link> for a description of the available project options. +</para> + +</sect2> + +<sect2 id="projects-temp"> +<title>Temporary Projects</title> + +<para> +Temporary projects are created when a user opens a cscope.out file directly. This option is useful for working on projects created by some other <application>Cscope</application> front-end (<application>Cscope</application>'s ncurses interface, <application>Vi</application>, <application>>Emacs</application>, etc.), or simply using <application>Cscope</application>'s <option>-b</option> command-line parameter. +</para> + +<para> +To open a database file, use the <menuchoice><guimenu>Project</guimenu><guimenuitem>Open Cscope.out...</guimenuitem></menuchoice> menu command. If the file is a valid <application>Cscope</application> cross-reference database, &kapp; will invoke <application>Cscope</application> using this file, and will be ready to accept queries on the database. Cscope.out files can also be opened through the command line, which means that you can simply drag a Cscope.out file, and drop it over &kapp;'s programme icon. +</para> + +<para> +Note, however, that most project management options provided by &kapp; will not be available for temporary projects: the file list for the project will be empty, users will not be able to add or remove files, and the project properties dialogue will not be available. You will also need to rebuild the database manually when making any changes. &kapp;'s rebuild command assumes the database has been updated, and only re-runs <application>Cscope</application>. +</para> + +</sect2> + +<sect2 id="projects-build"> +<title>Building Projects</title> + +<para> +While &kapp; was not designed as an IDE with a complete write-build-debug cycle, it does provide a simple GUI for building projects. The command <menuchoice><guimenu>Project</guimenu><guimenuitem>Make Project</guimenuitem></menuchoice> displays a dialogue, which can be used to invoke any external tool on a given directory. By default, it runs <command>make</command> on the project's source root. The output of the command will be displayed in the dialogue's <guilabel>Output</guilabel> pane, with any errors or warnings marked-up, similar to links in a browser. Clicking on a link will jump to an editor page showing the source file and line responsible for the message. A list of all abnormal messages also appears in the dialogue's <guilabel>Errors and Warnings</guilabel> pane. +</para> + +<screenshot> +<screeninfo>The Make Project dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="project_make.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Make Project dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> + +<variablelist> +<varlistentry> +<term><guilabel>Root Directory</guilabel></term> +<listitem><para>The directory in which to run the build command.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Command</guilabel></term> +<listitem><para>The command to execute.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Make</guibutton></term> +<listitem><para><action>Executes the build command.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Stop</guibutton></term> +<listitem><para><action>Halts an executing build process.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Close</guibutton></term> +<listitem><para><action>Closes the dialogue.</action></para></listitem> +</varlistentry> +</variablelist> + +</sect2> + +</sect1> diff --git a/doc/en/query_dlg.png b/doc/en/query_dlg.png Binary files differnew file mode 100644 index 0000000..120ddb7 --- /dev/null +++ b/doc/en/query_dlg.png diff --git a/doc/en/query_filter.png b/doc/en/query_filter.png Binary files differnew file mode 100644 index 0000000..de3a69c --- /dev/null +++ b/doc/en/query_filter.png diff --git a/doc/en/query_system.docbook b/doc/en/query_system.docbook new file mode 100644 index 0000000..6f637cf --- /dev/null +++ b/doc/en/query_system.docbook @@ -0,0 +1,434 @@ + +<sect1 id="queries"> +<title>The Query System</title> + +<para> +The most important task of &kapp; is to execute <application>Cscope</application> queries and display their results. Queries are always performed on the cross-reference database of the active project. +</para> +<para> +&kapp; currently supports the following query types: +<itemizedlist> +<listitem><para>Find all references to a symbol</para></listitem> +<listitem><para>Find a symbol's global definition</para></listitem> +<listitem><para>Find all functions called by a given function</para></listitem> +<listitem><para>Find all functions calling a given function</para></listitem> +<listitem><para>Find a text string</para></listitem> +<listitem><para>Find an EGrep pattern (regular expression)</para></listitem> +<listitem><para>Find a file's path by its name</para></listitem> +<listitem><para>Find all files including a given file</para></listitem> +<listitem><para>Display a call-tree for a given function</para></listitem> +</itemizedlist> +A symbol, as referred to in the above list, may be a function, a global variable, a structure, a union or a type definition. +</para> + +<para> +The cross-reference database may become obsolete when source files are modified, resulting in inaccurate (or simply wrong) query results. &kapp; has two ways for refreshing the database, manual and automatic. Manual database rebuilds are available through the <menuchoice><guimenu>Cscope</guimenu><guimenuitem>Rebuild Database</guimenuitem></menuchoice> menu command. Selecting this command will instruct Cscope to immediately rebuild the cross-reference database. +</para> + +<para> +Automatic database rebuilds are enabled per-project, an option controlled by the <guilabel>Project Properties</guilabel> dialogue. Since a database rebuild may be a time and resource-consuming operation, &kapp; does not invoke this procedure after every change to the source code. Instead, changes to the code initiate a timer (whose value is determined by the user in the <guilabel>Project Properties</guilabel> dialogue). Once this timer elapses, &kapp; instructs Cscope to rebuild the database. Code modifications that occur while the timer is running reset its value. +</para> + +<para> +A project's database is also updated whenever that project is opened. +</para> + +<sect2 id="query-run"> +<title>Running a Query</title> + +<para> +A query can be started in one of three ways: +<orderedlist> +<listitem><para>The main menu</para></listitem> +<listitem><para>Keyboard shortcuts</para></listitem> +<listitem><para>The editor's context-menu</para></listitem> +</orderedlist> +</para> + +<para> +To start a query from the main menu, select the desired query type from the <guimenu>Cscope</guimenu> menu. This will display a dialogue box prompting you for the query's text. The text to enter depends upon the query's type. +<screenshot> +<screeninfo>The query dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="query_dlg.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The query dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> +</para> + +<variablelist> +<varlistentry> +<term><guilabel>Type</guilabel></term> +<listitem><para>The type of query to perform. This value defaults to the requested type, by can be changed by selecting a different entry in the list.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Symbol</guibutton></term> +<listitem><para>Enter the symbol to query in this box. The default value is the symbol currently under the editor's cursor (if any).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Search for a Sub-String</guilabel></term> +<listitem><para>Mark this check-box to treat the entered text as part of a symbol (will query all symbols containing the entered text as a sub-string).</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>OK</guibutton></term> +<listitem><para><action>Runs the query.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Hint</guibutton></term> +<listitem><para><action>Provides a list of possible matches to the entered symbol.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Cancel</guibutton></term> +<listitem><para><action>Closes the dialogue without running the query.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Suggested Symbols</guilabel></term> +<listitem><para>A list of known symbols matching the text in the symbol box.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Hint Options</guilabel></term> +<listitem><para>These buttons affect the way text in the symbol box is matched to fill the suggested symbols list.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Symbols Beginning With...</guilabel></term> +<listitem><para>Choose this option to match symbols starting with the given text.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Symbols Containing...</guilabel></term> +<listitem><para>Choose this option to match symbols containing the given text.</para></listitem> +</varlistentry> +</variablelist> + +<para> +Any text selected in the editor when a query is requested will be automatically copied to the query dialogue. If no text is selected, KScope attempts to guess the requested symbol from the current location of the cursor. +</para> + +<para> +Each menu item is associated with a keyboard shortcut. These shortcuts follow the convention of using the <keycap>Ctrl</keycap> key, together with the numeric query index used by <application>Cscope</application> (this should allow experienced <application>Cscope</application> users to get quickly acquainted with &kapp;). For example, use <keycombo><keycap>Ctrl</keycap><keycap>1</keycap></keycombo> to look-up a symbol's definition. The call-tree is an exception to this convention (as it is not a native <application>Cscope</application> query). See the <link linkend="commands">Command Reference</link> for a complete listing of all menu and shortcut options. +</para> + +<note> +<para> +The EGrep query is invoked using <keycombo><keycap>Ctrl</keycap><keycap>5</keycap></keycombo>, as <keycombo><keycap>Ctrl</keycap><keycap>6</keycap></keycombo> is already used by &kate;. +</para> +</note> + +<para> +The third way of starting a query is by right-clicking inside an editor window. This invokes the context-menu, that displays the same options as in the <guimenu>Cscope</guimenu> section of the main menu. Using a context-menu is easy when combined with a symbol selection in the editor: position the text cursor inside a symbol, and then right click to display the context-menu. +</para> + +<para> +A query may take some time to complete, depending on its type and the size of the project. &kapp; displays a progress indicator during long queries. If <application>Cscope</application>'s <option>-v</option> command line option is used, this progress indication is accurate, and displays the percentage of files already searched in. In case this option was omitted (e.g., if working with a version of <application>Cscope</application> prior to 15.5), &kapp; will present a dummy progress bar, used simply to indicate that a query is running, and that &kapp; has not frozen. Please refer to the section <link linkend="configuration">Configuring &kapp;</link> for more information. +</para> + +</sect2> + +<sect2 id="query-window"> +<title>The Query Results Window</title> + +<para> +When a query has terminated, its output is displayed in the query window, at the bottom of &kapp;'s main window. This window can manage several result pages simultaneously, with each page holding the results of a different query. Each page is associated with a tab that displays a summary of the query that generated these results. This tab is used to bring the results page forward, and is also associated with several page operations through a close button and a context menu. +</para> + +<para> +By default, query results are displayed in the currently active page, overriding any prior contents. To keep a results page unchanged, the page needs to be "locked". Locked query pages are never overridden. The contents of these pages are also saved when the project is closed, and are restored when the project is reopened. To lock a project, either click the <guibutton>Lock/Unlock Query</guibutton> toggle button to the right of the query window, or use the context menu (available by right-clicking the page's tab.) The same methods can also be used to unlock a query. +</para> + +<para> +New query pages can also be created explicitly, by using either the <guibutton>New Query</guibutton> button to the right of the query window, or the context menu available by right-clicking the tab area of the query window. +</para> + +<para> +Each entry in a query results page represents a symbol or text string that complies to the search criteria. The entry is composed of four sections: +<itemizedlist> +<listitem><para>The path of the file in which the symbol or string were found</para></listitem> +<listitem><para>The name of the function containing the symbol or text string</para></listitem> +<listitem><para>The line number in this file</para></listitem> +<listitem><para>The text of this line</para></listitem> +</itemizedlist> +</para> + +<para> +By default, results are sorted according to the file name. This can be changed by clicking the column headers of the results list. +</para> + +<para> +The entries in a query results page can be used as shortcuts to editing the line in which the symbol or text string were found (or lines in that vicinity.) This is done by either double-clicking a result entry, or by selecting this entry and hitting the <keycap>Enter</keycap> key. As a result, &kapp; will open an editor window displaying the file referred to in the selected entry, and set the cursor to the beginning of the appropriate line. +</para> + +<para> +If a query results in a single entry, this entry is automatically selected for display. +</para> + +<para> +The results of a query can be refreshed by clicking the <guibutton>Refresh Query</guibutton> button to the right of the query window, or by using the context menu. This command is useful to rerun queries after the database has changed (such as after a <guimenuitem>Rebuild Database</guimenuitem> command had been issued). +</para> + +<para> +Query results pages can be closed by either clicking the icon on their tab, by clicking on the <guibutton>Close Query</guibutton> button to the right of the query window, by using the context menu (available by right-clicking the page's tab), or by selecting the <menuchoice><guimenu>Cscope</guimenu><guimenuitem>Close Query</guimenuitem></menuchoice> main-menu command. +</para> + +<para> +If the query window is not visible when a query is executed, it is temporarily displayed, and then re-hidden when the user selects an entry for viewing. +</para> + +</sect2> + +<sect2 id="result-options"> +<title>Query Results Options</title> + +<para> +Right-clicking a query result in either a query window or a call-tree dialogue displays a context menu. This menu includes several actions that can be used to either extract information or fine tune these results. +</para> + +<para> +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenuitem>Copy File</guimenuitem> +</menuchoice></term> +<listitem><para><action>Copies the file path part of a result record to the clipboard</action> (the copy commands are available depending on the position of the mouse cursor).</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Copy Function</guimenuitem> +</menuchoice></term> +<listitem><para><action>Copies the function name part of a result record to the clipboard.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Copy Line</guimenuitem> +</menuchoice></term> +<listitem><para><action>Copies the line number part of a result record.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Copy Text</guimenuitem> +</menuchoice></term> +<listitem><para><action>Copies the function name part of a result record to the clipboard.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Filter...</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays the Filter Query Results dialogue.</action> See the section <link linkend="filter-results">Filtering Query Results</link> for a detailed description of this option.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Show All</guimenuitem> +</menuchoice></term> +<listitem><para><action>Displays all query results.</action> This option reverts the effects of any filters previously applied.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenuitem>Remove Item</guimenuitem> +</menuchoice></term> +<listitem><para><action>Permanently removes a record from a query results window.</action> This action can only be undone by rerunning the query.</para></listitem> +</varlistentry> +</variablelist> +</para> +</sect2> + +<sect2 id="filter-results"> +<title>Filtering Query Results</title> + +<para> +It is often the case the a query results in an abundance of information. &kapp; allows the user to filter query results in order to show only those results that the user finds interesting, an action referred to as "Filtering". Filtering is done by matching patterns on any of the query record fields (file name, function, line number and line text). +</para> + +<para> +The Filter Query Results dialogue is invoked from the query context menu (see <link linkend="result-options">Query Result Options</link>). +<screenshot> +<screeninfo>The Filter Query Results dialogue</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="query_filter.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>The Filter Query Results dialogue</phrase> +</textobject> +</mediaobject> +</screenshot> +</para> + +<variablelist> +<varlistentry> +<term><guilabel>Search For</guilabel></term> +<listitem><para>Enter the pattern to match in the query result records. This pattern is interpreted based on the Search Type selection.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Search In</guilabel></term> +<listitem><para>The record field in which to look for the search pattern. By default, this is the field over which the context menu was invoked.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Search Type</guilabel></term> +<listitem><para>Defines the way in which the pattern should be interpreted.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Plain Text</guilabel></term> +<listitem><para>Choose this option to treat the pattern as a simple text string to search for.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>RegExp</guilabel></term> +<listitem><para>Choose this option to treat the pattern as a regular expression.</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Simplified RegExp</guilabel></term> +<listitem><para>Choose this option to treat the pattern as a simplified regular expression (a-la file expressions in a Unix shell).</para></listitem> +</varlistentry> +<varlistentry> +<term><guilabel>Case Sensitive</guilabel></term> +<listitem><para>Check for a case sensitive search, uncheck for a case insensitive one.</para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>OK</guibutton></term> +<listitem><para><action>Filters the query results based on the given information.</action></para></listitem> +</varlistentry> +<varlistentry> +<term><guibutton>Cancel</guibutton></term> +<listitem><para><action>Closes the dialogue without filtering the results.</action></para></listitem> +</varlistentry> +</variablelist> + +</sect2> + +<sect2 id="call-tree-graph"> +<title>Displaying Call-Trees and Graphs</title> + +<para> +Tracing a sequence of calls in the code base is a common task in code analysis. To facilitate this task, &kapp; offers two mechanisms for visualising the relationships between different functions in a project: the Call-Tree and the Call-Graph. Both of these mechanisms are provided through the <guilabel>Call Graph Dialogue</guilabel> which can be invoked on a function name in a similar way to a regular <application>Cscope</application> query. +</para> + +<sect3 id="call-tree"> +<title>Call Trees</title> + +<para> +The Call-Tree has two modes, "Called Functions" and "Calling Functions". In the first case, the call chain starts with a root function, and goes on to display all the functions it references. The second mode shows all functions calling the root function. In both modes each function in the second level can be further expanded to show functions calling it (or functions it calls). This process can be further applied to functions in the third level, an so on. +</para> + +<para> +Both modes use a standard tree widget to display the call chain. Expanding a function to the next level is performed by clicking the plus sign to the left of the function's name. Double-clicking a function (or selecting it and then hitting <keycap>Enter</keycap>) points the editor to the call's actual text. Right-clicking an entry provides a popup-menu with further options, similar to the query results menu (see <link linkend="result-options">Query Result Options</link>). +</para> + +<para> +<screenshot> +<screeninfo>A Call-Tree</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="call_tree.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>A Call-Tree in "Called Functions" mode</phrase> +</textobject> +</mediaobject> +</screenshot> +</para> + +</sect3> + +<sect3 id="call-graph"> +<title>Call Graphs</title> + +<para> +A Call-Tree often misses the true nature of a call sequence, since many such sequences contain loops, that is, functions calling back functions that precede them in the sequence. (Recursive calls provide a natural example for such a state of affairs.) A Call-Graph provides a more accurate description of the relationships between functions by depicting calls using a directed graph. Each node in the graph represents a function and each edge a function call. An edge is directed from the caller to the callee. +</para> + +<para> +<screenshot> +<screeninfo>A Call-Graph</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="call_graph.png" format="PNG" /> +</imageobject> +<textobject> +<phrase>A Call-Graph</phrase> +</textobject> +</mediaobject> +</screenshot> +</para> + +<para> +When a Call-Graph is created, it only displays a single function. Right-clicking on this function opens a popup menu that allows the user to display or hide either the functions called by or calling to this one. This menu consists of the following entries: + +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenu>Called Functions</guimenu> +<guimenuitem>Show</guimenuitem> +</menuchoice></term> +<listitem><para>Shows all functions called by this one.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Called Functions</guimenu> +<guimenuitem>List/Filter...</guimenuitem> +</menuchoice></term> +<listitem><para>Displays a detailed list of called functions. This list can also be used to select which calling functions to show.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Called Functions</guimenu> +<guimenuitem>Hide</guimenuitem> +</menuchoice></term> +<listitem><para>Removes any functions called by this one. This will also remove any unconnected graph components resulting from the removal of the corresponding nodes.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Calling Functions</guimenu> +<guimenuitem>Show</guimenuitem> +</menuchoice></term> +<listitem><para>Shows all functions calling this one.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Calling Functions</guimenu> +<guimenuitem>List/Filter...</guimenuitem> +</menuchoice></term> +<listitem><para>Displays a detailed list of calling functions. This list can also be used to select which calling functions to show.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>Calling Functions</guimenu> +<guimenuitem>Hide</guimenuitem> +</menuchoice></term> +<listitem><para>Removes any functions calling this one. This will also remove any unconnected graph components resulting from the removal of the corresponding nodes.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>This Function</guimenu> +<guimenuitem>Find Definition</guimenuitem> +</menuchoice></term> +<listitem><para>Queries the database for the definition of the selected function.</para></listitem> +</varlistentry> +<varlistentry> +<term><menuchoice> +<guimenu>This Function</guimenu> +<guimenuitem>Remove</guimenuitem> +</menuchoice></term> +<listitem><para>Deletes the selected node from the graph.</para></listitem> +</varlistentry> +</variablelist> +</para> + +<para> +Another popup menu is displayed when an arrow head is right-clicked: + +<variablelist> +<varlistentry> +<term><menuchoice> +<guimenuitem>Open Call</guimenuitem> +</menuchoice></term> +<listitem><para>Opens an editor page at the location of the call represented by this edge.</para></listitem> +</varlistentry> +</variablelist> +</para> + +</sect3> + +</sect2> + +</sect1> diff --git a/doc/en/quick_start.docbook b/doc/en/quick_start.docbook new file mode 100644 index 0000000..02ff501 --- /dev/null +++ b/doc/en/quick_start.docbook @@ -0,0 +1,41 @@ +<sect1 id="quick-start"> +<title>Quick Start</title> + +<para> +This section provides information for the impatient user who would like to start using &kapp; right away. While using &kapp; should be straight-forward for anyone who has ever used similar tools in the past, and is familiar with KDE applications, there are, nonetheless, some points that require attention. Even if you do not have the time or patience to browse through this entire manual, please make sure to read at least this section. +</para> + +<sect2> +<title>Configure Paths</title> + +<para> +&kapp; needs to be informed of the absolute paths to several executables, including <application>Cscope</application>, <application>Ctags</application> and (optionally) <application>Dot</application>. These can be configured in the <guilabel>Programmes</guilabel> page of the main configuration dialogue. See <link linkend="config-dlg">The Configuration Dialogue</link> section for more information. +<warning><para>&kapp; will not work properly if these paths are not configured correctly!</para></warning> +</para> +</sect2> + +<sect2> +<title>Create a Project</title> + +<para> +While &kapp; can be used to edit individual files, most of its browsing, analysis and editing features will not be available outside of a project. A project is a set of source files for which &kapp; creates a cross-reference database, the key to most of &kapp;'s capabilities. See <link linkend="project-create">Creating a New Project</link> for detailed instructions. +</para> +</sect2> + +<sect2> +<title>Populate the Project</title> + +<para> +As mentioned above, a project is associated with a set of source files. These need to be added to the project, before any useful work can be done. Files can be added (or removed) using the <link linkend="project-files">Project Files</link> dialogue. +</para> +</sect2> + +<sect2> +<title>Browse and Edit Files</title> + +<para> +Once a project has been defined, &kapp; is ready for use. You can now open files for viewing and editing, and use the query system for browsing and analysing the project's code base. See the rest of this manual for more information. +</para> +</sect2> + +</sect1> diff --git a/po/Makefile.am b/po/Makefile.am new file mode 100644 index 0000000..0fa209c --- /dev/null +++ b/po/Makefile.am @@ -0,0 +1 @@ +POFILES = AUTO diff --git a/po/kscope.pot b/po/kscope.pot new file mode 100644 index 0000000..12f8ce6 --- /dev/null +++ b/po/kscope.pot @@ -0,0 +1,1515 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-08-02 09:22-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "" + +#: calltreedlg.cpp:308 rc.cpp:73 rc.cpp:80 +#, no-c-format +msgid "Call Graph" +msgstr "" + +#: calltreedlg.cpp:310 +msgid "Right-click a function node or an arrow head for more options." +msgstr "" + +#: calltreedlg.cpp:316 rc.cpp:86 +#, no-c-format +msgid "Called Functions Tree" +msgstr "" + +#: calltreedlg.cpp:318 calltreedlg.cpp:327 +msgid "Right-click a tree item for more options." +msgstr "" + +#: calltreedlg.cpp:325 rc.cpp:92 +#, no-c-format +msgid "Calling Functions Tree" +msgstr "" + +#: cscopefrontend.cpp:416 +msgid "Processing query results, please wait..." +msgstr "" + +#: ctagsfrontend.cpp:104 +msgid "Ctags cannot be found in the given path" +msgstr "" + +#: ctagslist.cpp:147 rc.cpp:221 +#, no-c-format +msgid "Name" +msgstr "" + +#: ctagslist.cpp:148 queryview.cpp:53 rc.cpp:580 +#, no-c-format +msgid "Line" +msgstr "" + +#: ctagslist.cpp:149 rc.cpp:613 +#, no-c-format +msgid "Type" +msgstr "" + +#: ctagslist.cpp:189 queryview.cpp:51 rc.cpp:574 +#, no-c-format +msgid "Function" +msgstr "" + +#: ctagslist.cpp:194 +msgid "Variable" +msgstr "" + +#: ctagslist.cpp:199 +msgid "Struct" +msgstr "" + +#: ctagslist.cpp:204 +msgid "Macro" +msgstr "" + +#: ctagslist.cpp:209 +msgid "Member" +msgstr "" + +#: ctagslist.cpp:214 +msgid "Enum" +msgstr "" + +#: ctagslist.cpp:219 +msgid "Enumerator" +msgstr "" + +#: ctagslist.cpp:224 +msgid "Typedef" +msgstr "" + +#: ctagslist.cpp:229 +msgid "Label" +msgstr "" + +#: ctagslist.cpp:234 +msgid "Include" +msgstr "" + +#: dotfrontend.cpp:99 +msgid "Dot cannot be found in the given path" +msgstr "" + +#: editortabs.cpp:190 +msgid "" +"Some files contain unsaved changes.\n" +"Would you like to save these files?" +msgstr "" + +#: editortabs.cpp:295 +msgid "Untitled " +msgstr "" + +#: editortabs.cpp:299 +msgid "New unsaved file" +msgstr "" + +#: filelist.cpp:47 rc.cpp:215 +#, no-c-format +msgid "Path" +msgstr "" + +#: frontend.cpp:84 +msgid "Cannot restart while another process is still running" +msgstr "" + +#: frontend.cpp:104 +msgid ": Failed to start process" +msgstr "" + +#: frontend.cpp:108 +msgid "No error" +msgstr "" + +#: graphwidget.cpp:161 +msgid "<b>Called Functions</b>" +msgstr "" + +#: graphwidget.cpp:163 graphwidget.cpp:172 +msgid "Show" +msgstr "" + +#: graphwidget.cpp:165 graphwidget.cpp:174 +msgid "List/Filter..." +msgstr "" + +#: graphwidget.cpp:167 graphwidget.cpp:176 rc.cpp:135 +#, no-c-format +msgid "Hide" +msgstr "" + +#: graphwidget.cpp:170 +msgid "<b>Calling Functions</b>" +msgstr "" + +#: graphwidget.cpp:179 +msgid "<b>This Function</b>" +msgstr "" + +#: graphwidget.cpp:181 +msgid "Find Definition" +msgstr "" + +#: graphwidget.cpp:187 +msgid "List..." +msgstr "" + +#: graphwidget.cpp:195 +msgid "Open Call" +msgstr "" + +#: graphwidget.cpp:341 kscope.cpp:559 main.cpp:58 +msgid "KScope" +msgstr "" + +#: graphwidget.cpp:342 +msgid "Generating graph, please wait" +msgstr "" + +#: graphwidget.cpp:889 +msgid "" +"The query produced too many results.\n" +"A multiple-call node will appear in the graph instead.\n" +"Hint: The maximum number of in/out edges\n" +"can be adjusted by clicking the dialogue's \"Preferences\" button" +msgstr "" + +#: historypage.cpp:111 +msgid "HIS " +msgstr "" + +#: historypage.cpp:111 +msgid "History " +msgstr "" + +#: kscope.cpp:206 +msgid " Line: N/A Col: N/A " +msgstr "" + +#: kscope.cpp:287 +msgid "" +"The current project needs to be closed before a new one is created.\n" +"Would you like to close it now?" +msgstr "" + +#: kscope.cpp:348 +msgid "The Add/Remove Files dialogue is not available for temporary projects." +msgstr "" + +#: kscope.cpp:381 +msgid "" +"The Project Properties dialogue is not available for temporary projects." +msgstr "" + +#: kscope.cpp:559 +msgid "Please wait while KScope builds the database" +msgstr "" + +#: kscope.cpp:934 +msgid "Verifying Cscope installation..." +msgstr "" + +#: kscope.cpp:1122 +msgid "Verifying Cscope installation...Done" +msgstr "" + +#: kscope.cpp:1130 +msgid "" +"Cscope may not be properly installed on this system.\n" +"Please check the Cscope path specified in KScope's configuration dialogue." +msgstr "" + +#: kscope.cpp:1553 +msgid "Rebuilding the cross reference database..." +msgstr "" + +#: kscope.cpp:1566 +msgid "Please wait while KScope builds the inverted index" +msgstr "" + +#: kscope.cpp:1572 +msgid "Rebuilding inverted index..." +msgstr "" + +#: kscope.cpp:1590 +msgid "Rebuilding the cross reference database...Done!" +msgstr "" + +#: kscope.cpp:1607 +msgid "" +"The database could not be built.\n" +"Cross-reference information will not be available for this project.\n" +"Please ensure that the Cscope parameters were correctly entered in the " +"\"Settings\" dialogue." +msgstr "" + +#: kscope.cpp:1616 +msgid "Rebuilding the cross reference database...Failed" +msgstr "" + +#: kscope.cpp:1687 +msgid "Whould you like to add this file to the active project?" +msgstr "" + +#: kscope.cpp:1692 +msgid "Failed to write the file list." +msgstr "" + +#: kscopeactions.cpp:58 +msgid "Go to File List" +msgstr "" + +#: kscopeactions.cpp:66 +msgid "Save Al&l" +msgstr "" + +#: kscopeactions.cpp:75 +msgid "Edit in E&xternal Editor" +msgstr "" + +#: kscopeactions.cpp:83 +msgid "Go To Tag" +msgstr "" + +#: kscopeactions.cpp:91 +msgid "Complete Symbol" +msgstr "" + +#: kscopeactions.cpp:100 +msgid "&New Project..." +msgstr "" + +#: kscopeactions.cpp:108 +msgid "&Open Project..." +msgstr "" + +#: kscopeactions.cpp:116 +msgid "Open &Cscope.out..." +msgstr "" + +#: kscopeactions.cpp:124 +msgid "Add/Remove &Files..." +msgstr "" + +#: kscopeactions.cpp:140 +msgid "&Make Project" +msgstr "" + +#: kscopeactions.cpp:148 +msgid "&Remake Project" +msgstr "" + +#: kscopeactions.cpp:156 +msgid "&Close Project" +msgstr "" + +#: kscopeactions.cpp:165 +msgid "&References..." +msgstr "" + +#: kscopeactions.cpp:173 +msgid "&Definition..." +msgstr "" + +#: kscopeactions.cpp:181 +msgid "&Called Functions..." +msgstr "" + +#: kscopeactions.cpp:189 +msgid "C&alling Functions..." +msgstr "" + +#: kscopeactions.cpp:197 +msgid "Find &Text..." +msgstr "" + +#: kscopeactions.cpp:205 +msgid "Find &EGrep Pattern..." +msgstr "" + +#: kscopeactions.cpp:213 +msgid "Find &File..." +msgstr "" + +#: kscopeactions.cpp:221 +msgid "&Including Files..." +msgstr "" + +#: kscopeactions.cpp:229 +msgid "&Quick Definition" +msgstr "" + +#: kscopeactions.cpp:237 +msgid "Call &Graph..." +msgstr "" + +#: kscopeactions.cpp:245 +msgid "Re&build database" +msgstr "" + +#: kscopeactions.cpp:254 +msgid "P&revious Result" +msgstr "" + +#: kscopeactions.cpp:262 +msgid "N&ext Result" +msgstr "" + +#: kscopeactions.cpp:270 +msgid "&Previous Position" +msgstr "" + +#: kscopeactions.cpp:278 +msgid "&Next Position" +msgstr "" + +#: kscopeactions.cpp:286 +msgid "Position &History" +msgstr "" + +#: kscopeactions.cpp:294 +msgid "Global &Bookmarks" +msgstr "" + +#: kscopeactions.cpp:303 +msgid "Toggle File List" +msgstr "" + +#: kscopeactions.cpp:311 +msgid "Toggle Query Window" +msgstr "" + +#: kscopeactions.cpp:319 +msgid "Toggle Tag List" +msgstr "" + +#: kscopeactions.cpp:328 +msgid "Close &All" +msgstr "" + +#: kscopeactions.cpp:336 +msgid "Go &Left" +msgstr "" + +#: kscopeactions.cpp:344 +msgid "Go &Right" +msgstr "" + +#: kscopeactions.cpp:357 +msgid "Show &Welcome Message..." +msgstr "" + +#: kscopeactions.cpp:366 +msgid "&New" +msgstr "" + +#: kscopeactions.cpp:374 +msgid "&Refresh" +msgstr "" + +#: kscopeactions.cpp:382 +msgid "&Lock/Unlock" +msgstr "" + +#: main.cpp:36 +msgid "" +"KScope\n" +"A source-editing environment for KDE, based on Cscope" +msgstr "" + +#: main.cpp:42 +msgid "Opens a cscope.out file in a temporary project" +msgstr "" + +#: main.cpp:44 +msgid "Opens a KScope project" +msgstr "" + +#: makedlg.cpp:134 +msgid "A make process is running. Would you like to stop it first?" +msgstr "" + +#: makedlg.cpp:135 +msgid "Close Make Window" +msgstr "" + +#: newprojectdlg.cpp:77 +msgid "Project Properties" +msgstr "" + +#: newprojectdlg.cpp:200 +msgid "Project names must not contain whitespace." +msgstr "" + +#: newprojectdlg.cpp:239 +msgid "This is not a valid file type!" +msgstr "" + +#: preferencesdlg.cpp:56 rc.cpp:123 +#, no-c-format +msgid "Preferences" +msgstr "" + +#: preferencesdlg.cpp:63 +msgid "Programmes" +msgstr "" + +#: preferencesdlg.cpp:64 +msgid "Paths to back-end programmes" +msgstr "" + +#: preferencesdlg.cpp:71 rc.cpp:156 +#, no-c-format +msgid "Colours" +msgstr "" + +#: preferencesdlg.cpp:71 +msgid "Window colours" +msgstr "" + +#: preferencesdlg.cpp:78 +msgid "Window fonts" +msgstr "" + +#: preferencesdlg.cpp:85 +msgid "Misc. Options" +msgstr "" + +#: preferencesdlg.cpp:187 +msgid "This would reset all your configuration settings! Continue?" +msgstr "" + +#: preffont.cpp:77 preffont.cpp:87 +msgid "Sample" +msgstr "" + +#: preffrontend.cpp:137 +msgid "Looking for Cscope..." +msgstr "" + +#: preffrontend.cpp:141 +msgid "Checking Cscope version..." +msgstr "" + +#: preffrontend.cpp:145 +msgid "Cscope support for line mode verbose output..." +msgstr "" + +#: preffrontend.cpp:150 +msgid "Cscope support slow path definitions... " +msgstr "" + +#: preffrontend.cpp:154 +msgid "Looking for Ctags..." +msgstr "" + +#: preffrontend.cpp:158 +msgid "Ctags compatibilty with ctags-exuberant..." +msgstr "" + +#: preffrontend.cpp:163 +msgid "Looking for Dot..." +msgstr "" + +#: preffrontend.cpp:167 +msgid "Checking -Tplain..." +msgstr "" + +#: project.cpp:98 +msgid "Project directory does not exist" +msgstr "" + +#: project.cpp:111 +msgid "" +"Your project is not compatible with this version of KScope.\n" +"Please re-create the project." +msgstr "" + +#: project.cpp:120 +msgid "Cannot read project name" +msgstr "" + +#: projectfilesdlg.cpp:204 +#, c-format +msgid "Would you like to add %d files to your project?" +msgstr "" + +#: projectfilesdlg.cpp:299 +msgid "Are you sure you want to remove the selected files from the project?" +msgstr "" + +#: projectfilesdlg.cpp:329 +msgid "" +"Are you sure you want to remove the selected directory from the project?" +msgstr "" + +#: projectfilesdlg.cpp:362 +msgid "" +"Are you sure you want to remove all files in the selected tree from the " +"project?" +msgstr "" + +#: projectmanager.cpp:67 +msgid "Cannot create a project inside an existing directory" +msgstr "" + +#: projectmanager.cpp:74 +msgid "Failed to create the project's directory" +msgstr "" + +#: projectmanager.cpp:151 +msgid "No Project" +msgstr "" + +#: queryresultsmenu.cpp:41 +msgid "&View Source" +msgstr "" + +#: queryresultsmenu.cpp:43 +msgid "Find &Definition" +msgstr "" + +#: queryresultsmenu.cpp:48 +msgid "&Filter..." +msgstr "" + +#: queryresultsmenu.cpp:49 +msgid "&Show All" +msgstr "" + +#: queryresultsmenu.cpp:51 +msgid "&Remove Item" +msgstr "" + +#: queryview.cpp:54 rc.cpp:583 +#, no-c-format +msgid "Text" +msgstr "" + +#: queryview.cpp:213 +msgid "No results" +msgstr "" + +#: querywidget.cpp:446 +msgid "" +"You about about to close a locked page.\n" +"Are you sure?" +msgstr "" + +#: rc.cpp:12 +#, no-c-format +msgid "&Project" +msgstr "" + +#: rc.cpp:15 +#, no-c-format +msgid "&Cscope" +msgstr "" + +#: rc.cpp:18 +#, no-c-format +msgid "&Go" +msgstr "" + +#: rc.cpp:21 +#, no-c-format +msgid "&Window" +msgstr "" + +#: rc.cpp:30 +#, no-c-format +msgid "&Query" +msgstr "" + +#: rc.cpp:33 +#, no-c-format +msgid "Cscope" +msgstr "" + +#: rc.cpp:36 +#, no-c-format +msgid "Project" +msgstr "" + +#: rc.cpp:39 +#, no-c-format +msgid "Navigation" +msgstr "" + +#: rc.cpp:42 +#, no-c-format +msgid "Query" +msgstr "" + +#: rc.cpp:45 +#, no-c-format +msgid "Workspace" +msgstr "" + +#: rc.cpp:48 +#, no-c-format +msgid "Auto-Completion Properties" +msgstr "" + +#: rc.cpp:51 +#, no-c-format +msgid "Minimum Characters" +msgstr "" + +#: rc.cpp:54 +#, no-c-format +msgid "Delay (ms)" +msgstr "" + +#: rc.cpp:57 +#, no-c-format +msgid "Maximum Entries" +msgstr "" + +#: rc.cpp:66 +#, no-c-format +msgid "Global Bookmarks" +msgstr "" + +#: rc.cpp:77 rc.cpp:83 rc.cpp:89 rc.cpp:159 rc.cpp:165 +#, no-c-format +msgid "..." +msgstr "" + +#: rc.cpp:96 rc.cpp:102 rc.cpp:108 rc.cpp:114 rc.cpp:120 +#, no-c-format +msgid "a" +msgstr "" + +#: rc.cpp:105 +#, no-c-format +msgid "Zoom In" +msgstr "" + +#: rc.cpp:111 +#, no-c-format +msgid "Zoom Out" +msgstr "" + +#: rc.cpp:117 +#, no-c-format +msgid "Rotate" +msgstr "" + +#: rc.cpp:126 +#, no-c-format +msgid "Help Message" +msgstr "" + +#: rc.cpp:129 +#, no-c-format +msgid "Cscope Error Messages" +msgstr "" + +#: rc.cpp:138 +#, no-c-format +msgid "Form1" +msgstr "" + +#: rc.cpp:143 +#, no-c-format +msgid "Project File List" +msgstr "" + +#: rc.cpp:147 +#, no-c-format +msgid "File Tree" +msgstr "" + +#: rc.cpp:150 +#, no-c-format +msgid "Call Graph Preferences" +msgstr "" + +#: rc.cpp:153 +#, no-c-format +msgid "Maximal In/Out Node Degree" +msgstr "" + +#: rc.cpp:176 +#, no-c-format +msgid "KScope - Make" +msgstr "" + +#: rc.cpp:179 +#, no-c-format +msgid "Root Directory:" +msgstr "" + +#: rc.cpp:182 +#, no-c-format +msgid "Command:" +msgstr "" + +#: rc.cpp:185 +#, no-c-format +msgid "Output" +msgstr "" + +#: rc.cpp:188 +#, no-c-format +msgid "Errors a&nd Warnings" +msgstr "" + +#: rc.cpp:191 +#, no-c-format +msgid "&Make" +msgstr "" + +#: rc.cpp:194 +#, no-c-format +msgid "Alt+M" +msgstr "" + +#: rc.cpp:197 +#, no-c-format +msgid "&Stop" +msgstr "" + +#: rc.cpp:200 +#, no-c-format +msgid "Alt+S" +msgstr "" + +#: rc.cpp:206 +#, no-c-format +msgid "Alt+C" +msgstr "" + +#: rc.cpp:209 +#, no-c-format +msgid "Create Project" +msgstr "" + +#: rc.cpp:212 +#, no-c-format +msgid "Detai&ls" +msgstr "" + +#: rc.cpp:218 +#, no-c-format +msgid "Source Root (Optional)" +msgstr "" + +#: rc.cpp:224 +#, no-c-format +msgid "" +"Enter a name for this project.\n" +"The name must conform to the file system's naming conventions for " +"directories (e.g., no spaces, exclamaion marks, etc.)." +msgstr "" + +#: rc.cpp:228 +#, no-c-format +msgid "" +"The path to hold this project.\n" +"KScope will create a directory with the given name under this project, and " +"populate it with the project configuration and database files.\n" +"This does not need to be the path in which the source files reside." +msgstr "" + +#: rc.cpp:233 +#, no-c-format +msgid "" +"<blockquote>A project consists of several files located in a directory\n" +" with the given name and path. The project's name needs to be a valid " +"directory\n" +"name and must not contain any whitespace.</blockquote>\n" +"<br>\n" +"<blockquote>The Source Root is a convinient way to specify a common\n" +"path for all source files, but is not required.</blockquote>" +msgstr "" + +#: rc.cpp:241 +#, no-c-format +msgid "File T&ypes" +msgstr "" + +#: rc.cpp:244 +#, no-c-format +msgid "This Project" +msgstr "" + +#: rc.cpp:247 +#, no-c-format +msgid "" +"KScope uses these filters to locate source files to include in this project." +msgstr "" + +#: rc.cpp:250 +#, no-c-format +msgid "<< &Add" +msgstr "" + +#: rc.cpp:253 rc.cpp:649 +#, no-c-format +msgid "Alt+A" +msgstr "" + +#: rc.cpp:256 +#, no-c-format +msgid "Adds the selected file type to the current project." +msgstr "" + +#: rc.cpp:259 +#, no-c-format +msgid ">> &Remove" +msgstr "" + +#: rc.cpp:262 +#, no-c-format +msgid "Alt+R" +msgstr "" + +#: rc.cpp:265 +#, no-c-format +msgid "Remove the selected file type from the project." +msgstr "" + +#: rc.cpp:268 +#, no-c-format +msgid "Available Types" +msgstr "" + +#: rc.cpp:271 +#, no-c-format +msgid "You can enter custom file types here." +msgstr "" + +#: rc.cpp:274 +#, no-c-format +msgid "*.c" +msgstr "" + +#: rc.cpp:277 +#, no-c-format +msgid "*.h" +msgstr "" + +#: rc.cpp:280 +#, no-c-format +msgid "*.l" +msgstr "" + +#: rc.cpp:283 +#, no-c-format +msgid "*.y" +msgstr "" + +#: rc.cpp:286 +#, no-c-format +msgid "*.S" +msgstr "" + +#: rc.cpp:289 +#, no-c-format +msgid "*.cc" +msgstr "" + +#: rc.cpp:292 +#, no-c-format +msgid "*.cpp" +msgstr "" + +#: rc.cpp:295 +#, no-c-format +msgid "*.cxx" +msgstr "" + +#: rc.cpp:298 +#, no-c-format +msgid "*.C" +msgstr "" + +#: rc.cpp:301 +#, no-c-format +msgid "*.hh" +msgstr "" + +#: rc.cpp:304 +#, no-c-format +msgid "*.hpp" +msgstr "" + +#: rc.cpp:307 +#, no-c-format +msgid "*.hxx" +msgstr "" + +#: rc.cpp:310 +#, no-c-format +msgid "*.H" +msgstr "" + +#: rc.cpp:313 +#, no-c-format +msgid "A list of standard file types." +msgstr "" + +#: rc.cpp:319 +#, no-c-format +msgid "Kernel project (-k)" +msgstr "" + +#: rc.cpp:323 +#, no-c-format +msgid "" +"For kernel projects, symbols are not looked up in the standard include path." +msgstr "" + +#: rc.cpp:326 +#, no-c-format +msgid "Build inverted inde&x (-q)" +msgstr "" + +#: rc.cpp:329 +#, no-c-format +msgid "Alt+X" +msgstr "" + +#: rc.cpp:332 +#, no-c-format +msgid "" +"An inverted index may greatly speed up searches in a large project. The " +"project's building process is longer, though." +msgstr "" + +#: rc.cpp:335 +#, no-c-format +msgid "Do not compress the database (-c)" +msgstr "" + +#: rc.cpp:339 +#, no-c-format +msgid "Slower, but more accurate, function definition detection (-D)" +msgstr "" + +#: rc.cpp:342 +#, no-c-format +msgid "Refresh data&base automatically" +msgstr "" + +#: rc.cpp:345 +#, no-c-format +msgid "Alt+B" +msgstr "" + +#: rc.cpp:348 +#, no-c-format +msgid "Rebuild the database after changed files are saved to disk." +msgstr "" + +#: rc.cpp:351 +#, no-c-format +msgid "(Seconds)" +msgstr "" + +#: rc.cpp:354 +#, no-c-format +msgid "" +"Wait this number of seconds after the last save before rebuilding the " +"database." +msgstr "" + +#: rc.cpp:357 +#, no-c-format +msgid "&Use symbol auto-completion" +msgstr "" + +#: rc.cpp:360 +#, no-c-format +msgid "Alt+U" +msgstr "" + +#: rc.cpp:363 +#, no-c-format +msgid "As-you-type symbol completion." +msgstr "" + +#: rc.cpp:366 +#, no-c-format +msgid "Options..." +msgstr "" + +#: rc.cpp:369 +#, no-c-format +msgid "Override default tab width (Kate only)" +msgstr "" + +#: rc.cpp:372 +#, no-c-format +msgid "Overrides the editor's configured tab width" +msgstr "" + +#: rc.cpp:375 +#, no-c-format +msgid "Cre&ate" +msgstr "" + +#: rc.cpp:378 +#, no-c-format +msgid "Ca&ncel" +msgstr "" + +#: rc.cpp:381 +#, no-c-format +msgid "Open Project" +msgstr "" + +#: rc.cpp:384 +#, no-c-format +msgid "Project Path" +msgstr "" + +#: rc.cpp:387 +#, no-c-format +msgid "Recent Projects" +msgstr "" + +#: rc.cpp:393 +#, no-c-format +msgid "&Open" +msgstr "" + +#: rc.cpp:396 +#, no-c-format +msgid "Alt+O" +msgstr "" + +#: rc.cpp:399 +#, no-c-format +msgid "C&ancel" +msgstr "" + +#: rc.cpp:402 rc.cpp:411 rc.cpp:435 +#, no-c-format +msgid "Form4" +msgstr "" + +#: rc.cpp:405 rc.cpp:414 +#, no-c-format +msgid "GUI Element" +msgstr "" + +#: rc.cpp:408 +#, no-c-format +msgid "Colour" +msgstr "" + +#: rc.cpp:420 +#, no-c-format +msgid "Form3" +msgstr "" + +#: rc.cpp:423 +#, no-c-format +msgid "Cscope path:" +msgstr "" + +#: rc.cpp:426 +#, no-c-format +msgid "Ctags path:" +msgstr "" + +#: rc.cpp:429 +#, no-c-format +msgid "Dot path:" +msgstr "" + +#: rc.cpp:432 +#, no-c-format +msgid "G&uess" +msgstr "" + +#: rc.cpp:438 +#, no-c-format +msgid "" +"Determines whether KScope should automatically load the last project when " +"started." +msgstr "" + +#: rc.cpp:441 +#, no-c-format +msgid "External Editor" +msgstr "" + +#: rc.cpp:444 +#, no-c-format +msgid "Read-Onl&y Mode" +msgstr "" + +#: rc.cpp:447 +#, no-c-format +msgid "Alt+Y" +msgstr "" + +#: rc.cpp:450 +#, no-c-format +msgid "" +"Forces all editor windows to work in a read-only mode, so that the user " +"cannot modify the displayed files." +msgstr "" + +#: rc.cpp:453 +#, no-c-format +msgid "Open Last Project on Start-Up" +msgstr "" + +#: rc.cpp:456 +#, no-c-format +msgid "Automatic Tag Highlighting" +msgstr "" + +#: rc.cpp:459 +#, no-c-format +msgid "" +"Determines whether the tag list should highlight the relevant tag based on " +"the cursor's position." +msgstr "" + +#: rc.cpp:462 +#, no-c-format +msgid "Brief Tab Captions for &Query Pages" +msgstr "" + +#: rc.cpp:465 +#, no-c-format +msgid "" +"If set, the tab captions for query pages will be shortened, by using aliases " +"for the query types." +msgstr "" + +#: rc.cpp:468 +#, no-c-format +msgid "Warn When a File is Modified Outside KScope" +msgstr "" + +#: rc.cpp:471 +#, no-c-format +msgid "" +"If set, the user is prompted whenever the currently edited file is changed " +"by an external programme." +msgstr "" + +#: rc.cpp:474 +#, no-c-format +msgid "Automatically Sort Files in the File List" +msgstr "" + +#: rc.cpp:478 +#, no-c-format +msgid "" +"Sorts files in the project's file list when a project is loaded. This may be " +"too slow for large projects on older machines." +msgstr "" + +#: rc.cpp:481 +#, no-c-format +msgid "System Profile" +msgstr "" + +#: rc.cpp:484 +#, no-c-format +msgid "Fast" +msgstr "" + +#: rc.cpp:487 +#, no-c-format +msgid "Slow" +msgstr "" + +#: rc.cpp:490 +#, no-c-format +msgid "Editor Popup Menu" +msgstr "" + +#: rc.cpp:493 +#, no-c-format +msgid "Embedded" +msgstr "" + +#: rc.cpp:496 +#, no-c-format +msgid "KScope Only" +msgstr "" + +#: rc.cpp:499 +#, no-c-format +msgid "Project Files" +msgstr "" + +#: rc.cpp:502 +#, no-c-format +msgid "Filter" +msgstr "" + +#: rc.cpp:505 +#, no-c-format +msgid "Show All" +msgstr "" + +#: rc.cpp:511 +#, no-c-format +msgid "Files..." +msgstr "" + +#: rc.cpp:514 rc.cpp:526 +#, no-c-format +msgid "Directory..." +msgstr "" + +#: rc.cpp:517 rc.cpp:529 +#, no-c-format +msgid "Tree..." +msgstr "" + +#: rc.cpp:523 +#, no-c-format +msgid "Selected" +msgstr "" + +#: rc.cpp:539 +#, no-c-format +msgid "Query Results" +msgstr "" + +#: rc.cpp:542 +#, no-c-format +msgid "Right-click inside the list for more options." +msgstr "" + +#: rc.cpp:553 +#, no-c-format +msgid "Form2" +msgstr "" + +#: rc.cpp:556 +#, no-c-format +msgid "Scanning Directory" +msgstr "" + +#: rc.cpp:559 +#, no-c-format +msgid "Scanned 0 files..." +msgstr "" + +#: rc.cpp:565 +#, no-c-format +msgid "Filter Query Results" +msgstr "" + +#: rc.cpp:568 +#, no-c-format +msgid "Search For:" +msgstr "" + +#: rc.cpp:571 +#, no-c-format +msgid "Search In:" +msgstr "" + +#: rc.cpp:586 +#, no-c-format +msgid "Search Type" +msgstr "" + +#: rc.cpp:589 +#, no-c-format +msgid "Plain Text" +msgstr "" + +#: rc.cpp:592 +#, no-c-format +msgid "RegE&xp" +msgstr "" + +#: rc.cpp:595 +#, no-c-format +msgid "Simplified RegExp" +msgstr "" + +#: rc.cpp:598 +#, no-c-format +msgid "Case Sensitive" +msgstr "" + +#: rc.cpp:601 +#, no-c-format +msgid "Negate Search" +msgstr "" + +#: rc.cpp:610 +#, no-c-format +msgid "KScope Query" +msgstr "" + +#: rc.cpp:616 +#, no-c-format +msgid "Symbol" +msgstr "" + +#: rc.cpp:619 +#, no-c-format +msgid "References to" +msgstr "" + +#: rc.cpp:622 +#, no-c-format +msgid "Definition of" +msgstr "" + +#: rc.cpp:625 +#, no-c-format +msgid "Functions called by" +msgstr "" + +#: rc.cpp:628 +#, no-c-format +msgid "Functions calling" +msgstr "" + +#: rc.cpp:631 +#, no-c-format +msgid "Find text" +msgstr "" + +#: rc.cpp:634 +#, no-c-format +msgid "Find EGrep pattern" +msgstr "" + +#: rc.cpp:637 +#, no-c-format +msgid "Find file" +msgstr "" + +#: rc.cpp:640 +#, no-c-format +msgid "Files #including" +msgstr "" + +#: rc.cpp:643 +#, no-c-format +msgid "Call graph for" +msgstr "" + +#: rc.cpp:646 +#, no-c-format +msgid "Search for &a Sub-String" +msgstr "" + +#: rc.cpp:655 +#, no-c-format +msgid "Hi&nt" +msgstr "" + +#: rc.cpp:661 +#, no-c-format +msgid "Hint Options" +msgstr "" + +#: rc.cpp:664 +#, no-c-format +msgid "S&ymbols Beginning With..." +msgstr "" + +#: rc.cpp:667 +#, no-c-format +msgid "Sym&bols Containing..." +msgstr "" + +#: rc.cpp:670 +#, no-c-format +msgid "Welcome" +msgstr "" + +#: rc.cpp:673 +#, no-c-format +msgid "" +"<h1>Welcome to <font color=\"#c00000\">KScope</font>!</h1>\n" +"\n" +"If this is the first time you are running Kscope, please follow these steps " +"(click on the links for detailed instructions):\n" +"<p>\n" +"1. <a href=\"help:/kscope/configuration.html#config-progs\">Configure</a> " +"paths to the required back-end executables<br>\n" +"2. <a href=\"help:/kscope/projects.html#project-create\">Create</a> a new " +"project<br>\n" +"3. <a href=\"help:/kscope/projects.html#project-files\">Populate</a> the " +"project with source files<br>\n" +"4. <a href=\"help:/kscope/queries.html\">Browse</a> the project and <a href=" +"\"help:/kscope/editing.html\">edit</a> files<br>\n" +"\n" +"</p>\n" +"\n" +"<p>\n" +"For more information, please take a look at KScope's <a href=\"help:/kscope" +"\">manual</a>, or visit the KScope <a href=\"http://kscope.sourceforge.net" +"\">website</a>.\n" +"</p>\n" +"\n" +"<p>\n" +"Enjoy!\n" +"</p>\n" +"\n" +"<p>\n" +"<font size=\"-1\">This message will only appear once. Use the \"<b>Help-" +">Show Welcome Message...</b>\" menu command to show it again at any time.</" +"font>\n" +"</p>" +msgstr "" + +#: scanprogressdlg.cpp:76 +#, c-format +msgid "Scanned %d files..." +msgstr "" + +#: symbolcompletion.cpp:272 +msgid "No matching completion found..." +msgstr "" + +#: symbolcompletion.cpp:277 +msgid "Too many options..." +msgstr "" + +#: symboldlg.cpp:55 +msgid "Suggested Symbols" +msgstr "" + +#: tabwidget.cpp:50 +msgid "Shows a list of all open tabs" +msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000..c60c706 --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,1642 @@ +# translation of kscope.po to Simplified Chinese +# translation of kscope.po to +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Roy Qu <quh@thunis.com>, 2007. +# Roy Qu <royqh1979@gmail.com>, 2007. +msgid "" +msgstr "" +"Project-Id-Version: kscope\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-08-02 09:22-0400\n" +"PO-Revision-Date: 2007-07-29 11:45+0800\n" +"Last-Translator: Roy Qu <royqh1979@gmail.com>\n" +"Language-Team: Simplified Chinese\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "" + +#: calltreedlg.cpp:308 rc.cpp:73 rc.cpp:80 +#, no-c-format +msgid "Call Graph" +msgstr "调用图" + +#: calltreedlg.cpp:310 +msgid "Right-click a function node or an arrow head for more options." +msgstr "右击函数节点或箭头以获取更多选项。" + +#: calltreedlg.cpp:316 rc.cpp:86 +#, no-c-format +msgid "Called Functions Tree" +msgstr "函数调用情况树" + +#: calltreedlg.cpp:318 calltreedlg.cpp:327 +msgid "Right-click a tree item for more options." +msgstr "右击树中的节点以获取更多选项。" + +#: calltreedlg.cpp:325 rc.cpp:92 +#, no-c-format +msgid "Calling Functions Tree" +msgstr "被其它函数调用情况树" + +#: cscopefrontend.cpp:416 +msgid "Processing query results, please wait..." +msgstr "正在处理查询请求,请等待..." + +#: ctagsfrontend.cpp:104 +msgid "Ctags cannot be found in the given path" +msgstr "在所给的路径中找不到ctags" + +#: ctagslist.cpp:147 rc.cpp:221 +#, no-c-format +msgid "Name" +msgstr "名称" + +#: ctagslist.cpp:148 queryview.cpp:53 rc.cpp:580 +#, no-c-format +msgid "Line" +msgstr "行号" + +#: ctagslist.cpp:149 rc.cpp:613 +#, no-c-format +msgid "Type" +msgstr "类型" + +#: ctagslist.cpp:189 queryview.cpp:51 rc.cpp:574 +#, no-c-format +msgid "Function" +msgstr "函数" + +#: ctagslist.cpp:194 +msgid "Variable" +msgstr "Variable" + +#: ctagslist.cpp:199 +msgid "Struct" +msgstr "Struct" + +#: ctagslist.cpp:204 +msgid "Macro" +msgstr "Macro" + +#: ctagslist.cpp:209 +msgid "Member" +msgstr "Member" + +#: ctagslist.cpp:214 +msgid "Enum" +msgstr "Enum" + +#: ctagslist.cpp:219 +msgid "Enumerator" +msgstr "Enumerator" + +#: ctagslist.cpp:224 +msgid "Typedef" +msgstr "Typedef" + +#: ctagslist.cpp:229 +msgid "Label" +msgstr "Label" + +#: ctagslist.cpp:234 +msgid "Include" +msgstr "Include" + +#: dotfrontend.cpp:99 +msgid "Dot cannot be found in the given path" +msgstr "在给定的路径中找不到" + +#: editortabs.cpp:190 +msgid "" +"Some files contain unsaved changes.\n" +"Would you like to save these files?" +msgstr "" +"某些文件中含有未保存的修改。\n" +"您是否想保存这些文件?" + +#: editortabs.cpp:295 +msgid "Untitled " +msgstr "无标题" + +#: editortabs.cpp:299 +msgid "New unsaved file" +msgstr "新未保存的文件" + +#: filelist.cpp:47 rc.cpp:215 +#, no-c-format +msgid "Path" +msgstr "路径" + +#: frontend.cpp:84 +msgid "Cannot restart while another process is still running" +msgstr "正在运行其它处理,无法重启" + +#: frontend.cpp:104 +msgid ": Failed to start process" +msgstr ":启动处理失败" + +#: frontend.cpp:108 +msgid "No error" +msgstr "无错误" + +#: graphwidget.cpp:161 +msgid "<b>Called Functions</b>" +msgstr "<b>调用的函数</b>" + +#: graphwidget.cpp:163 graphwidget.cpp:172 +msgid "Show" +msgstr "显示" + +#: graphwidget.cpp:165 graphwidget.cpp:174 +msgid "List/Filter..." +msgstr "列表/过滤..." + +#: graphwidget.cpp:167 graphwidget.cpp:176 rc.cpp:135 +#, no-c-format +msgid "Hide" +msgstr "隐藏" + +#: graphwidget.cpp:170 +msgid "<b>Calling Functions</b>" +msgstr "<b>调用它的函数</b>" + +#: graphwidget.cpp:179 +msgid "<b>This Function</b>" +msgstr "<b>此函数</b>" + +#: graphwidget.cpp:181 +msgid "Find Definition" +msgstr "查找定义" + +#: graphwidget.cpp:187 +msgid "List..." +msgstr "列表..." + +#: graphwidget.cpp:195 +msgid "Open Call" +msgstr "" + +#: graphwidget.cpp:341 kscope.cpp:559 main.cpp:58 +msgid "KScope" +msgstr "KScope" + +#: graphwidget.cpp:342 +msgid "Generating graph, please wait" +msgstr "正在生成图形,请等待" + +#: graphwidget.cpp:889 +msgid "" +"The query produced too many results.\n" +"A multiple-call node will appear in the graph instead.\n" +"Hint: The maximum number of in/out edges\n" +"can be adjusted by clicking the dialogue's \"Preferences\" button" +msgstr "" +"这次查询获得的结果太多。\n" +"将在图形中使用多重调用节点来替代。\n" +"提示:可以通过点击对话框的\"偏好设置\"按扭来调整出/入边的最大数量。" + +#: historypage.cpp:111 +msgid "HIS " +msgstr "历史" + +#: historypage.cpp:111 +msgid "History " +msgstr "历史" + +#: kscope.cpp:206 +msgid " Line: N/A Col: N/A " +msgstr "行: N/A 列: N/A " + +#: kscope.cpp:287 +msgid "" +"The current project needs to be closed before a new one is created.\n" +"Would you like to close it now?" +msgstr "" +"为了创建新工程,必须关闭当前工程。\n" +"您要关闭当前工程吗?" + +#: kscope.cpp:348 +msgid "The Add/Remove Files dialogue is not available for temporary projects." +msgstr "在临时工程中不能使用添加/删除文件对话框。" + +#: kscope.cpp:381 +msgid "" +"The Project Properties dialogue is not available for temporary projects." +msgstr "在临时工程中不能使用工程属性对话框。" + +#: kscope.cpp:559 +msgid "Please wait while KScope builds the database" +msgstr "KScope正在建立数据库,请等待" + +#: kscope.cpp:934 +msgid "Verifying Cscope installation..." +msgstr "正在验证Cscope安装..." + +#: kscope.cpp:1122 +msgid "Verifying Cscope installation...Done" +msgstr "正在验证Cscope安装...完成" + +#: kscope.cpp:1130 +msgid "" +"Cscope may not be properly installed on this system.\n" +"Please check the Cscope path specified in KScope's configuration dialogue." +msgstr "" +"此系统上似乎没有安装Cscope。\n" +"请在KScope配置对话框中检查Cscope路径。" + +#: kscope.cpp:1553 +msgid "Rebuilding the cross reference database..." +msgstr "正在重建交叉引用数据库..." + +#: kscope.cpp:1566 +msgid "Please wait while KScope builds the inverted index" +msgstr "KScope正在建立反向索引,请等待" + +#: kscope.cpp:1572 +msgid "Rebuilding inverted index..." +msgstr "正在重建反向索引..." + +#: kscope.cpp:1590 +msgid "Rebuilding the cross reference database...Done!" +msgstr "正在重建反向索引...完成!" + +#: kscope.cpp:1607 +msgid "" +"The database could not be built.\n" +"Cross-reference information will not be available for this project.\n" +"Please ensure that the Cscope parameters were correctly entered in the " +"\"Settings\" dialogue." +msgstr "" +"无法建立数据库。\n" +"在此工程中将无法使用交叉引用信息。\n" +"请检查\"设置\"对话框中的Cscope参数设置是否正确。" + +#: kscope.cpp:1616 +msgid "Rebuilding the cross reference database...Failed" +msgstr "正在重建交叉引用数据库...失败" + +#: kscope.cpp:1687 +msgid "Whould you like to add this file to the active project?" +msgstr "您想要把此文件加入当前工程吗?" + +#: kscope.cpp:1692 +msgid "Failed to write the file list." +msgstr "写文件列表失败。" + +#: kscopeactions.cpp:58 +msgid "Go to File List" +msgstr "转到文件列表" + +#: kscopeactions.cpp:66 +msgid "Save Al&l" +msgstr "全部保存(&L)" + +#: kscopeactions.cpp:75 +msgid "Edit in E&xternal Editor" +msgstr "在外部编辑器中编辑(&X)" + +#: kscopeactions.cpp:83 +msgid "Go To Tag" +msgstr "转到标签" + +#: kscopeactions.cpp:91 +msgid "Complete Symbol" +msgstr "完整符号" + +#: kscopeactions.cpp:100 +msgid "&New Project..." +msgstr "新建工程(&N)..." + +#: kscopeactions.cpp:108 +msgid "&Open Project..." +msgstr "打开工程(&O)..." + +#: kscopeactions.cpp:116 +msgid "Open &Cscope.out..." +msgstr "打开Cscope.out(&C)..." + +#: kscopeactions.cpp:124 +msgid "Add/Remove &Files..." +msgstr "添加/删除文件(&F)..." + +#: kscopeactions.cpp:140 +msgid "&Make Project" +msgstr "Make工程(&M)" + +#: kscopeactions.cpp:148 +msgid "&Remake Project" +msgstr "重新Make工程(&R)" + +#: kscopeactions.cpp:156 +msgid "&Close Project" +msgstr "关闭工程(&C)" + +#: kscopeactions.cpp:165 +msgid "&References..." +msgstr "引用(&R)..." + +#: kscopeactions.cpp:173 +msgid "&Definition..." +msgstr "定义(&D)..." + +#: kscopeactions.cpp:181 +msgid "&Called Functions..." +msgstr "调用的函数(&C)..." + +#: kscopeactions.cpp:189 +msgid "C&alling Functions..." +msgstr "调用它的函数(&A)..." + +#: kscopeactions.cpp:197 +msgid "Find &Text..." +msgstr "查找文字(&T)..." + +#: kscopeactions.cpp:205 +msgid "Find &EGrep Pattern..." +msgstr "查找EGrep模式(&E)..." + +#: kscopeactions.cpp:213 +msgid "Find &File..." +msgstr "查找文件(&F)..." + +#: kscopeactions.cpp:221 +msgid "&Including Files..." +msgstr "包含的文件(&I)..." + +#: kscopeactions.cpp:229 +msgid "&Quick Definition" +msgstr "快速查找定义(&Q)" + +#: kscopeactions.cpp:237 +msgid "Call &Graph..." +msgstr "调用图(&G)..." + +#: kscopeactions.cpp:245 +msgid "Re&build database" +msgstr "重建数据库(&B)" + +#: kscopeactions.cpp:254 +msgid "P&revious Result" +msgstr "前一个结果(&R)" + +#: kscopeactions.cpp:262 +msgid "N&ext Result" +msgstr "下一个结果(&E)" + +#: kscopeactions.cpp:270 +msgid "&Previous Position" +msgstr "前一次定位(&P)" + +#: kscopeactions.cpp:278 +msgid "&Next Position" +msgstr "后一次定位(&N)" + +#: kscopeactions.cpp:286 +msgid "Position &History" +msgstr "定位历史" + +#: kscopeactions.cpp:294 +msgid "Global &Bookmarks" +msgstr "全局书签(&B)" + +#: kscopeactions.cpp:303 +msgid "Toggle File List" +msgstr "切换文件列表" + +#: kscopeactions.cpp:311 +msgid "Toggle Query Window" +msgstr "切换查询窗口" + +#: kscopeactions.cpp:319 +msgid "Toggle Tag List" +msgstr "切换标签列表" + +#: kscopeactions.cpp:328 +msgid "Close &All" +msgstr "全部关闭(&A)" + +#: kscopeactions.cpp:336 +msgid "Go &Left" +msgstr "转到左边(&L)" + +#: kscopeactions.cpp:344 +msgid "Go &Right" +msgstr "转到右边(&R)" + +#: kscopeactions.cpp:357 +msgid "Show &Welcome Message..." +msgstr "显示欢迎信息(&W)..." + +#: kscopeactions.cpp:366 +msgid "&New" +msgstr "新建(&N)" + +#: kscopeactions.cpp:374 +msgid "&Refresh" +msgstr "刷新(&R)" + +#: kscopeactions.cpp:382 +msgid "&Lock/Unlock" +msgstr "锁定/解锁(&L)" + +#: main.cpp:36 +msgid "" +"KScope\n" +"A source-editing environment for KDE, based on Cscope" +msgstr "" + +#: main.cpp:42 +msgid "Opens a cscope.out file in a temporary project" +msgstr "" + +#: main.cpp:44 +#, fuzzy +msgid "Opens a KScope project" +msgstr "打开工程" + +#: makedlg.cpp:134 +msgid "A make process is running. Would you like to stop it first?" +msgstr "一个make进程正在运行。您要先停止它吗?" + +#: makedlg.cpp:135 +msgid "Close Make Window" +msgstr "关闭Make窗口" + +#: newprojectdlg.cpp:77 +msgid "Project Properties" +msgstr "工程属性" + +#: newprojectdlg.cpp:200 +msgid "Project names must not contain whitespace." +msgstr "工程名中不能有空格。" + +#: newprojectdlg.cpp:239 +msgid "This is not a valid file type!" +msgstr "非法的文件类型!" + +#: preferencesdlg.cpp:56 rc.cpp:123 +#, no-c-format +msgid "Preferences" +msgstr "偏好设置" + +#: preferencesdlg.cpp:63 +msgid "Programmes" +msgstr "程序" + +#: preferencesdlg.cpp:64 +msgid "Paths to back-end programmes" +msgstr "后台程序路径" + +#: preferencesdlg.cpp:71 rc.cpp:156 +#, no-c-format +msgid "Colours" +msgstr "配色" + +#: preferencesdlg.cpp:71 +msgid "Window colours" +msgstr "窗口颜色" + +#: preferencesdlg.cpp:78 +msgid "Window fonts" +msgstr "窗口字体" + +#: preferencesdlg.cpp:85 +msgid "Misc. Options" +msgstr "杂项" + +#: preferencesdlg.cpp:187 +msgid "This would reset all your configuration settings! Continue?" +msgstr "这将会重设您的全部配置设定。要继续吗?" + +#: preffont.cpp:77 preffont.cpp:87 +msgid "Sample" +msgstr "例子" + +#: preffrontend.cpp:137 +msgid "Looking for Cscope..." +msgstr "正在查找Cscope..." + +#: preffrontend.cpp:141 +msgid "Checking Cscope version..." +msgstr "正在检查Cscope版本..." + +#: preffrontend.cpp:145 +msgid "Cscope support for line mode verbose output..." +msgstr "Cscope对行模式详细输出的支持..." + +#: preffrontend.cpp:150 +msgid "Cscope support slow path definitions... " +msgstr "Cscope对慢路径定义的支持..." + +#: preffrontend.cpp:154 +msgid "Looking for Ctags..." +msgstr "正在查找Ctags..." + +#: preffrontend.cpp:158 +msgid "Ctags compatibilty with ctags-exuberant..." +msgstr "Ctags对ctags-exuberant的兼容性..." + +#: preffrontend.cpp:163 +msgid "Looking for Dot..." +msgstr "正在查找Dot..." + +#: preffrontend.cpp:167 +msgid "Checking -Tplain..." +msgstr "正在检查-Tplian参数..." + +#: project.cpp:98 +msgid "Project directory does not exist" +msgstr "工程目录不存在" + +#: project.cpp:111 +msgid "" +"Your project is not compatible with this version of KScope.\n" +"Please re-create the project." +msgstr "此版本的KScope不兼容您的工程。请重新创建此工程。" + +#: project.cpp:120 +msgid "Cannot read project name" +msgstr "无法读工程名。" + +#: projectfilesdlg.cpp:204 +#, c-format +msgid "Would you like to add %d files to your project?" +msgstr "您想要将%d个文件添加到您的工程中吗?" + +#: projectfilesdlg.cpp:299 +msgid "Are you sure you want to remove the selected files from the project?" +msgstr "您确定要从工程中删除选中的文件吗?" + +#: projectfilesdlg.cpp:329 +msgid "" +"Are you sure you want to remove the selected directory from the project?" +msgstr "您确定要从工程中删除选中的目录吗?" + +#: projectfilesdlg.cpp:362 +msgid "" +"Are you sure you want to remove all files in the selected tree from the " +"project?" +msgstr "您确定要从工程中删除选中树里的全部文件吗?" + +#: projectmanager.cpp:67 +msgid "Cannot create a project inside an existing directory" +msgstr "无法在已存在的目录中创建工程" + +#: projectmanager.cpp:74 +msgid "Failed to create the project's directory" +msgstr "创建工程目录失败" + +#: projectmanager.cpp:151 +msgid "No Project" +msgstr "无工程" + +#: queryresultsmenu.cpp:41 +msgid "&View Source" +msgstr "查看源文件(&V)" + +#: queryresultsmenu.cpp:43 +msgid "Find &Definition" +msgstr "查找定义(&D)" + +#: queryresultsmenu.cpp:48 +msgid "&Filter..." +msgstr "过滤(&F)..." + +#: queryresultsmenu.cpp:49 +msgid "&Show All" +msgstr "显示全部(&S)..." + +#: queryresultsmenu.cpp:51 +msgid "&Remove Item" +msgstr "删除项(R)..." + +#: queryview.cpp:54 rc.cpp:583 +#, no-c-format +msgid "Text" +msgstr "文字" + +#: queryview.cpp:213 +msgid "No results" +msgstr "无结果" + +#: querywidget.cpp:446 +msgid "" +"You about about to close a locked page.\n" +"Are you sure?" +msgstr "" +"您将要关闭一个已锁定的页。\n" +"确定要这么做吗?" + +#: rc.cpp:12 +#, no-c-format +msgid "&Project" +msgstr "工程(&P)" + +#: rc.cpp:15 +#, no-c-format +msgid "&Cscope" +msgstr "&Cscope" + +#: rc.cpp:18 +#, no-c-format +msgid "&Go" +msgstr "跳转(&G)" + +#: rc.cpp:21 +#, no-c-format +msgid "&Window" +msgstr "窗口(&W)" + +#: rc.cpp:30 +#, no-c-format +msgid "&Query" +msgstr "查询(&Q)" + +#: rc.cpp:33 +#, no-c-format +msgid "Cscope" +msgstr "Cscope" + +#: rc.cpp:36 +#, no-c-format +msgid "Project" +msgstr "工程" + +#: rc.cpp:39 +#, no-c-format +msgid "Navigation" +msgstr "导航" + +#: rc.cpp:42 +#, no-c-format +msgid "Query" +msgstr "查询" + +#: rc.cpp:45 +#, no-c-format +msgid "Workspace" +msgstr "工作空间" + +#: rc.cpp:48 +#, no-c-format +msgid "Auto-Completion Properties" +msgstr "自动补全属性" + +#: rc.cpp:51 +#, no-c-format +msgid "Minimum Characters" +msgstr "最短字符数" + +#: rc.cpp:54 +#, no-c-format +msgid "Delay (ms)" +msgstr "延迟(毫秒)" + +#: rc.cpp:57 +#, no-c-format +msgid "Maximum Entries" +msgstr "最大条目数" + +#: rc.cpp:66 +#, no-c-format +msgid "Global Bookmarks" +msgstr "全局书签" + +#: rc.cpp:77 rc.cpp:83 rc.cpp:89 rc.cpp:159 rc.cpp:165 +#, no-c-format +msgid "..." +msgstr "..." + +#: rc.cpp:96 rc.cpp:102 rc.cpp:108 rc.cpp:114 rc.cpp:120 +#, no-c-format +msgid "a" +msgstr "a" + +#: rc.cpp:105 +#, no-c-format +msgid "Zoom In" +msgstr "放大" + +#: rc.cpp:111 +#, no-c-format +msgid "Zoom Out" +msgstr "缩小" + +#: rc.cpp:117 +#, no-c-format +msgid "Rotate" +msgstr "旋转" + +#: rc.cpp:126 +#, no-c-format +msgid "Help Message" +msgstr "帮助信息" + +#: rc.cpp:129 +#, no-c-format +msgid "Cscope Error Messages" +msgstr "Cscope错误信息" + +#: rc.cpp:138 +#, no-c-format +msgid "Form1" +msgstr "Form1" + +#: rc.cpp:143 +#, no-c-format +msgid "Project File List" +msgstr "工程文件列表" + +#: rc.cpp:147 +#, no-c-format +msgid "File Tree" +msgstr "文件树" + +#: rc.cpp:150 +#, no-c-format +msgid "Call Graph Preferences" +msgstr "调用图偏好设置" + +#: rc.cpp:153 +#, no-c-format +msgid "Maximal In/Out Node Degree" +msgstr "最大出/入节点数" + +#: rc.cpp:176 +#, no-c-format +msgid "KScope - Make" +msgstr "KScope - Make" + +#: rc.cpp:179 +#, no-c-format +msgid "Root Directory:" +msgstr "根目录:" + +#: rc.cpp:182 +#, no-c-format +msgid "Command:" +msgstr "命令:" + +#: rc.cpp:185 +#, no-c-format +msgid "Output" +msgstr "输出" + +#: rc.cpp:188 +#, no-c-format +msgid "Errors a&nd Warnings" +msgstr "错误与警告(&N)" + +#: rc.cpp:191 +#, no-c-format +msgid "&Make" +msgstr "&Make" + +#: rc.cpp:194 +#, no-c-format +msgid "Alt+M" +msgstr "Alt+M" + +#: rc.cpp:197 +#, no-c-format +msgid "&Stop" +msgstr "停止(&S)" + +#: rc.cpp:200 +#, no-c-format +msgid "Alt+S" +msgstr "Alt+S" + +#: rc.cpp:206 +#, no-c-format +msgid "Alt+C" +msgstr "Alt+C" + +#: rc.cpp:209 +#, no-c-format +msgid "Create Project" +msgstr "新建工程" + +#: rc.cpp:212 +#, no-c-format +msgid "Detai&ls" +msgstr "详细信息(&L)" + +#: rc.cpp:218 +#, no-c-format +msgid "Source Root (Optional)" +msgstr "源文件根目录(可选)" + +#: rc.cpp:224 +#, no-c-format +msgid "" +"Enter a name for this project.\n" +"The name must conform to the file system's naming conventions for " +"directories (e.g., no spaces, exclamaion marks, etc.)." +msgstr "" +"输入此工程的名称。\n" +"此名称的格式必须遵循文件系统对目录名的格式要求(例如:不包含空格、特殊符号等)。" + +#: rc.cpp:228 +#, no-c-format +msgid "" +"The path to hold this project.\n" +"KScope will create a directory with the given name under this project, and " +"populate it with the project configuration and database files.\n" +"This does not need to be the path in which the source files reside." +msgstr "" +"存放此工程的路径。\n" +"KScope将在此工程下创建一个以工程名称命名的目录,并将工程配置和数据库 文件保存" +"在里面。\n" +"此路径不需要和项目源文件所在的目录路径相同。" + +#: rc.cpp:233 +#, no-c-format +msgid "" +"<blockquote>A project consists of several files located in a directory\n" +" with the given name and path. The project's name needs to be a valid " +"directory\n" +"name and must not contain any whitespace.</blockquote>\n" +"<br>\n" +"<blockquote>The Source Root is a convinient way to specify a common\n" +"path for all source files, but is not required.</blockquote>" +msgstr "" +"<blockquote>在一个工程中包含保存在给定的名称和路径下的多个文件。 因此,工程名" +"称和路径必须是合法的目录名,其中不能含有空格。</blockquote>\n" +"<br>\n" +"<blockquote>源文件根目录可以被用来为所有源文件指定一个公共路径,不过它并不是" +"必须的。</blockquote>" + +#: rc.cpp:241 +#, no-c-format +msgid "File T&ypes" +msgstr "文件类型(&Y)" + +#: rc.cpp:244 +#, no-c-format +msgid "This Project" +msgstr "此工程" + +#: rc.cpp:247 +#, no-c-format +msgid "" +"KScope uses these filters to locate source files to include in this project." +msgstr "KScope使用这些过滤器来定位包含在此工程中的源文件。" + +#: rc.cpp:250 +#, no-c-format +msgid "<< &Add" +msgstr "<< 添加(&A)" + +#: rc.cpp:253 rc.cpp:649 +#, no-c-format +msgid "Alt+A" +msgstr "Alt+A" + +#: rc.cpp:256 +#, no-c-format +msgid "Adds the selected file type to the current project." +msgstr "将选中类型的文件添加到当前项目中。" + +#: rc.cpp:259 +#, no-c-format +msgid ">> &Remove" +msgstr ">> 删除(&R)" + +#: rc.cpp:262 +#, no-c-format +msgid "Alt+R" +msgstr "Alt+R" + +#: rc.cpp:265 +#, no-c-format +msgid "Remove the selected file type from the project." +msgstr "从工程中删除选中类型的文件。" + +#: rc.cpp:268 +#, no-c-format +msgid "Available Types" +msgstr "可用类型" + +#: rc.cpp:271 +#, no-c-format +msgid "You can enter custom file types here." +msgstr "您可以在这里输入自定义文件类型。" + +#: rc.cpp:274 +#, no-c-format +msgid "*.c" +msgstr "*.c" + +#: rc.cpp:277 +#, no-c-format +msgid "*.h" +msgstr "*.h" + +#: rc.cpp:280 +#, no-c-format +msgid "*.l" +msgstr "*.l" + +#: rc.cpp:283 +#, no-c-format +msgid "*.y" +msgstr "*.y" + +#: rc.cpp:286 +#, no-c-format +msgid "*.S" +msgstr "*.S" + +#: rc.cpp:289 +#, no-c-format +msgid "*.cc" +msgstr "*.cc" + +#: rc.cpp:292 +#, no-c-format +msgid "*.cpp" +msgstr "*.cpp" + +#: rc.cpp:295 +#, no-c-format +msgid "*.cxx" +msgstr "*.cxx" + +#: rc.cpp:298 +#, no-c-format +msgid "*.C" +msgstr "*.C" + +#: rc.cpp:301 +#, no-c-format +msgid "*.hh" +msgstr "*.hh" + +#: rc.cpp:304 +#, no-c-format +msgid "*.hpp" +msgstr "*.hpp" + +#: rc.cpp:307 +#, no-c-format +msgid "*.hxx" +msgstr "*.hxx" + +#: rc.cpp:310 +#, no-c-format +msgid "*.H" +msgstr "*.H" + +#: rc.cpp:313 +#, no-c-format +msgid "A list of standard file types." +msgstr "标准文件类型列表" + +#: rc.cpp:319 +#, no-c-format +msgid "Kernel project (-k)" +msgstr "内核工程(-k)" + +#: rc.cpp:323 +#, no-c-format +msgid "" +"For kernel projects, symbols are not looked up in the standard include path." +msgstr "对于内核工程,不在标准的包含路径中寻找符号声明。" + +#: rc.cpp:326 +#, no-c-format +msgid "Build inverted inde&x (-q)" +msgstr "建立反向索引(-q)(&X)" + +#: rc.cpp:329 +#, no-c-format +msgid "Alt+X" +msgstr "Alt+X" + +#: rc.cpp:332 +#, no-c-format +msgid "" +"An inverted index may greatly speed up searches in a large project. The " +"project's building process is longer, though." +msgstr "" +"在大工程中使用反向索引可以大大提高检索速度。不过,这也会增加创建过程所需要的" +"时间。" + +#: rc.cpp:335 +#, no-c-format +msgid "Do not compress the database (-c)" +msgstr "不压缩数据库(-c)" + +#: rc.cpp:339 +#, no-c-format +msgid "Slower, but more accurate, function definition detection (-D)" +msgstr "更慢,但是更准确,检测函数定义(-D)" + +#: rc.cpp:342 +#, no-c-format +msgid "Refresh data&base automatically" +msgstr "自动更新数据库(&B)" + +#: rc.cpp:345 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#: rc.cpp:348 +#, no-c-format +msgid "Rebuild the database after changed files are saved to disk." +msgstr "当被修改的文件保存到磁盘上之后,重建数据库。" + +#: rc.cpp:351 +#, no-c-format +msgid "(Seconds)" +msgstr "(秒)" + +#: rc.cpp:354 +#, no-c-format +msgid "" +"Wait this number of seconds after the last save before rebuilding the " +"database." +msgstr "在最后一次保存后,等待这些秒数再开始重建数据库。" + +#: rc.cpp:357 +#, no-c-format +msgid "&Use symbol auto-completion" +msgstr "使用符号自动补全(&U)" + +#: rc.cpp:360 +#, no-c-format +msgid "Alt+U" +msgstr "Alt+U" + +#: rc.cpp:363 +#, no-c-format +msgid "As-you-type symbol completion." +msgstr "输入符号时自动补全。" + +#: rc.cpp:366 +#, no-c-format +msgid "Options..." +msgstr "选项..." + +#: rc.cpp:369 +#, no-c-format +msgid "Override default tab width (Kate only)" +msgstr "覆盖缺省标签页宽度(只用于Kate)" + +#: rc.cpp:372 +#, no-c-format +msgid "Overrides the editor's configured tab width" +msgstr "覆盖编辑器中配置的标签页宽度" + +#: rc.cpp:375 +#, no-c-format +msgid "Cre&ate" +msgstr "新建(&A)" + +#: rc.cpp:378 +#, no-c-format +msgid "Ca&ncel" +msgstr "取消(&N)" + +#: rc.cpp:381 +#, no-c-format +msgid "Open Project" +msgstr "打开工程" + +#: rc.cpp:384 +#, no-c-format +msgid "Project Path" +msgstr "工程路径" + +#: rc.cpp:387 +#, no-c-format +msgid "Recent Projects" +msgstr "最近的工程" + +#: rc.cpp:393 +#, no-c-format +msgid "&Open" +msgstr "打开(&O)" + +#: rc.cpp:396 +#, no-c-format +msgid "Alt+O" +msgstr "Alt+O" + +#: rc.cpp:399 +#, no-c-format +msgid "C&ancel" +msgstr "取消(&A)" + +#: rc.cpp:402 rc.cpp:411 rc.cpp:435 +#, no-c-format +msgid "Form4" +msgstr "Form4" + +#: rc.cpp:405 rc.cpp:414 +#, no-c-format +msgid "GUI Element" +msgstr "图形界面元素" + +#: rc.cpp:408 +#, no-c-format +msgid "Colour" +msgstr "颜色" + +#: rc.cpp:420 +#, no-c-format +msgid "Form3" +msgstr "Form3" + +#: rc.cpp:423 +#, no-c-format +msgid "Cscope path:" +msgstr "Cscope路径:" + +#: rc.cpp:426 +#, no-c-format +msgid "Ctags path:" +msgstr "Ctags路径:" + +#: rc.cpp:429 +#, no-c-format +msgid "Dot path:" +msgstr "Dot路径:" + +#: rc.cpp:432 +#, no-c-format +msgid "G&uess" +msgstr "猜测(&U)" + +#: rc.cpp:438 +#, no-c-format +msgid "" +"Determines whether KScope should automatically load the last project when " +"started." +msgstr "决定当KScope启动时,是否自动载入上次的工程。" + +#: rc.cpp:441 +#, no-c-format +msgid "External Editor" +msgstr "外部编辑器" + +#: rc.cpp:444 +#, no-c-format +msgid "Read-Onl&y Mode" +msgstr "只读模式(&Y)" + +#: rc.cpp:447 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#: rc.cpp:450 +#, no-c-format +msgid "" +"Forces all editor windows to work in a read-only mode, so that the user " +"cannot modify the displayed files." +msgstr "强制全部编辑窗口在只读模式下工作,以确保读者无法修改显示的文件。" + +#: rc.cpp:453 +#, no-c-format +msgid "Open Last Project on Start-Up" +msgstr "启动时打开上次的工程" + +#: rc.cpp:456 +#, no-c-format +msgid "Automatic Tag Highlighting" +msgstr "自动高亮标签" + +#: rc.cpp:459 +#, no-c-format +msgid "" +"Determines whether the tag list should highlight the relevant tag based on " +"the cursor's position." +msgstr "决定在标签列表中是否高亮显示与当前光标位置对应的标签" + +#: rc.cpp:462 +#, no-c-format +msgid "Brief Tab Captions for &Query Pages" +msgstr "在查询页面中简写标签页标题" + +#: rc.cpp:465 +#, no-c-format +msgid "" +"If set, the tab captions for query pages will be shortened, by using aliases " +"for the query types." +msgstr "如果设置了此选项,在查询页中将会使用查询类型的别名来简写标签页标题。" + +#: rc.cpp:468 +#, no-c-format +msgid "Warn When a File is Modified Outside KScope" +msgstr "当文件在KScope外面被修改时发出警告" + +#: rc.cpp:471 +#, no-c-format +msgid "" +"If set, the user is prompted whenever the currently edited file is changed " +"by an external programme." +msgstr "如果设置了此选项,当有外部程序改动了当前正在编辑的文件时,会提示用户。" + +#: rc.cpp:474 +#, no-c-format +msgid "Automatically Sort Files in the File List" +msgstr "自动对文件列表中的文件进行排序" + +#: rc.cpp:478 +#, no-c-format +msgid "" +"Sorts files in the project's file list when a project is loaded. This may be " +"too slow for large projects on older machines." +msgstr "" +"当载入一个工程时,自动在工程的文件列表中对文件进行排序。如果在旧机器 上编辑很" +"大的项目,这可能会导致响应变慢。" + +#: rc.cpp:481 +#, no-c-format +msgid "System Profile" +msgstr "系统偏好文件" + +#: rc.cpp:484 +#, no-c-format +msgid "Fast" +msgstr "快" + +#: rc.cpp:487 +#, no-c-format +msgid "Slow" +msgstr "慢" + +#: rc.cpp:490 +#, no-c-format +msgid "Editor Popup Menu" +msgstr "编辑器弹出菜单" + +#: rc.cpp:493 +#, no-c-format +msgid "Embedded" +msgstr "嵌入" + +#: rc.cpp:496 +#, no-c-format +msgid "KScope Only" +msgstr "仅KScope" + +#: rc.cpp:499 +#, no-c-format +msgid "Project Files" +msgstr "工程文件" + +#: rc.cpp:502 +#, no-c-format +msgid "Filter" +msgstr "过滤" + +#: rc.cpp:505 +#, no-c-format +msgid "Show All" +msgstr "显示全部" + +#: rc.cpp:511 +#, no-c-format +msgid "Files..." +msgstr "文件..." + +#: rc.cpp:514 rc.cpp:526 +#, no-c-format +msgid "Directory..." +msgstr "目录..." + +#: rc.cpp:517 rc.cpp:529 +#, no-c-format +msgid "Tree..." +msgstr "树..." + +#: rc.cpp:523 +#, no-c-format +msgid "Selected" +msgstr "已有选择" + +#: rc.cpp:539 +#, no-c-format +msgid "Query Results" +msgstr "查询结果" + +#: rc.cpp:542 +#, no-c-format +msgid "Right-click inside the list for more options." +msgstr "在列表内右击以获取更多选项。" + +#: rc.cpp:553 +#, no-c-format +msgid "Form2" +msgstr "Form2" + +#: rc.cpp:556 +#, no-c-format +msgid "Scanning Directory" +msgstr "正在扫描目录" + +#: rc.cpp:559 +#, no-c-format +msgid "Scanned 0 files..." +msgstr "已扫描0个文件..." + +#: rc.cpp:565 +#, no-c-format +msgid "Filter Query Results" +msgstr "过滤查询结果" + +#: rc.cpp:568 +#, no-c-format +msgid "Search For:" +msgstr "查找:" + +#: rc.cpp:571 +#, no-c-format +msgid "Search In:" +msgstr "在...中查找:" + +#: rc.cpp:586 +#, no-c-format +msgid "Search Type" +msgstr "查找类型" + +#: rc.cpp:589 +#, no-c-format +msgid "Plain Text" +msgstr "纯文本" + +#: rc.cpp:592 +#, no-c-format +msgid "RegE&xp" +msgstr "正则表达式(&X)" + +#: rc.cpp:595 +#, no-c-format +msgid "Simplified RegExp" +msgstr "简化的正则表达式" + +#: rc.cpp:598 +#, no-c-format +msgid "Case Sensitive" +msgstr "大小写敏感" + +#: rc.cpp:601 +#, no-c-format +msgid "Negate Search" +msgstr "反转查找" + +#: rc.cpp:610 +#, no-c-format +msgid "KScope Query" +msgstr "KScope查询" + +#: rc.cpp:616 +#, no-c-format +msgid "Symbol" +msgstr "符号" + +#: rc.cpp:619 +#, no-c-format +msgid "References to" +msgstr "对它的引用" + +#: rc.cpp:622 +#, no-c-format +msgid "Definition of" +msgstr "定义" + +#: rc.cpp:625 +#, no-c-format +msgid "Functions called by" +msgstr "被它调用的函数" + +#: rc.cpp:628 +#, no-c-format +msgid "Functions calling" +msgstr "调用它的函数" + +#: rc.cpp:631 +#, no-c-format +msgid "Find text" +msgstr "查找文字" + +#: rc.cpp:634 +#, no-c-format +msgid "Find EGrep pattern" +msgstr "查找EGrep模式" + +#: rc.cpp:637 +#, no-c-format +msgid "Find file" +msgstr "查找文件" + +#: rc.cpp:640 +#, no-c-format +msgid "Files #including" +msgstr "#include它的文件" + +#: rc.cpp:643 +#, no-c-format +msgid "Call graph for" +msgstr "调用图" + +#: rc.cpp:646 +#, no-c-format +msgid "Search for &a Sub-String" +msgstr "查找子字符串(&A)" + +#: rc.cpp:655 +#, no-c-format +msgid "Hi&nt" +msgstr "提示(&N)" + +#: rc.cpp:661 +#, no-c-format +msgid "Hint Options" +msgstr "提示选项" + +#: rc.cpp:664 +#, no-c-format +msgid "S&ymbols Beginning With..." +msgstr "以...开头的符号(&Y)..." + +#: rc.cpp:667 +#, no-c-format +msgid "Sym&bols Containing..." +msgstr "包含...的符号(&B)..." + +#: rc.cpp:670 +#, no-c-format +msgid "Welcome" +msgstr "欢迎" + +#: rc.cpp:673 +#, no-c-format +msgid "" +"<h1>Welcome to <font color=\"#c00000\">KScope</font>!</h1>\n" +"\n" +"If this is the first time you are running Kscope, please follow these steps " +"(click on the links for detailed instructions):\n" +"<p>\n" +"1. <a href=\"help:/kscope/configuration.html#config-progs\">Configure</a> " +"paths to the required back-end executables<br>\n" +"2. <a href=\"help:/kscope/projects.html#project-create\">Create</a> a new " +"project<br>\n" +"3. <a href=\"help:/kscope/projects.html#project-files\">Populate</a> the " +"project with source files<br>\n" +"4. <a href=\"help:/kscope/queries.html\">Browse</a> the project and <a href=" +"\"help:/kscope/editing.html\">edit</a> files<br>\n" +"\n" +"</p>\n" +"\n" +"<p>\n" +"For more information, please take a look at KScope's <a href=\"help:/kscope" +"\">manual</a>, or visit the KScope <a href=\"http://kscope.sourceforge.net" +"\">website</a>.\n" +"</p>\n" +"\n" +"<p>\n" +"Enjoy!\n" +"</p>\n" +"\n" +"<p>\n" +"<font size=\"-1\">This message will only appear once. Use the \"<b>Help-" +">Show Welcome Message...</b>\" menu command to show it again at any time.</" +"font>\n" +"</p>" +msgstr "" +"<h1>欢迎使用 <font color=\"#c00000\">KScope</font>!</h1>\n" +"\n" +"如果这是您第一次使用KScope,请按照下面的步骤做(点击连接可以获取更详细 的指" +"示):\n" +"<p>\n" +"1. <a href=\"help:/kscope/configuration.html#config-progs\">配置</a> 必要的后" +"台程序所在的路径<br>\n" +"2. <a href=\"help:/kscope/projects.html#project-create\">创建</a> 一个新工程" +"<br>\n" +"3. 向工程中<a href=\"help:/kscope/projects.html#project-files\">添加</a>源文" +"件<br>\n" +"4. <a href=\"help:/kscope/queries.html\">浏览</a> 工程,<a href=\"help:/" +"kscope/editing.html\">编辑</a>文件<br>\n" +"\n" +"</p>\n" +"\n" +"<p>\n" +"请查看KScope<a href=\"help:/kscope\">手册</a>, 或访问KScope <a href=\"http://" +"kscope.sourceforge.net\">网站</a>以获取更多信息.\n" +"</p>\n" +"\n" +"<p>\n" +"请尽情享受KScope吧!\n" +"</p>\n" +"\n" +"<p>\n" +"<font size=\"-1\">此消息只会显示一次。可以使用菜单中的\"<b>帮助->显示欢迎信" +"息...</b>\"项来再次显示它。</font>\n" +"</p>" + +#: scanprogressdlg.cpp:76 +#, c-format +msgid "Scanned %d files..." +msgstr "已扫描%d个文件..." + +#: symbolcompletion.cpp:272 +msgid "No matching completion found..." +msgstr "未找到匹配的补足" + +#: symbolcompletion.cpp:277 +msgid "Too many options..." +msgstr "选项太多..." + +#: symboldlg.cpp:55 +msgid "Suggested Symbols" +msgstr "建议的符号" + +#: tabwidget.cpp:50 +msgid "Shows a list of all open tabs" +msgstr "显示包含全部已打开标签页的列表" + +#~ msgid "OK" +#~ msgstr "确定" + +#~ msgid "Cancel" +#~ msgstr "取消" + +#~ msgid "Close" +#~ msgstr "关闭" + +#~ msgid "Save As..." +#~ msgstr "另存为..." + +#~ msgid "Clear" +#~ msgstr "清除" + +#~ msgid "Fonts" +#~ msgstr "字体" + +#~ msgid "&OK" +#~ msgstr "确定(&O)" + +#~ msgid "&Cancel" +#~ msgstr "取消(&C)" + +#~ msgid "&Close" +#~ msgstr "关闭(&C)" + +#~ msgid "&Options" +#~ msgstr "选项(&O)" + +#~ msgid "Remove" +#~ msgstr "删除" + +#~ msgid "Font" +#~ msgstr "字体" + +#~ msgid "Add" +#~ msgstr "添加" + +#~ msgid "File" +#~ msgstr "文件" + +#~ msgid "&File" +#~ msgstr "文件(&F)" + +#~ msgid "&Edit" +#~ msgstr "编辑(&E)" + +#~ msgid "&View" +#~ msgstr "查看(&V)" + +#~ msgid "&Settings" +#~ msgstr "设置(&S)" + +#~ msgid "&Help" +#~ msgstr "帮助(&H)" + +#~ msgid "&Properties..." +#~ msgstr "偏好设置(&P)..." + +#~ msgid "Options" +#~ msgstr "选项" + +#~ msgid "&Copy" +#~ msgstr "复制(&C)" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..e82522d --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,68 @@ +# set the include path for X, qt and KDE +INCLUDES = $(all_includes) + +# these are the headers for your project +noinst_HEADERS = bookmarksdlg.h calltreedlg.h calltreemanager.h \ + configfrontend.h cscopefrontend.h cscopemsgdlg.h ctagsfrontend.h ctagslist.h \ + dirscanner.h dotfrontend.h editormanager.h editorpage.h editortabs.h encoder.h \ + filelist.h fileview.h frontend.h graphedge.h graphnode.h graphprefdlg.h \ + graphwidget.h historypage.h historyview.h kscope.h kscopeactions.h kscopeconfig.h \ + kscopepixmaps.h makedlg.h makefrontend.h newprojectdlg.h openprojectdlg.h prefcolor.h \ + preferencesdlg.h preffont.h preffrontend.h prefopt.h progressdlg.h project.h \ + projectbase.h projectfilesdlg.h projectmanager.h querypage.h querypagebase.h \ + queryresultsmenu.h queryview.h queryviewdlg.h queryviewdriver.h querywidget.h \ + scanprogressdlg.h searchlist.h searchresultsdlg.h symbolcompletion.h symboldlg.h \ + tabwidget.h treewidget.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kscope.pot + +KDE_ICON = kscope + +######################################################################### +# APPLICATION SECTION +######################################################################### +# this is the program that gets installed. it's name is used for all +# of the other Makefile.am variables +bin_PROGRAMS = kscope + +# the application source, library search path, and link libraries +kscope_SOURCES = autocompletionlayout.ui bookmarksdlg.cpp bookmarkslayout.ui \ + calltreedlg.cpp calltreelayout.ui calltreemanager.cpp configfrontend.cpp \ + cscopefrontend.cpp cscopemsgdlg.cpp cscopemsglayout.ui ctagsfrontend.cpp ctagslist.cpp \ + dirscanner.cpp dotfrontend.cpp dotparse.ypp dotscan.lpp editormanager.cpp \ + editorpage.cpp editortabs.cpp encoder.cpp filelist.cpp fileview.cpp fileviewlayout.ui \ + frontend.cpp graphedge.cpp graphnode.cpp graphprefdlg.cpp graphpreflayout.ui \ + graphwidget.cpp historypage.cpp historyview.cpp kscope.cpp kscopeactions.cpp \ + kscopeconfig.cpp kscopepixmaps.cpp main.cpp makedlg.cpp makefrontend.cpp makelayout.ui \ + newprojectdlg.cpp newprojectlayout.ui openprojectdlg.cpp openprojectlayout.ui \ + prefcolor.cpp prefcolorlayout.ui preferencesdlg.cpp preffont.cpp preffontlayout.ui \ + preffrontend.cpp preffrontendlayout.ui prefopt.cpp prefoptlayout.ui progressdlg.cpp \ + project.cpp projectbase.cpp projectfilesdlg.cpp projectfileslayout.ui \ + projectmanager.cpp querypage.cpp querypagebase.cpp queryresultsmenu.cpp queryview.cpp \ + queryviewdlg.cpp queryviewdriver.cpp queryviewlayout.ui querywidget.cpp \ + querywidgetlayout.ui scanprogressdlg.cpp scanprogresslayout.ui searchlist.cpp \ + searchresultsdlg.cpp searchresultslayout.ui symbolcompletion.cpp symboldlg.cpp \ + symbollayout.ui tabwidget.cpp treewidget.cpp welcomedlg.ui + +kscope_LDFLAGS = $(KDE_RPATH) $(all_libraries) +kscope_LDADD = -lkateinterfaces -lktexteditor $(LIB_KDEUI) + +# this is where the desktop file will go +shelldesktopdir = $(kde_appsdir)/Development +shelldesktop_DATA = kscope.desktop + +# this is where the shell's XML-GUI resource file goes +shellrcdir = $(kde_datadir)/kscope +shellrc_DATA = kscopeui.rc kscope_config + +picsdir = $(kde_datadir)/kscope/pics +pics_DATA = file_ro.png file_rw.png file_save.png query_locked.png \ + query_unlocked.png tab_list.png call_graph.png called_tree.png calling_tree.png \ + bookmark.png + +BUILT_SOURCES = dotparse.h +AM_YFLAGS = -d diff --git a/src/autocompletionlayout.ui b/src/autocompletionlayout.ui new file mode 100644 index 0000000..2c8c274 --- /dev/null +++ b/src/autocompletionlayout.ui @@ -0,0 +1,217 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AutoCompletionLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>AutoCompletionLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>287</width> + <height>183</height> + </rect> + </property> + <property name="caption"> + <string>Auto-Completion Properties</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout20</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Minimum Characters</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer15</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>71</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pMinCharsSpin</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout21</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Delay (ms)</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer16</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>101</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pDelaySpin</cstring> + </property> + <property name="maxValue"> + <number>10000</number> + </property> + <property name="lineStep"> + <number>100</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout22</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Maximum Entries</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer17</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pMaxEntriesSpin</cstring> + </property> + <property name="maxValue"> + <number>1000</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer19</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout23</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer18</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>111</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pOKButton</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/bookmark.png b/src/bookmark.png Binary files differnew file mode 100644 index 0000000..5e76158 --- /dev/null +++ b/src/bookmark.png diff --git a/src/bookmarksdlg.cpp b/src/bookmarksdlg.cpp new file mode 100644 index 0000000..577476a --- /dev/null +++ b/src/bookmarksdlg.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "bookmarksdlg.h" +#include "queryview.h" + +BookmarksDlg::BookmarksDlg(QWidget* pParent, const char* szName) : + BookmarksLayout (pParent, szName, true) +{ + // Do not show the "Function" column + m_pView->setColumnWidth(0, 0); + + // Handle requests for source locations + connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotLineRequested(const QString&, uint))); +} + +BookmarksDlg::~BookmarksDlg() +{ +} + +void BookmarksDlg::getBookmark(QString& sPath, uint& nLine) +{ + sPath = m_sPath; + nLine = m_nLine; +} + +void BookmarksDlg::slotLineRequested(const QString& sPath, uint nLine) +{ + m_sPath = sPath; + m_nLine = nLine; + accept(); +} + +#include "bookmarksdlg.moc" + diff --git a/src/bookmarksdlg.h b/src/bookmarksdlg.h new file mode 100644 index 0000000..ab74f9d --- /dev/null +++ b/src/bookmarksdlg.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef BOOKMARKSDLG_H +#define BOOKMARKSDLG_H + +#include "bookmarkslayout.h" + +class BookmarksDlg : public BookmarksLayout +{ +Q_OBJECT + +public: + BookmarksDlg(QWidget* pParent = 0, const char* szName = 0); + ~BookmarksDlg(); + + QueryView* getView() { return m_pView; } + void getBookmark(QString&, uint&); + +private: + QString m_sPath; + uint m_nLine; + +private slots: + void slotLineRequested(const QString&, uint); +}; + +#endif + diff --git a/src/bookmarkslayout.ui b/src/bookmarkslayout.ui new file mode 100644 index 0000000..f1f8135 --- /dev/null +++ b/src/bookmarkslayout.ui @@ -0,0 +1,116 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>BookmarksLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>BookmarksLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>480</height> + </rect> + </property> + <property name="caption"> + <string>Global Bookmarks</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QueryView"> + <property name="name"> + <cstring>m_pView</cstring> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>291</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCloseButton</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>QueryView</class> + <header location="local">queryview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data> + </image> +</images> +<connections> + <connection> + <sender>m_pCloseButton</sender> + <signal>clicked()</signal> + <receiver>BookmarksLayout</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>queryview.h</includehint> +</includehints> +</UI> diff --git a/src/call_graph.png b/src/call_graph.png Binary files differnew file mode 100644 index 0000000..0b87ddd --- /dev/null +++ b/src/call_graph.png diff --git a/src/called_tree.png b/src/called_tree.png Binary files differnew file mode 100644 index 0000000..db58776 --- /dev/null +++ b/src/called_tree.png diff --git a/src/calling_tree.png b/src/calling_tree.png Binary files differnew file mode 100644 index 0000000..89e40d2 --- /dev/null +++ b/src/calling_tree.png diff --git a/src/calltreedlg.cpp b/src/calltreedlg.cpp new file mode 100644 index 0000000..65ee4f8 --- /dev/null +++ b/src/calltreedlg.cpp @@ -0,0 +1,336 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfile.h> +#include <qtoolbutton.h> +#include <qbuttongroup.h> +#include <qwidgetstack.h> +#include <klocale.h> +#include <kfiledialog.h> +#include "calltreedlg.h" +#include "graphwidget.h" +#include "treewidget.h" +#include "kscopepixmaps.h" +#include "kscopeconfig.h" +#include "graphprefdlg.h" + +/** The currently supported version of saved call-tree files. */ +#define FILE_VERSION 5 + +/** Window flags for call-tree widgets. */ +#define CALL_TREE_W_FLAGS \ + WStyle_Customize | \ + WStyle_NormalBorder | \ + WStyle_Title | \ + WDestructiveClose + +/** File Name index for the file name generation */ +int CallTreeDlg::s_nFileNameIndex = 0; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +CallTreeDlg::CallTreeDlg(QWidget* pParent, const char* szName) : + CallTreeLayout(pParent, szName, CALL_TREE_W_FLAGS) +{ + // Set button pixmaps + m_pCalledButton->setPixmap(GET_PIXMAP(CalledTree)); + m_pCallingButton->setPixmap(GET_PIXMAP(CallingTree)); + m_pGraphButton->setPixmap(GET_PIXMAP(CallGraph)); + m_pSaveButton->setPixmap(GET_PIXMAP(ButtonSaveAs)); + m_pZoomInButton->setPixmap(GET_PIXMAP(ButtonZoomIn)); + m_pZoomOutButton->setPixmap(GET_PIXMAP(ButtonZoomOut)); + m_pRotateButton->setPixmap(GET_PIXMAP(ButtonRotate)); + m_pPrefButton->setPixmap(GET_PIXMAP(ButtonPref)); + + // Open the location of a call + connect(m_pGraphWidget, SIGNAL(lineRequested(const QString&, uint)), + this, SIGNAL(lineRequested(const QString&, uint))); + connect(m_pCalledWidget, SIGNAL(lineRequested(const QString&, uint)), + this, SIGNAL(lineRequested(const QString&, uint))); + connect(m_pCallingWidget, SIGNAL(lineRequested(const QString&, uint)), + this, SIGNAL(lineRequested(const QString&, uint))); + + m_pCallingWidget->setMode(TreeWidget::Calling); + + // Get the default view from KScope's configuration + m_nDefView = Config().getDefGraphView(); +} + +/** + * Class destructor. + */ +CallTreeDlg::~CallTreeDlg() +{ +} + +/** + * @param sFunc The function to use as the root of the call tree + */ +void CallTreeDlg::setRoot(const QString& sFunc) +{ + m_sRoot = sFunc; + + // Generate unique file name to save call tree later + m_sFileName = sFunc; + m_sFileName.replace(' ', '_'); + m_sFileName += QString::number(++s_nFileNameIndex); + + // Set the root item in all views + m_pGraphWidget->setRoot(sFunc); + m_pCalledWidget->setRoot(sFunc); + m_pCallingWidget->setRoot(sFunc); +} + +/** + * Displays the dialogue. + */ +void CallTreeDlg::show() +{ + // Set the default view. + m_pViewGroup->setButton(m_nDefView); + m_pStack->raiseWidget(m_nDefView); + slotViewChanged(m_nDefView); + + CallTreeLayout::show(); +} + +/** + * Informs the call tree manager that this object should be removed from the + * list of call tree dialogues. + * The close event is received when the dialogue is explicitly closed by the + * user. This dialogue will not appear when the project is reopened, and it + * is therefore safe to delete the graph file at this point. + * @param pEvent Information on the closing event + */ +void CallTreeDlg::closeEvent(QCloseEvent* pEvent) +{ + if (!m_sFilePath.isEmpty()) + QFile::remove(m_sFilePath); + + emit closed(this); + QWidget::closeEvent(pEvent); +} + +extern void yyinit(CallTreeDlg*, FILE*, Encoder*); +extern int yyparse(); + +/** + * Restores a call tree from the given call tree file. + * NOTE: The call tree file is deleted when loading is complete. + * @param sProjPath The full path of the project directory + * @param sFileName The name of the call tree file to load + * @return true if successful, false otherwise + */ +bool CallTreeDlg::load(const QString& sProjPath, const QString& sFileName) +{ + QString sPath; + FILE* pFile; + int nVersion, nView, nResult; + Encoder enc; + + // Create the full path name + sPath = sProjPath + "/" + sFileName; + + // Open the file for reading + pFile = fopen(sPath.latin1(), "r"); + if (pFile == NULL) + return false; + + // Check file version + if ((fscanf(pFile, "VERSION=%d\n", &nVersion) != 1) || + (nVersion != FILE_VERSION)) { + fclose(pFile); + return false; + } + + // Get default view + if ((fscanf(pFile, "View=%d\n", &nView) == 1) && + (nView >= 0) && + (nView <= 2)) { + m_nDefView = nView; + } + + // Read the call trees and the graph stored on this file + yyinit(this, pFile, &enc); + nResult = yyparse(); + + // Close the file + fclose(pFile); + + // Check the result returned by the parser + if (nResult != 0) + return false; + + // Store the file name + m_sFileName = sFileName; + m_sFilePath = sPath; + + // Draw the graph + m_pGraphWidget->draw(); + return true; +} + +/** + * Writes the contents of the call tree dialog to a call tree file. + * This method is called for call trees before the owner project is + * closed. + * @param sProjPath The full path of the project directory + */ +void CallTreeDlg::store(const QString& sProjPath) +{ + QString sPath; + FILE* pFile; + + // Create the full file path + sPath = sProjPath + "/" + m_sFileName; + m_sFilePath = sPath; + + // Open a file for writing (create if necessary) + pFile = fopen(sPath.latin1(), "w+"); + if (pFile == NULL) + return; + + // Write header + fprintf(pFile, "VERSION=%d\n", FILE_VERSION); + fprintf(pFile, "View=%d\n", m_pViewGroup->selectedId()); + + // Save the contents of all widgets + m_pCalledWidget->save(pFile); + m_pCallingWidget->save(pFile); + m_pGraphWidget->save(pFile); + + // Close the file + fclose(pFile); +} + +/** + * Saves the graph to a dot file. + * The user is prompted for a name to use for the file, and then graph + * widget writes its information to this file (using the dot language). + * This slot is connected to the clicked() signal of the "Save As..." button. + */ +void CallTreeDlg::slotSaveClicked() +{ + QString sFile; + + // Prompt the user for a file name + sFile = KFileDialog::getSaveFileName(":kscope"); + + // Save the graph to a file (unless the user did not give a file name) + if (!sFile.isEmpty()) + m_pGraphWidget->save(sFile); +} + +/** + * Increases the zoom factor of the graph. + * This slot is connected to the clicked() signal of the "Zoom In" button. + */ +void CallTreeDlg::slotZoomInClicked() +{ + m_pGraphWidget->zoom(true); + m_pGraphWidget->draw(); +} + +/** + * Decreases the zoom factor of the graph. + * This slot is connected to the clicked() signal of the "Zoom Out" button. + */ +void CallTreeDlg::slotZoomOutClicked() +{ + m_pGraphWidget->zoom(false); + m_pGraphWidget->draw(); +} + +/** + * Changes the graph's layout direction. + * This slot is connected to the clicked() signal of the "Rotate" button. + */ +void CallTreeDlg::slotRotateClicked() +{ + m_pGraphWidget->rotate(); + m_pGraphWidget->draw(); +} + +/** + * Opens the call graph preferences dialogue. + * This slot is connected to the clicked() signal of the "Preferences" button. + */ +void CallTreeDlg::slotPrefClicked() +{ + GraphPrefDlg dlg(this); + int nMaxNodeDegree; + + if (dlg.exec() == QDialog::Accepted) { + nMaxNodeDegree = dlg.getMaxNodeDegree(); + Config().setGraphMaxNodeDegree(nMaxNodeDegree); + m_pGraphWidget->setMaxNodeDegree(nMaxNodeDegree); + } +} + +/** + * Prepares the selected view. + * This slot is called when the user chooses a different view through the + * toggle buttons in the dialogue's toolbar. + * @param nView Identifies the selected view + */ +void CallTreeDlg::slotViewChanged(int nView) +{ + switch (nView) { + case 0: + // Call graph + setCaption(i18n("Call Graph")); + m_pGraphGroup->setEnabled(true); + m_pHelpLabel->setText(i18n("Right-click a function node or an arrow " + "head for more options.")); + break; + + case 1: + // Called functions tree + setCaption(i18n("Called Functions Tree")); + m_pGraphGroup->setEnabled(false); + m_pHelpLabel->setText(i18n("Right-click a tree item for more " + "options.")); + m_pCalledWidget->queryRoot(); + break; + + case 2: + // Calling functions tree + setCaption(i18n("Calling Functions Tree")); + m_pGraphGroup->setEnabled(false); + m_pHelpLabel->setText(i18n("Right-click a tree item for more " + "options.")); + m_pCallingWidget->queryRoot(); + break; + } + + Config().setDefGraphView(nView); +} + +#include "calltreedlg.moc" diff --git a/src/calltreedlg.h b/src/calltreedlg.h new file mode 100644 index 0000000..d5f567b --- /dev/null +++ b/src/calltreedlg.h @@ -0,0 +1,111 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CALLTREEDLG_H +#define CALLTREEDLG_H + +#include <qwidget.h> +#include <qlistview.h> +#include <calltreelayout.h> + +/** + * A multiple-view window showing function call information. + * The available views are: + * - Call graph, showing both calling and call functions + * - Called functions tree + * - Calling functions tree + * NOTE: This is class is now derived from QWidget instead of QDialog. This + * means that call-trees are independent windows, which can be maximised or + * minimised. + * @author Elad Lahav + */ +class CallTreeDlg : public CallTreeLayout +{ + Q_OBJECT + +public: + CallTreeDlg(QWidget* pParent = 0, const char* szName = 0); + ~CallTreeDlg(); + + void setRoot(const QString&); + bool load(const QString&, const QString&); + void store(const QString&); + + /** Returns Call Tree filename */ + QString getFileName() { return m_sFileName; } + +public slots: + virtual void show(); + +signals: + /** + * Emitted when the user makes a request to view the contents of a + * location in the source code. + * This can be the location of a call, the definition of a function, + * etc. + * @param sPath The full path of the file to show + * @param nLine The line number in this file + */ + void lineRequested(const QString& sPath, uint nLine); + + /** + * Emitted when the user closes the tree view. + */ + void closed(const CallTreeDlg*); + +protected: + virtual void closeEvent(QCloseEvent*); + +protected slots: + virtual void slotSaveClicked(); + virtual void slotZoomInClicked(); + virtual void slotZoomOutClicked(); + virtual void slotRotateClicked(); + virtual void slotPrefClicked(); + virtual void slotViewChanged(int); + +private: + /** The root function. */ + QString m_sRoot; + + /** A unique file name used for storing the call tree on a file. + The name is a combination of the root function and an incremented + index. */ + QString m_sFileName; + + /** The full path of the file on which the call tree was saved + (empty if this graph was never stored). */ + QString m_sFilePath; + + /** The view to show when the dialogue is first displayed. */ + int m_nDefView; + + /** An index for the generating unique file names. */ + static int s_nFileNameIndex; +}; + +#endif diff --git a/src/calltreelayout.ui b/src/calltreelayout.ui new file mode 100644 index 0000000..2562977 --- /dev/null +++ b/src/calltreelayout.ui @@ -0,0 +1,430 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CallTreeLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CallTreeLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>695</width> + <height>578</height> + </rect> + </property> + <property name="caption"> + <string>Call Graph</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_pViewGroup</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="title"> + <string></string> + </property> + <property name="exclusive"> + <bool>true</bool> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pGraphButton</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toggleButton"> + <bool>true</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Call Graph</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pCalledButton</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toggleButton"> + <bool>true</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Called Functions Tree</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pCallingButton</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="toggleButton"> + <bool>true</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Calling Functions Tree</string> + </property> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>VLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_pGraphGroup</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="title"> + <string></string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pSaveButton</cstring> + </property> + <property name="text"> + <string>a</string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Save As...</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pZoomInButton</cstring> + </property> + <property name="text"> + <string>a</string> + </property> + <property name="toggleButton"> + <bool>false</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Zoom In</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pZoomOutButton</cstring> + </property> + <property name="text"> + <string>a</string> + </property> + <property name="toggleButton"> + <bool>false</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Zoom Out</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pRotateButton</cstring> + </property> + <property name="text"> + <string>a</string> + </property> + <property name="toggleButton"> + <bool>false</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Rotate</string> + </property> + </widget> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_pPrefButton</cstring> + </property> + <property name="text"> + <string>a</string> + </property> + <property name="toggleButton"> + <bool>false</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Preferences</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>m_pStack</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="GraphWidget"> + <property name="name"> + <cstring>m_pGraphWidget</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>1</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="TreeWidget"> + <property name="name"> + <cstring>m_pCalledWidget</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>2</number> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="TreeWidget"> + <property name="name"> + <cstring>m_pCallingWidget</cstring> + </property> + </widget> + </vbox> + </widget> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_pHelpLabel</cstring> + </property> + <property name="text"> + <string>Help Message</string> + </property> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>GraphWidget</class> + <header location="local">graphwidget.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>TreeWidget</class> + <header location="local">treewidget.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>m_pPrefButton</sender> + <signal>clicked()</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotPrefClicked()</slot> + </connection> + <connection> + <sender>m_pRotateButton</sender> + <signal>clicked()</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotRotateClicked()</slot> + </connection> + <connection> + <sender>m_pZoomOutButton</sender> + <signal>clicked()</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotZoomOutClicked()</slot> + </connection> + <connection> + <sender>m_pZoomInButton</sender> + <signal>clicked()</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotZoomInClicked()</slot> + </connection> + <connection> + <sender>m_pSaveButton</sender> + <signal>clicked()</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotSaveClicked()</slot> + </connection> + <connection> + <sender>m_pViewGroup</sender> + <signal>clicked(int)</signal> + <receiver>CallTreeLayout</receiver> + <slot>slotViewChanged(int)</slot> + </connection> + <connection> + <sender>m_pViewGroup</sender> + <signal>clicked(int)</signal> + <receiver>m_pStack</receiver> + <slot>raiseWidget(int)</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotSaveClicked()</slot> + <slot access="protected">slotZoomInClicked()</slot> + <slot access="protected">slotZoomOutClicked()</slot> + <slot access="protected">slotRotateClicked()</slot> + <slot access="protected">slotViewChanged(int)</slot> + <slot access="protected">slotViewChanged(QWidget*)</slot> + <slot access="protected">slotPrefClicked()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>graphwidget.h</includehint> + <includehint>treewidget.h</includehint> + <includehint>treewidget.h</includehint> +</includehints> +</UI> diff --git a/src/calltreemanager.cpp b/src/calltreemanager.cpp new file mode 100644 index 0000000..5dc8e9f --- /dev/null +++ b/src/calltreemanager.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "calltreemanager.h" +#include "calltreedlg.h" +#include "projectmanager.h" + +/** + * Class constructor. + * @param pParent The widget to use as the parent of all Call Tree + * dialogues + */ +CallTreeManager::CallTreeManager(QWidget* pParent) : QObject(pParent) +{ + // Delete dialogue objects when they are removed from the list + m_lstDialogs.setAutoDelete(true); +} + +/** + * Class destructor. + */ +CallTreeManager::~CallTreeManager() +{ +} + +/** + * Saves all call trees into the project directory. + * @param sProjPath The project's directory + * @param slFiles Holds a list of saved file names, upon return + */ +void CallTreeManager::saveOpenDialogs(const QString& sProjPath, + QStringList& slFiles) +{ + CallTreeDlg *pDlg; + + // Iterate over the open dialogues + for (pDlg = m_lstDialogs.first(); pDlg != NULL; + pDlg = m_lstDialogs.next()) { + pDlg->store(sProjPath); + slFiles += pDlg->getFileName(); + } +} + +/** + * Loads all call trees according to the list of files + * @param sProjPath The project's directory + * @param slFiles A list of file names to open + */ +void CallTreeManager::loadOpenDialogs(const QString& sProjPath, + const QStringList& slFiles) +{ + QStringList::ConstIterator itr; + CallTreeDlg *pDlg; + + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) { + // Create a new dialogue for this file + pDlg = addDialog(); + + // Try to load the graph from the file + if (!pDlg->load(sProjPath, *itr)) { + m_lstDialogs.remove(pDlg); + continue; + } + + // Show the call tree + pDlg->show(); + } +} + +/** + * Creates a new Call Tree dialogue. + * @return The newly allocated dialogue object + */ +CallTreeDlg* CallTreeManager::addDialog() +{ + CallTreeDlg* pDlg; + + // Create a modeless call tree dialogue + pDlg = new CallTreeDlg(); + m_lstDialogs.append(pDlg); + + // Open an editor whenever a function name is double-clicked + connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), + this, SIGNAL(lineRequested(const QString&, uint))); + + // Track the closing of the call tree dialog + connect(pDlg, SIGNAL(closed(const CallTreeDlg*)), this, + SLOT(slotRemoveDialog(const CallTreeDlg*))); + + return pDlg; +} + +/** + * Closes all Call Tree dialogues. + */ +void CallTreeManager::closeAll() +{ + m_lstDialogs.clear(); +} + +/** + * Removes a Call Tree dialogue from the list of open Call Trees. + * This slot is connected to the closed() signal emitted by the dialogue. + * @param pDlg The dialogue to remove from the list + */ +void CallTreeManager::slotRemoveDialog(const CallTreeDlg* pDlg) +{ + m_lstDialogs.remove(pDlg); +} + +#include "calltreemanager.moc" + diff --git a/src/calltreemanager.h b/src/calltreemanager.h new file mode 100644 index 0000000..adb91e6 --- /dev/null +++ b/src/calltreemanager.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CALLTREEMANAGER_H +#define CALLTREEMANAGER_H + +#include <qwidget.h> +#include <qptrlist.h> + +class CallTreeDlg; + +/** + * Manages all call tree dialogs within the project. + * Responsible for saving/loading of the call tree dialogs. + * @author Albert Yosher + */ +class CallTreeManager : public QObject +{ + Q_OBJECT + +public: + CallTreeManager(QWidget*); + ~CallTreeManager(); + + void saveOpenDialogs(const QString&, QStringList&); + void loadOpenDialogs(const QString&, const QStringList&); + CallTreeDlg* addDialog(); + void closeAll(); + +signals: + /** + * Emitted when any call tree dialogue sends a request to view a location + * in the source code. + * @param sPath The full path of the file to show + * @param nLine The line number in this file + */ + void lineRequested(const QString& sPath, uint nLine); + +private: + /** The list of open call tree dialogues. */ + QPtrList<CallTreeDlg> m_lstDialogs; + +private slots: + void slotRemoveDialog(const CallTreeDlg*); +}; + +#endif diff --git a/src/configfrontend.cpp b/src/configfrontend.cpp new file mode 100644 index 0000000..27e4e32 --- /dev/null +++ b/src/configfrontend.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <kstandarddirs.h> +#include "configfrontend.h" + +/** + * Class constructor. + * @param bAutoDelete True to destroy the object when the process ends, + * false otherwise + */ +ConfigFrontend::ConfigFrontend(bool bAutoDelete) : + Frontend(1, bAutoDelete) +{ +} + +/** + * Class destructor. + */ +ConfigFrontend::~ConfigFrontend() +{ +} + +/** + * Executes the script using the "sh" shell. + * @param sCscopePath If given, overrides the automatic check for Cscope's + * path + * @param sCtagsPath If given, overrides the automatic check for Ctags' + * path + * @param sDotPath If given, overrides the automatic check for Dot's + * path + * @param bCscopeOptsOnly Only verify cscope's path and options + * @return true if successful, false otherwise + */ +bool ConfigFrontend::run(const QString& sCscopePath, + const QString& sCtagsPath, const QString& sDotPath, + bool bCscopeOptsOnly) +{ + QStringList slArgs; + KStandardDirs sd; + QString sScript; + + // Execute using the user's shell + setUseShell(true); + + // Find the configuration script + sScript = sd.findResource("data", "kscope/kscope_config"); + if (sScript.isEmpty()) + return false; + + // Set command line arguments + slArgs.append("sh"); + slArgs.append(sScript); + + if (bCscopeOptsOnly) + slArgs.append("-co"); + + // Initialise environment + setEnvironment("CSCOPE_PATH", sCscopePath); + setEnvironment("CTAGS_PATH", sCtagsPath); + setEnvironment("DOT_PATH", sDotPath); + + // Parser initialisation + m_delim = Newline; + m_nNextResult = CscopePath; + + if (!Frontend::run("sh", slArgs)) + return false; + + emit test(CscopePath); + return true; +} + +/** + * Handles tokens generated by the script. + * Each token represents a line in the script's output, and is the result of + * a different test. + * @param sToken The generated token + */ +Frontend::ParseResult ConfigFrontend::parseStdout(QString& sToken, + ParserDelim) +{ + uint nResult; + + // Store the type of test for which the given token in the result + nResult = m_nNextResult; + + // Determine the next test + switch (m_nNextResult) { + case CscopePath: + if (sToken == "ERROR") + m_nNextResult = CtagsPath; + else + m_nNextResult = CscopeVersion; + break; + + case CscopeVersion: + if (sToken == "ERROR") + m_nNextResult = CtagsPath; + else + m_nNextResult = CscopeVerbose; + break; + + case CscopeVerbose: + m_nNextResult = CscopeSlowPath; + break; + + case CscopeSlowPath: + m_nNextResult = CtagsPath; + break; + + case CtagsPath: + if (sToken == "ERROR") + m_nNextResult = END; + else + m_nNextResult = CtagsExub; + break; + + case CtagsExub: + if (sToken == "ERROR") + m_nNextResult = END; + else + m_nNextResult = DotPath; + break; + + case DotPath: + if (sToken == "ERROR") + m_nNextResult = END; + else + m_nNextResult = DotPlain; + break; + + case DotPlain: + m_nNextResult = END; + break; + + case END: + return DiscardToken; + } + + // Publish the result and the type of the next test + emit result(nResult, sToken); + emit test(m_nNextResult); + + return DiscardToken; +} + +#include "configfrontend.moc" diff --git a/src/configfrontend.h b/src/configfrontend.h new file mode 100644 index 0000000..df5e303 --- /dev/null +++ b/src/configfrontend.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CONFIGFRONTEND_H +#define CONFIGFRONTEND_H + +#include <frontend.h> + +/** + * Frontend to the kscope_config shell script. + * The script executes a set of tests and outputs their results. + * @author Elad Lahav + */ +class ConfigFrontend : public Frontend +{ + Q_OBJECT + +public: + ConfigFrontend(bool bAutoDelete = false); + ~ConfigFrontend(); + + bool run(const QString&, const QString&, const QString&, + bool bCscopeOptsOnly = false); + + /** + * The types of tests executed by the script. + */ + enum { CscopePath, CscopeVersion, CscopeVerbose, CscopeSlowPath, + CtagsPath, CtagsExub, DotPath, DotPlain, END }; + +signals: + /** + * Indicates that the script is now running a given test. + * @param nType The type of test being executed + */ + void test(uint nType); + + /** + * Called after a test has produced a result. + * @param nType The type of test executed + * @param sResult The obtained result + */ + void result(uint nType, const QString& sResult); + +protected: + virtual ParseResult parseStdout(QString&, ParserDelim); + +private: + /** The type of test whose result is expected next. */ + uint m_nNextResult; +}; + +#endif diff --git a/src/cscopefrontend.cpp b/src/cscopefrontend.cpp new file mode 100644 index 0000000..7c8f288 --- /dev/null +++ b/src/cscopefrontend.cpp @@ -0,0 +1,524 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <qtimer.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kglobalsettings.h> +#include "cscopefrontend.h" +#include "kscopeconfig.h" +#include "configfrontend.h" + +#define BUILD_STR "Building symbol database %d of %d" +#define SEARCH_STR "Search %d of %d" +#define INV_STR "Possible references retrieved %d of %d" +#define REGEXP_STR "Symbols matched %d of %d" +#define SEARCHEND_STR "%d lines" + +QString CscopeFrontend::s_sProjPath; +uint CscopeFrontend::s_nProjArgs; +uint CscopeFrontend::s_nSupArgs; + +/** + * Class constructor. + * @param bAutoDelete true to delete the object once the process has + * terminated, false otherwise + */ +CscopeFrontend::CscopeFrontend(bool bAutoDelete) : + Frontend(CSCOPE_RECORD_SIZE, bAutoDelete), + m_state(Unknown), + m_sErrMsg(""), + m_bRebuildOnExit(false) +{ +} + +/** + * Class destructor. + */ +CscopeFrontend::~CscopeFrontend() +{ +} + +/** + * Executes a Cscope process using the given command line arguments. + * The full path to the Cscope executable should be set in the "Path" key + * under the "Cscope" group. + * @param slArgs Command line arguments for Cscope + * @return true if successful, false otherwise + */ +bool CscopeFrontend::run(const QStringList& slArgs) +{ + QStringList slCmdLine; + + // Set the command line arguments + slCmdLine.append(Config().getCscopePath()); + slCmdLine += slArgs; + + // Use verbose mode, if supported + if (s_nSupArgs & VerboseOut) + slCmdLine << "-v"; + + // Project-specific options + if (s_nProjArgs & Kernel) + slCmdLine << "-k"; + if (s_nProjArgs & InvIndex) + slCmdLine << "-q"; + if (s_nProjArgs & NoCompression) + slCmdLine << "-c"; + if (s_nProjArgs & s_nSupArgs & SlowPathDef) + slCmdLine << "-D"; + + // Run a new process + if (!Frontend::run("cscope", slCmdLine, s_sProjPath)) { + emit aborted(); + return false; + } + + return true; +} + +/** + * Executes a Cscope query. + * A query is composed of a numeric type and a query text, which are written + * to the stndard input of the currently running Cscope process. + * @param nType The type of query to run + * @param sText The query's text + * @param bCase true for case-sensitive queries, false otherwise + * @param nMaxRecords The maximal number of records to return (abort if this + * number is exceeded) + */ +void CscopeFrontend::query(uint nType, const QString& sText, bool bCase, + uint nMaxRecords) +{ + QString sQuery; + QStringList slArgs; + + m_nMaxRecords = nMaxRecords; + + // Create the Cscope command line + slArgs.append(QString("-L") + QString::number(nType)); + slArgs.append(sText); + slArgs.append("-d"); + if (!bCase) + slArgs.append("-C"); + + run(slArgs); + + // Initialise stdout parsing + m_state = SearchSymbol; + m_delim = WSpace; + + emit progress(0, 1); +} + +/** + * Rebuilds the symbol database of the current project. + */ +void CscopeFrontend::rebuild() +{ + QStringList slArgs; + + // If a process is already running, kill it start a new one + if (isRunning()) { + m_bRebuildOnExit = true; + kill(); + return; + } + + // Run the database building process + slArgs.append("-b"); + run(slArgs); + + // Initialise output parsing + m_state = BuildStart; + m_delim = Newline; + + emit progress(0, 1); +} + +/** + * Sets default parameters for all CscopeFrontend projects based on the + * current project. + * @param sProjPath The full path of the project's directory + * @param nArgs Project-specific command-line arguments + */ +void CscopeFrontend::init(const QString& sProjPath, uint nArgs) +{ + s_sProjPath = sProjPath; + s_nProjArgs = nArgs; +} + +/** + * Stops a Cscope action. + */ +void CscopeFrontend::slotCancel() +{ + kill(); +} + +/** + * Parses the output of a Cscope process. + * Implements a state machine, where states correspond to the output of the + * controlled Cscope process. + * @param sToken The current token read (the token delimiter is determined + * by the current state) + * @return A value indicating the way this token should be treated: dropped, + * added to the token queue, or finishes a new record + */ +Frontend::ParseResult CscopeFrontend::parseStdout(QString& sToken, + ParserDelim /* ignored */) +{ + int nFiles, nTotal, nRecords; + ParseResult result = DiscardToken; + ParserState stPrev; + + // Remember previous state + stPrev = m_state; + + // Handle the token according to the current state + switch (m_state) { + case BuildStart: + if (sToken == "Building cross-reference...") { + m_state = BuildSymbol; + m_delim = WSpace; + } + else if (sToken == "Building inverted index...") { + emit buildInvIndex(); + } + + result = DiscardToken; + break; + + case BuildSymbol: + // A single angle bracket is the prefix of a progress indication, + // while double brackets is Cscope's prompt for a new query + if (sToken == ">") { + m_state = Building; + m_delim = Newline; + } + + result = DiscardToken; + break; + + case Building: + // Try to get building progress + if (sscanf(sToken.latin1(), BUILD_STR, &nFiles, &nTotal) == 2) { + emit progress(nFiles, nTotal); + + // Check for last progress message + if (nFiles == nTotal) { + m_state = BuildStart; + m_delim = Newline; + + result = DiscardToken; + break; + } + } + + // Wait for another progress line or the "ready" symbol + m_state = BuildSymbol; + m_delim = WSpace; + + result = DiscardToken; + break; + + case SearchSymbol: + // Check for more search progress, or the end of the search, + // designated by a line in the format of "cscope: X lines" + if (sToken == ">") { + m_state = Searching; + m_delim = Newline; + result = DiscardToken; + break; + } + else if (sToken == "cscope:") { + m_state = SearchEnd; + m_delim = Newline; + result = DiscardToken; + break; + } + + case File: + // Is this the first entry? If so, signal that the query is complete + if (stPrev != LineText) + emit progress(1, 1); + + // Treat the token as the name of the file in this record + m_state = Func; + result = AcceptToken; + break; + + case Searching: + // Try to get the search progress value (ignore other messages) + if ((sscanf(sToken.latin1(), SEARCH_STR, &nFiles, &nTotal) == 2) || + (sscanf(sToken.latin1(), INV_STR, &nFiles, &nTotal) == 2) || + (sscanf(sToken.latin1(), REGEXP_STR, &nFiles, &nTotal) == 2)) { + emit progress(nFiles, nTotal); + } + + m_state = SearchSymbol; + m_delim = WSpace; + result = DiscardToken; + break; + + case SearchEnd: + // Get the number of results found in this search + if ((sscanf(sToken.latin1(), SEARCHEND_STR, &nRecords) == 1) && + (m_nMaxRecords > 0) && + (nRecords > m_nMaxRecords)) { + result = Abort; + } + else { + m_state = File; + m_delim = WSpace; + result = DiscardToken; + } + + break; + + case Func: + // Treat the token as the name of the function in this record + if (sToken.toInt()) { + // In case of a global definition, there is no function name, and + // instead the line number is given immediately + m_state = LineText; + m_delim = Newline; + } + else { + // Not a number, it is the name of the function + m_state = Line; + } + + result = AcceptToken; + break; + + case Line: + // Treat the token as the line number in this record + m_state = LineText; + m_delim = Newline; + result = AcceptToken; + break; + + case LineText: + // Treat the token as the text of this record, and report a new + // record + m_state = File; + m_delim = WSpace; + result = RecordReady; + break; + + default: + // Do nothing (prevents a compilation warning for unused enum values) + break; + } + + return result; +} + +/** + * Handles Cscope messages sent to the standard error stream. + * @param sText The error message text + */ +void CscopeFrontend::parseStderr(const QString& sText) +{ + // Wait for a complete line to arrive + m_sErrMsg += sText; + if (!sText.endsWith("\n")) + return; + + // Display the error message + emit error(m_sErrMsg); + + // Line displayed, reset the text accumulator + m_sErrMsg = ""; +} + +/** + * Called when the underlying process exits. + * Checks if the rebuild flag was raised, and if so restarts the building + * process. + */ +void CscopeFrontend::finalize() +{ + // Reset the parser state machine + m_state = Unknown; + + // Restart the building process, if required + if (m_bRebuildOnExit) { + m_bRebuildOnExit = false; + rebuild(); + } +} + +/** + * Class constructor. + * @param pMainWidget The parent widget to use for the progress bar and + * label + */ +CscopeProgress::CscopeProgress(QWidget* pMainWidget) : QObject(), + m_pMainWidget(pMainWidget), + m_pProgressBar(NULL), + m_pLabel(NULL) +{ +} + +/** + * Class destructor. + */ +CscopeProgress::~CscopeProgress() +{ +} + +/** + * Displays query progress information. + * If the progress value is below the expected final value, a progress bar is + * used to show the advance of the query process. Otherwise, a label is + * displayed asking the user to wait ahile the query output is processed. + * @param nProgress The current progress value + * @param nTotal The expected final value + */ +void CscopeProgress::setProgress(int nProgress, int nTotal) +{ + // Was the final value is reached? + if (nProgress == nTotal) { + // Destroy the progress bar + if (m_pProgressBar != NULL) { + delete m_pProgressBar; + m_pProgressBar = NULL; + } + + // Show the "Please wait..." label + if (m_pLabel == NULL) { + m_pLabel = new QLabel(i18n("Processing query results, " + "please wait..."), m_pMainWidget); + m_pLabel->setFrameStyle(QFrame::Box | QFrame::Plain); + m_pLabel->setLineWidth(1); + m_pLabel->adjustSize(); + + m_pLabel->setPaletteBackgroundColor( + KGlobalSettings::highlightColor()); + m_pLabel->setPaletteForegroundColor( + KGlobalSettings::highlightedTextColor()); + + QTimer::singleShot(1000, this, SLOT(slotShowLabel())); + } + + return; + } + + // Create the progress bar, if it does not exist. + // Note that the progress bar will only be displayed one second after the + // first progress signal is received. Thus the bar will not be displayed + // on very short queries. + if (m_pProgressBar == NULL) { + m_pProgressBar = new QProgressBar(m_pMainWidget); + QTimer::singleShot(1000, this, SLOT(slotShowProgressBar())); + } + + // Set the current progress value + m_pProgressBar->setProgress(nProgress, nTotal); +} + +/** + * detsroys any progress widgets when the process is terminated. + */ +void CscopeProgress::finished() +{ + // Destroy the progress bar + if (m_pProgressBar != NULL) { + delete m_pProgressBar; + m_pProgressBar = NULL; + } + + // Destroy the label + if (m_pLabel != NULL) { + delete m_pLabel; + m_pLabel = NULL; + } +} + +/** + * Shows the progress bar. + * This slot is connected to a timer activated when the first progress signal + * is received. + */ +void CscopeProgress::slotShowProgressBar() +{ + if (m_pProgressBar != NULL) + m_pProgressBar->show(); +} + +/** + * Shows the "Please wait...". + * This slot is connected to a timer activated when the progress bar + * reaches its final value. + */ +void CscopeProgress::slotShowLabel() +{ + if (m_pLabel != NULL) + m_pLabel->show(); +} + +void CscopeVerifier::verify() +{ + ConfigFrontend* pConf; + + pConf = new ConfigFrontend(true); + connect(pConf, SIGNAL(result(uint, const QString&)), this, + SLOT(slotConfigResult(uint, const QString&))); + connect(pConf, SIGNAL(finished(uint)), this, SLOT(slotFinished())); + + pConf->run(Config().getCscopePath(), "", "", true); +} + +void CscopeVerifier::slotConfigResult(uint nType, const QString& sResult) +{ + switch (nType) { + case ConfigFrontend::CscopeVerbose: + if (sResult == "Yes") + m_nArgs |= CscopeFrontend::VerboseOut; + break; + + case ConfigFrontend::CscopeSlowPath: + if (sResult == "Yes") + m_nArgs |= CscopeFrontend::SlowPathDef; + + // If we got this far, then Cscope is configured properly + m_bResult = true; + break; + } +} + +void CscopeVerifier::slotFinished() +{ + emit done(m_bResult, m_nArgs); + delete this; +} + +#include "cscopefrontend.moc" diff --git a/src/cscopefrontend.h b/src/cscopefrontend.h new file mode 100644 index 0000000..2b2c569 --- /dev/null +++ b/src/cscopefrontend.h @@ -0,0 +1,186 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CSCOPEFRONTEND_H +#define CSCOPEFRONTEND_H + +#include <qstringlist.h> +#include <qprogressbar.h> +#include <qlabel.h> +#include "frontend.h" + +#define CSCOPE_RECORD_SIZE 4 + +/** + * Controls a Cscope process for the current project. + * This class creates a Cscope process, using the project's files for + * configuration. Once the process is running, KScope uses the query() method + * to initiate Cscope queries on the project's files. The queries' output is + * parsed into a set of records, each consisting of the following fields: + * - File name + * - Function name + * - Line number + * - The line's text + * These records are used to display the output in different windows, such as + * QueryWidget and CallTreeDlg. + * @author Elad Lahav + */ + +class CscopeFrontend : public Frontend +{ + Q_OBJECT + +public: + CscopeFrontend(bool bAutoDelete = false); + ~CscopeFrontend(); + + /** + * The available Cscope query types. + */ + enum QueryType { Reference = 0, Definition = 1, Called = 2, Calling = 3, + Text = 4, Pattern = 6, FileName = 7, Including = 8, None = 9 }; + + /** + * Options for running Cscope, used to construct the command line. + * Some of these options are global, while some are project specific. + */ + enum Options { VerboseOut = 0x01, SlowPathDef = 0x02, + Kernel = 0x04, InvIndex = 0x08, NoCompression = 0x10 }; + + void query(uint, const QString&, bool bCase = true, uint nMaxRecords = 0); + void rebuild(); + + static void init(const QString&, uint); + + /** + * @param nArgs The command-line arguments supported by the version of + * Cscope currently in use + */ + static void setSupArgs(uint nArgs) { s_nSupArgs = nArgs; } + +public slots: + void slotCancel(); + +signals: + /** + * Emitted when Cscope starts building the inverted index. + */ + void buildInvIndex(); + +protected: + virtual ParseResult parseStdout(QString&, ParserDelim); + virtual void parseStderr(const QString&); + virtual void finalize(); + +private: + /** + * The possible states of the parser state machine. + */ + enum ParserState { Unknown = 0, BuildStart, BuildSymbol, Building, + SearchSymbol, Searching, SearchEnd, File, Func, Line, LineText }; + + /** The current state of the parser state machine. */ + ParserState m_state; + + /** Accumulates text sent by Cscope to the standard error stream. */ + QString m_sErrMsg; + + /** If true, the rebuild process will be restarted when the process + exits. */ + bool m_bRebuildOnExit; + + /** The maximal number of records requested for the current query. + The process aborts if this number if reached. */ + int m_nMaxRecords; + + /** The full path of the directory holding the project files. */ + static QString s_sProjPath; + + /** Project-specific options for the command-line arguments. */ + static uint s_nProjArgs; + + /** The command line arguments supported by this version of Cscope. */ + static uint s_nSupArgs; + + bool run(const QStringList&); +}; + +/** + * Provides progress information on a Cscope query. + * Classes used to display query results can use this class to show a + * progress bar while a query is running, and a "Please Wait..." label while + * output is being processed. + * @author Elad Lahav + */ +class CscopeProgress : public QObject +{ + Q_OBJECT + +public: + CscopeProgress(QWidget*); + ~CscopeProgress(); + + void setProgress(int, int); + void finished(); + +private: + /** The parent widget for the progress bar and label. */ + QWidget* m_pMainWidget; + + /** A bar used to display query progress information. */ + QProgressBar* m_pProgressBar; + + /** A label used to display a "Please wait..." message. */ + QLabel* m_pLabel; + +private slots: + void slotShowProgressBar(); + void slotShowLabel(); +}; + +class CscopeVerifier : public QObject +{ + Q_OBJECT + +public: + CscopeVerifier() : m_bResult(false), m_nArgs(0) {} + + void verify(); + +signals: + void done(bool, uint); + +private: + bool m_bResult; + uint m_nArgs; + +private slots: + void slotConfigResult(uint, const QString&); + void slotFinished(); +}; + +#endif diff --git a/src/cscopemsgdlg.cpp b/src/cscopemsgdlg.cpp new file mode 100644 index 0000000..1bf6656 --- /dev/null +++ b/src/cscopemsgdlg.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtextedit.h> +#include <qpushbutton.h> +#include "cscopemsgdlg.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +CscopeMsgDlg::CscopeMsgDlg(QWidget* pParent, const char* szName) + : CscopeMsgLayout(pParent, szName, false, 0) +{ + // Hide the dialog when the "Hide" button is clicked + connect(m_pHideButton, SIGNAL(clicked()), this, SLOT(hide())); + + // Clear all messages when the "Clear" button is clicked + connect(m_pClearButton, SIGNAL(clicked()), m_pMsgText, SLOT(clear())); +} + +/** + * Class destructor. + */ +CscopeMsgDlg::~CscopeMsgDlg() +{ +} + +/** + * Appends a given message to the text box. + * After a new messsage is added, the dialog becomes visible. + * @param sText The text of the message to add + */ +void CscopeMsgDlg::addText(const QString& sText) +{ + m_pMsgText->append(sText); + show(); +} + +#include "cscopemsgdlg.moc" + diff --git a/src/cscopemsgdlg.h b/src/cscopemsgdlg.h new file mode 100644 index 0000000..0cd45cd --- /dev/null +++ b/src/cscopemsgdlg.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CSCOPEMSGDLG_H +#define CSCOPEMSGDLG_H + +#include "cscopemsglayout.h" + +/** + * Displays messages sent by Cscope to its standard error stream. + * @author Elad Lahav + */ +class CscopeMsgDlg : public CscopeMsgLayout +{ + Q_OBJECT + +public: + CscopeMsgDlg(QWidget* pParent = 0, const char* szName = 0); + ~CscopeMsgDlg(); + + void addText(const QString&); +}; + +#endif + diff --git a/src/cscopemsglayout.ui b/src/cscopemsglayout.ui new file mode 100644 index 0000000..1a6458d --- /dev/null +++ b/src/cscopemsglayout.ui @@ -0,0 +1,79 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>CscopeMsgLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CscopeMsgLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>451</height> + </rect> + </property> + <property name="caption"> + <string>Cscope Error Messages</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTextEdit"> + <property name="name"> + <cstring>m_pMsgText</cstring> + </property> + <property name="textFormat"> + <enum>PlainText</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>321</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pClearButton</cstring> + </property> + <property name="text"> + <string>Clear</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pHideButton</cstring> + </property> + <property name="text"> + <string>Hide</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/ctagsfrontend.cpp b/src/ctagsfrontend.cpp new file mode 100644 index 0000000..73f7519 --- /dev/null +++ b/src/ctagsfrontend.cpp @@ -0,0 +1,179 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kshell.h> +#include "ctagsfrontend.h" +#include "kscopeconfig.h" + +QStringList CtagsFrontend::s_slExtraArgs; + +/** + * Class constructor. + */ +CtagsFrontend::CtagsFrontend() : Frontend(CTAGS_RECORD_SIZE) +{ +} + +/** + * Class destructor. + */ +CtagsFrontend::~CtagsFrontend() +{ +} + +/** + * Executes a Ctags process on a source file. + * @param sFileName The full path to the source file + * @return true if successful, false otherwise + */ +bool CtagsFrontend::run(const QString& sFileName) +{ + QString sPath; + QStringList slArgs; + + // Make sure the executable exists + sPath = Config().getCtagsPath(); + + // Set the command line arguments + slArgs.append(sPath); + slArgs.append("--excmd=n"); + slArgs.append("-u"); // don't sort + slArgs.append("-f"); + slArgs.append("-"); + + // Per-project command-line arguments + slArgs += s_slExtraArgs; + + slArgs.append(sFileName); + + // Run a new process + if (!Frontend::run("ctags", slArgs)) + return false; + + // Initialize stdout parsing + m_state = Name; + m_delim = Tab; + + return true; +} + +/** + * Tests that the given file path leads to an executable. + * @param sPath The path to check + * @return true if the file in the given path exists and has executable + * permissions, false otherwise + */ +bool CtagsFrontend::verify(const QString& sPath) +{ + QFileInfo fi(sPath); + + if (!fi.exists() || !fi.isFile() || !fi.isExecutable() || + fi.fileName().find("ctags", 0, false) == -1) { + KMessageBox::error(0, i18n("Ctags cannot be found in the given " + "path")); + return false; + } + + return true; +} + +/** + * Turns the per-project string of additional arguments into a list of + * command-line arguments. + * @param sArgs The per-project command string + */ +void CtagsFrontend::setExtraArgs(const QString& sArgs) +{ + s_slExtraArgs = KShell::splitArgs(sArgs); +} + +/** + * Parses the output of a Ctags process. + * @param sToken The current token read (the token delimiter is determined + * by the current state) + * @param delim The delimiter that ends this token + * @return A value indicating the way this token should be treated: dropped, + * added to the token queue, or finishes a new record + */ +Frontend::ParseResult CtagsFrontend::parseStdout(QString& sToken, + ParserDelim delim) +{ + ParseResult result = DiscardToken; + + // Handle the token according to the current state + switch (m_state) { + case Name: + if (sToken.left(6) == "ctags:") { + m_state = Other; + m_delim = Newline; + break; + } + + m_state = File; + result = AcceptToken; + break; + + case File: + m_state = Line; + result = DiscardToken; + break; + + case Line: + sToken = sToken.left(sToken.length() - 2); + m_state = Type; + m_delim = All; + result = AcceptToken; + break; + + case Type: + if (delim == Newline) { + m_state = Name; + m_delim = Tab; + } + else { + m_state = Other; + m_delim = Newline; + } + + result = RecordReady; + break; + + case Other: + m_state = Name; + m_delim = Tab; + result = DiscardToken; + break; + + } + + return result; +} + +#include "ctagsfrontend.moc" diff --git a/src/ctagsfrontend.h b/src/ctagsfrontend.h new file mode 100644 index 0000000..3c0c452 --- /dev/null +++ b/src/ctagsfrontend.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CTAGSFRONTEND_H +#define CTAGSFRONTEND_H + +#include <frontend.h> + +#define CTAGS_RECORD_SIZE 3 + +/** + * Controls a Ctags process for an file in an EditorPage window. + * A new Ctags process is run each time the file in the editor window is + * loaded (including the initial load, and any subsequent ones which follow a + * 'save' operation.) + * The output of the process is parsed into a set of records, each composed of + * the following fields: + * - Tag type + * - Tag name + * - Line number + * The records are then displayed in the CtagsList widget that is attached to + * each EditorPage window. + * @author Elad Lahav + */ + +class CtagsFrontend : public Frontend +{ + Q_OBJECT + +public: + CtagsFrontend(); + ~CtagsFrontend(); + + bool run(const QString&); + + static bool verify(const QString&); + static void setExtraArgs(const QString&); + +protected: + virtual ParseResult parseStdout(QString&, ParserDelim); + +private: + /** State values for the parser state machine. */ + enum ParserState { Name = 0, File, Line, Type, Other }; + + /** The current state of the parser state machine. */ + ParserState m_state; + + /** Additional ommand-line arguments (per-project). */ + static QStringList s_slExtraArgs; +}; + +#endif diff --git a/src/ctagslist.cpp b/src/ctagslist.cpp new file mode 100644 index 0000000..687e9fb --- /dev/null +++ b/src/ctagslist.cpp @@ -0,0 +1,446 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qheader.h> +#include <klocale.h> +#include "ctagslist.h" +#include "kscopeconfig.h" +#include "kscopepixmaps.h" + +/** + * Defines a special list item for the tag list. + * This special definition allows the tag list to be sorted according to + * symbol line numbers. By default, all items are treated as text, hence the + * comparison of line numbers such as "123" and "24" sets "24" to be the + * larger item. By overriding the comparison function, this class allows for + * correct sorting. + * @author Elad Lahav + */ +class CtagsListItem : public QListViewItem +{ +public: + /** + * Class constructor. + * @param pParent The owning list view widget + * @param sName The name of the tag + * @param sLine The line in which the tag is defined + * @param sType The type of the tag + */ + CtagsListItem(QListView* pParent, QString sName, QString sLine, + QString sType) : QListViewItem(pParent, sName, sLine, sType), + m_nPendLine (sLine.toUInt()) {} + + /** + * Compares two tag list items, and determines their order. + * If comparison is based on a text-column, the default behaviour is + * used. Otherwise, the text is converted to unsigned integers, and then + * compared as numbers. + * @param pItem The item to compare against the local object + * @param nCol The column index by which to compare + * @param bAscend true if sorting in ascending order, false otherwise + * @return 0 if the items are equal, 1 if the local item is greater, -1 + * if the local item is lesser + */ + virtual int compare(QListViewItem* pItem, int nCol, bool bAscend) const { + if (nCol == 1) { + uint nLineCur, nLineOther; + int nResult; + + // Get the line numbers of each item + nLineCur = text(1).toUInt(); + nLineOther = pItem->text(1).toUInt(); + + // Compare the line numbers + nResult = nLineCur - nLineOther; + if (nResult == 0) + return 0; // Items are equal + else if (nResult > 0) + return 1; // The first item is greater + else + return -1; // The second item is greater + } + + // Use default comparison for text columns + return QListViewItem::compare(pItem, nCol, bAscend); + } + + /** + * @return The line number associated with this item + */ + inline uint getLine() { return m_nPendLine; } + +private: + /** The numeric value of the line number column of this item. */ + uint m_nPendLine; +}; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +CtagsList::CtagsList(QWidget* pParent, const char* szName) : + SearchList(0, pParent, szName), + m_arrLines(16), + m_nItems(0), + m_nCurItem(0), + m_bReady(false), + m_nCurLine(0), + m_nPendLine(0) +{ + m_pList->setShowSortIndicator(true); + connect(m_pList->header(), SIGNAL(clicked(int)), this, + SLOT(slotSortChanged(int))); + + // Determine the default sorting order + switch (Config().getCtagSortOrder()) { + case KScopeConfig::NameAsc: + m_pList->setSorting(0, true); + break; + + case KScopeConfig::NameDes: + m_pList->setSorting(0, false); + break; + + case KScopeConfig::LineAsc: + m_pList->setSorting(1, true); + break; + + case KScopeConfig::LineDes: + m_pList->setSorting(1, false); + break; + + case KScopeConfig::TypeAsc: + m_pList->setSorting(2, true); + break; + + case KScopeConfig::TypeDes: + m_pList->setSorting(2, false); + break; + } + + // Add the list columns + m_pList->addColumn(i18n("Name")); + m_pList->addColumn(i18n("Line")); + m_pList->addColumn(i18n("Type")); + m_pList->setColumnAlignment(1, Qt::AlignRight); + + // Set colours and font + applyPrefs(); +} + +/** + * Class destructor. + */ +CtagsList::~CtagsList() +{ +} + +/** + * Adds a Ctags output entry to the list. + * This slot is connected to the dataReady() signal of a CtagsFrontend object. + * @param pToken The first token in the entry + */ +void CtagsList::slotDataReady(FrontendToken* pToken) +{ + QString sName, sType, sLine; + CtagsListItem* pItem; + KScopePixmaps::PixName pix; + + // Get the name of the symbol + sName = pToken->getData(); + pToken = pToken->getNext(); + + // Get the line number + sLine = pToken->getData(); + pToken = pToken->getNext(); + + // Get the type of the symbol + sType = pToken->getData(); + pToken = pToken->getNext(); + + // Set the appropriate pixmap + switch (sType[0].latin1()) { + case 'f': + sType = i18n("Function"); + pix = KScopePixmaps::SymFunc; + break; + + case 'v': + sType = i18n("Variable"); + pix = KScopePixmaps::SymVar; + break; + + case 's': + sType = i18n("Struct"); + pix = KScopePixmaps::SymStruct; + break; + + case 'd': + sType = i18n("Macro"); + pix = KScopePixmaps::SymMacro; + break; + + case 'm': + sType = i18n("Member"); + pix = KScopePixmaps::SymMember; + break; + + case 'g': + sType = i18n("Enum"); + pix = KScopePixmaps::SymEnum; + break; + + case 'e': + sType = i18n("Enumerator"); + pix = KScopePixmaps::SymEnumerator; + break; + + case 't': + sType = i18n("Typedef"); + pix = KScopePixmaps::SymTypedef; + break; + + case 'l': + sType = i18n("Label"); + pix = KScopePixmaps::SymLabel; + break; + + case 'i': + sType = i18n("Include"); + pix = KScopePixmaps::SymInclude; + break; + + default: + sType = "Unknown"; + pix = KScopePixmaps::SymUnknown; + } + + // Add a new item to the list + pItem = new CtagsListItem(m_pList, sName, sLine, sType); + pItem->setPixmap(0, Pixmaps().getPixmap(pix)); + m_nItems++; + + // Resize the line array, if required + if (m_arrLines.size() < m_nItems) + m_arrLines.resize(m_nItems, QGArray::SpeedOptim); + + // Add the new item to the line array + m_arrLines[m_nItems - 1] = pItem; +} + +/** + * Handles the "resize" event, which occurs when the size of the widget + * changes. + * @param pEvent The event data + */ +void CtagsList::resizeEvent(QResizeEvent* pEvent) +{ + SearchList::resizeEvent(pEvent); + emit resized(); +} + +/** + * Emits the lineRequested() signal when a list item is selected. + * This function is called if either an item is double-clicked, or an item is + * highlighted and the ENTER key is pressed. + * @param pItem The selected list item + */ +void CtagsList::processItemSelected(QListViewItem* pItem) +{ + QString sLine; + + sLine = pItem->text(1); + emit lineRequested(sLine.toUInt()); +} + +/** + * Constructs a tool-tip for the given item. + * @param pItem The item for which a tip is required + * @param sTip The constructed tip string (on return) + * @return Always true + */ +bool CtagsList::getTip(QListViewItem* pItem, QString& sTip) +{ + sTip = QString("Type: <b>%1</b><br>Name: <b>%2</b><br>Line: <b>%3</b>"). + arg(pItem->text(2)).arg(pItem->text(0)).arg(pItem->text(1)); + return true; +} + +/** + * Sets the list's colours and font, according the user's preferences. + */ +void CtagsList::applyPrefs() +{ + // Apply colour settings + m_pList->setPaletteBackgroundColor(Config().getColor( + KScopeConfig::TagListBack)); + m_pList->setPaletteForegroundColor(Config().getColor( + KScopeConfig::TagListFore)); + m_pList->setFont(Config().getFont(KScopeConfig::TagList)); +} + +/** + * Selects the symbol that dominates the given line in the source file. + * @param nLine The requested line + */ +void CtagsList::gotoLine(uint nLine) +{ + CtagsListItem* pItem; + int nFrom, nTo, nItem, nDiff; + + // Wait until Ctags finishes + if (!m_bReady) { + m_nPendLine = nLine; + return; + } + + // Do nothing if no tags are available + if (m_nItems == 0) + return; + + // Calculate the difference from the current line + nDiff = (int)(nLine - m_nCurLine); + m_nCurLine = nLine; + + // In most cases, all the user does is move to the next or prevuious lines + // Handle these simple cases first + if (nDiff == 1) { + if ((m_nCurItem < m_nItems - 1) && + (m_arrLines[m_nCurItem + 1]->getLine() == nLine)) { + m_nCurItem++; + } + else { + return; // New line corresponds to the same tag + } + } + else if (nDiff == -1) { + if ((m_nCurItem > 0) && + (m_arrLines[m_nCurItem]->getLine() > nLine)) { + m_nCurItem--; + } + else { + return; // New line corresponds to the same tag + } + } + else { + // Initialise binary search + nFrom = 0; + nTo = m_nItems - 1; + m_nCurItem = 0; // use the first item if nothing else works + + // Perform a binary search + // This algorithm finds the greatest line that is smaller or equal to + // the requested line + do { + nItem = (nFrom + nTo) / 2; + pItem = m_arrLines[nItem]; + + if (pItem->getLine() == nLine) { + m_nCurItem = nItem; + break; + } + else if (nLine > pItem->getLine()) { + m_nCurItem = nItem; + nFrom = nItem + 1; + } + else { + nTo = nItem - 1; + } + } while (nFrom <= nTo); + } + + // Mark the selected item + pItem = m_arrLines[m_nCurItem]; + m_pList->setSelected(pItem, true); + m_pList->ensureItemVisible(pItem); + + m_nPendLine = 0; +} + +/** + * Deletes all items in the list. + */ +void CtagsList::clear() +{ + m_pList->clear(); + m_nItems = 0; + m_nCurItem = 0; + m_nCurLine = 0; + m_nPendLine = 0; + m_bReady = false; +} + +/** + * Indicates Ctags has finished processing the current file. + * If a goto operation has been scheduled, it is processed. + * @param nRecords The number of records generated by Ctags + */ +void CtagsList::slotCtagsFinished(uint nRecords) +{ + if (nRecords) { + m_bReady = true; + if (m_nPendLine) + gotoLine(m_nPendLine); + } +} + +/** + * Determines the new sort order in the tags list. + * This slot is connected to the clicked() signal of the tag list's header. + * @param nSection Identifies the column whose header button was clicked. + */ +void CtagsList::slotSortChanged(int nSection) +{ + Qt::SortOrder order; + + // Determine whether the new order is ascending or descending + order = m_pList->sortOrder(); + + // Translate the section number into the order constant + switch (nSection) { + case 0: + // Sort by name + Config().setCtagSortOrder(order == Qt::Ascending ? + KScopeConfig::NameAsc : KScopeConfig::NameDes); + break; + + case 1: + // Sort by line + Config().setCtagSortOrder(order == Qt::Ascending ? + KScopeConfig::LineAsc : KScopeConfig::LineDes); + break; + + case 2: + // Sort by type + Config().setCtagSortOrder(order == Qt::Ascending ? + KScopeConfig::TypeAsc : KScopeConfig::TypeDes); + break; + } +} + +#include "ctagslist.moc" diff --git a/src/ctagslist.h b/src/ctagslist.h new file mode 100644 index 0000000..4d318cc --- /dev/null +++ b/src/ctagslist.h @@ -0,0 +1,108 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef CTAGSLIST_H +#define CTAGSLIST_H + +#include <qwidget.h> +#include <qpixmap.h> +#include <qmemarray.h> +#include "searchlist.h" +#include "frontend.h" + +class CtagsListItem; +class CtagsToolTip; + +/** + * Displays a list of tags for a source file. + * The list is embedded inside an editor page. Whenever a new document is + * opened in that editor, or the current document is changed and saved, the + * source file is re-scanned for tags, and the results are displayed in this + * list. + * @author Elad Lahav + */ + +class CtagsList : public SearchList +{ + Q_OBJECT + +public: + CtagsList(QWidget* pParent = 0, const char* szName = 0); + ~CtagsList(); + + void applyPrefs(); + void gotoLine(uint); + void clear(); + + virtual bool getTip(QListViewItem*, QString&); + +public slots: + void slotDataReady(FrontendToken*); + void slotCtagsFinished(uint); + +signals: + /** + * Emitted when the size of the list is changed (usually as the result + * of moving the separator between the list and the editor.) + */ + void resized(); + + /** + * Emitted when the user selects a tag item from the list. + * @param nLine The line number associated with the selected tag + */ + void lineRequested(uint nLine); + +protected: + virtual void resizeEvent(QResizeEvent*); + virtual void processItemSelected(QListViewItem*); + +private: + /** An array of pointers to the tag list items, sorted by the line + number. */ + QMemArray<CtagsListItem*> m_arrLines; + + /** The number of items in the tag list. */ + uint m_nItems; + + /** The last item selected by gotoLine(). */ + uint m_nCurItem; + + /** This value is set to 'false' while the Ctags process is running. */ + bool m_bReady; + + /** The current line number. */ + uint m_nCurLine; + + /** Stores the requested line number during Ctags operation. */ + uint m_nPendLine; + +private slots: + void slotSortChanged(int); +}; + +#endif diff --git a/src/dirscanner.cpp b/src/dirscanner.cpp new file mode 100644 index 0000000..517237e --- /dev/null +++ b/src/dirscanner.cpp @@ -0,0 +1,164 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qapplication.h> +#include "dirscanner.h" + +/** + * Class constructor. + * @param nFiles The number of files scanned since the previous event + * @param bFinished true if all files were scanned, false otherwise + */ +DirScanEvent::DirScanEvent(int nFiles, bool bFinished) + : QCustomEvent(EventId), + m_nFiles(nFiles), + m_bFinished(bFinished) +{ +} + +/** + * Class constructor. + * @param pEventReceiver Pointer to an object to receive DirScanEvent + * updates + * @param pDicFiles Pointer to a map of current project files (to + avoid duplication) + */ +DirScanner::DirScanner(QObject* pEventReceiver, + QDict<QListViewItem>* pDicFiles) : QThread(), + m_pEventReceiver(pEventReceiver), + m_pDicFiles(pDicFiles) +{ +} + +/** + * Class destructor. + */ +DirScanner::~DirScanner() +{ +} + +/** + * Begins a new search for source files. + * Invokes the search thread on a given directory. The search may be either + * recursive (i.e., the search will descend to each sub-directory) or flat + * (will search the given directory only.) + * @param sDir The name of the directory to search + * @param sNameFilter Defines the search pattern + * @param bRecursive true to descend into sub-dorectories, false otherwise + */ +void DirScanner::start(const QString& sDir, const QString& sNameFilter, + bool bRecursive) +{ + // Initialise the search parameters + m_dir = QDir(sDir); + m_sNameFilter = sNameFilter; + m_bCancel = false; + m_bRecursive = bRecursive; + m_slFiles.clear(); + + // Invoke the thread + QThread::start(); +} + +/** + * Begins a scan of files on the directory associated with this object. + * Note that this function is synchronous: it returns when the scan ends. + */ +void DirScanner::run() +{ + int nFiles; + + nFiles = scanDir(m_dir); + QApplication::postEvent(m_pEventReceiver, + new DirScanEvent(nFiles, true)); + + m_setScanned.clear(); +} + +/** + * Recursively scans a directory for a files matching the current filter. + * @param dir A directory object set to the folder from which files are + * added + * @return The total number of files added + */ +int DirScanner::scanDir(QDir& dir) +{ + QString sCanon; + QStringList slDirFiles, slDirs; + QStringList::const_iterator itr; + QString sFile; + int nFiles = 0; + + if (m_bCancel) + return -1; + + // Make sure this directory has not been previously visited (e.g., through a + // symbolic link) + sCanon = dir.canonicalPath(); + if (m_setScanned.exists(sCanon)) + return 0; + + m_setScanned.insert(sCanon); + + // Add all files in this directory + slDirFiles = dir.entryList(m_sNameFilter, QDir::Files); + for (itr = slDirFiles.begin(); itr != slDirFiles.end(); ++itr) { + sFile = dir.absPath() + "/" + *itr; + + // Make sure an entry for this file does not exist + if (m_pDicFiles->find(sFile) == NULL) { + m_slFiles.append(sFile); + nFiles++; + } + } + + QApplication::postEvent(m_pEventReceiver, + new DirScanEvent(nFiles, false)); + + // Recurse into sub-directories, if requested + if (!m_bRecursive) + return nFiles; + + slDirs = dir.entryList(QDir::Dirs); + + // Iterate the list of sub-directories + for (itr = slDirs.begin(); itr != slDirs.end(); ++itr) { + if (m_bCancel) + return -1; + + // Skip the "." and ".." directories + if (*itr == "." || *itr == "..") + continue; + + // Add the files in each sub-directory + QDir dirSub(dir); + if (dirSub.cd(*itr)) + nFiles += scanDir(dirSub); + } + + return nFiles; +} diff --git a/src/dirscanner.h b/src/dirscanner.h new file mode 100644 index 0000000..b25fc2d --- /dev/null +++ b/src/dirscanner.h @@ -0,0 +1,144 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef DIRSCANNER_H +#define DIRSCANNER_H + +#include <qobject.h> +#include <qevent.h> +#include <qthread.h> +#include <qdir.h> +#include <qstringlist.h> +#include <qdict.h> +#include <qlistview.h> + +class DirScanner; + +/** + * Defines a new event that can be used to pass progress information from the + * dir scanning thread to the main application thread. + * @author Elad Lahav + */ +class DirScanEvent : public QCustomEvent +{ +public: + /** The event's unique ID. */ + enum { EventId = 6924 }; + + DirScanEvent(int, bool); + + /** The number of files already scanned. */ + int m_nFiles; + + /** True if the dir scanning thread has finished, false otherwise. */ + bool m_bFinished; +}; + +/** + * A set of unique strings. + * Qt3 does not have a set class, so this is a simple implementation based on + * a QDict of dummy int pointers. + * @author Elad Lahav + */ +class StringSet : public QDict<int> +{ +public: + StringSet() : QDict<int>() {} + + void insert(const QString& sItem) { + static int nDummy = 0; + QDict<int>::insert(sItem, &nDummy); + } + + bool exists(const QString& sItem) { + return find(sItem) != NULL; + } +}; + +/** + * Scans a directory for files matching a given pattern, using a separate thread. + * @author Elad Lahav + */ +class DirScanner : public QThread +{ +public: + DirScanner(QObject*, QDict<QListViewItem>*); + ~DirScanner(); + + void start(const QString&, const QString&, bool); + + /** + * @return The list of files scanned by this thread. + */ + const QStringList& getFiles() { return m_slFiles; } + + /** + * Stops a scanning process, by setting the object's cancel flag. + */ + void cancel() { m_bCancel = true; } + + /** + * @return true if the user has cancelled the process, false otherwise + */ + bool wasCancelled() { return m_bCancel; } + +protected: + virtual void run(); + +private: + /** Pointer to an object that receives the scanner update events. */ + QObject* m_pEventReceiver; + + /** Currently scanned directory. */ + QDir m_dir; + + /** + * A set of already-scanned directories (prevents infinite loops in case + * of cyclic symbolic links in the scanned file system). + */ + StringSet m_setScanned; + + /** Pointer to a list of files indexed by the file path (used to identify + files that should not appear in the scan results.) */ + QDict<QListViewItem>* m_pDicFiles; + + /** Regular expression for scanning source files. */ + QString m_sNameFilter; + + /** The list of scanned file paths. */ + QStringList m_slFiles; + + /** A cancellation flag. Stops the scanning process when raised. */ + bool m_bCancel; + + /** true to descend to child directories, false otherwise. */ + bool m_bRecursive; + + int scanDir(QDir&); +}; + +#endif diff --git a/src/dotfrontend.cpp b/src/dotfrontend.cpp new file mode 100644 index 0000000..e0cfbed --- /dev/null +++ b/src/dotfrontend.cpp @@ -0,0 +1,297 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <qpaintdevicemetrics.h> +#include <kmessagebox.h> +#include <klocale.h> +#include "dotfrontend.h" +#include "graphwidget.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pGraph The graph widget on which to draw the output + */ +DotFrontend::DotFrontend(GraphWidget* pGraph) : Frontend(1), + m_pGraph(pGraph) +{ +} + +/** + * Class destructor. + */ +DotFrontend::~DotFrontend() +{ +} + +/** + * Executes dot on the goven input file. + * @param sFile The path to a temporary file holding the graph's + * description + * @return true if successful, false otherwise + */ +bool DotFrontend::run(const QString& sFile) +{ + QString sPath; + QStringList slArgs; + QPaintDeviceMetrics pdm(m_pGraph); + + // Set the horizontal and vertical DPI values + m_dDpiX = (double)pdm.logicalDpiX(); + m_dDpiY = (double)pdm.logicalDpiY(); + + // Make sure the executable exists + sPath = Config().getDotPath(); + + // Set the command line arguments + slArgs.append(sPath); + slArgs.append("-Tplain"); + slArgs.append(sFile); + + // Run a new process + if (!Frontend::run("dot", slArgs)) + return false; + + // Initialize stdout parsing + m_state = Graph; + m_delim = All; + + return true; +} + +/** + * Tests that the given file path leads to an executable. + * @param sPath The path to check + * @return true if the file in the given path exists and has executable + * permissions, false otherwise + */ +bool DotFrontend::verify(const QString& sPath) +{ + QFileInfo fi(sPath); + + if (!fi.exists() || !fi.isFile() || !fi.isExecutable() || + fi.fileName() != "dot") { + KMessageBox::error(0, i18n("Dot cannot be found in the given " + "path")); + return false; + } + + return true; +} + +#define PAD 5 + +/** + * Parses the output of a Dot process. + * @param sToken The current token read (the token delimiter is determined + * by the current state) + * @param delim The delimiter that ends this token + * @return A value indicating the way this token should be treated: dropped, + * added to the token queue, or finishes a new record + */ +Frontend::ParseResult DotFrontend::parseStdout(QString& sToken, + ParserDelim delim) +{ + static int nWidth, nHeight, nXpos, nYpos, nCurveSize, nCurveCount; + static QPointArray arrCurve; + static QString sNode, sEdgeHead, sEdgeTail; + ParseResult result = DiscardToken; + double dVal; + bool bOK; + + // Handle the token according to the current state + switch (m_state) { + case Graph: + if (sToken == "graph") + m_state = GraphScale; + break; + + case GraphScale: + sToken.toDouble(&bOK); + if (bOK) + m_state = GraphWidth; + break; + + case GraphWidth: + // Read and transform the graph's width + dVal = sToken.toDouble(&bOK); + if (bOK) { + nWidth = (int)(dVal * m_dDpiX) + (PAD * 2); + m_state = GraphHeight; + } + break; + + case GraphHeight: + // Read and transform the graph's height + dVal = sToken.toDouble(&bOK); + if (bOK) { + nHeight = (int)(dVal * m_dDpiY) + (PAD * 2); + + // Set the graph's size + m_pGraph->resize(nWidth, nHeight); + + m_state = NodeEdgeStop; + } + break; + + case NodeEdgeStop: + // "node" starts a new node + // "edge" starts a new edge + // "stop" ends this graph + if (sToken == "node") { + m_state = NodeName; + } + else if (sToken == "edge") { + m_state = EdgeHead; + } + else if (sToken == "stop") { + m_state = Graph; + } + break; + + case NodeName: + // Get a node's name + sNode = sToken; + m_state = NodeCentreX; + break; + + case NodeCentreX: + // Read and transform the node's centre location (X coordinate) + dVal = sToken.toDouble(&bOK); + if (bOK) { + nXpos = (int)(dVal * m_dDpiX) + PAD; + m_state = NodeCentreY; + } + break; + + case NodeCentreY: + // Read and transform the node's centre location (Y coordinate) + dVal = sToken.toDouble(&bOK); + if (bOK) { + nYpos = (int)(dVal * m_dDpiY) + PAD; + m_state = NodeWidth; + } + break; + + case NodeWidth: + // Read and transform the node's width + dVal = sToken.toDouble(&bOK); + if (bOK) { + nWidth = (int)(dVal * m_dDpiX); + m_state = NodeHeight; + } + break; + + case NodeHeight: + // Read and transform the node's height + dVal = sToken.toDouble(&bOK); + if (bOK) { + nHeight = (int)(dVal * m_dDpiY); + + // Create the bounding rectangle of the node + QRect rect; + rect.setX(nXpos - (nWidth / 2)); + rect.setY(nYpos - (nHeight / 2)); + rect.setWidth(nWidth); + rect.setHeight(nHeight); + + // Draw the node + m_pGraph->drawNode(sNode, rect); + + m_state = EndNodeEdge; + } + break; + + case EdgeHead: + // Get the edge's head node + sEdgeHead = sToken; + m_state = EdgeTail; + break; + + case EdgeTail: + // Get the edge's tail node + sEdgeTail = sToken; + m_state = EdgeCurveSize; + break; + + case EdgeCurveSize: + // Get the number of control points in the edge's spline + nCurveSize = sToken.toInt(&bOK); + if (bOK) { + arrCurve.resize(nCurveSize); + nCurveCount = 0; + m_state = EdgeCurveX; + } + break; + + case EdgeCurveX: + // Read and a control point (X coordinate) + dVal = sToken.toDouble(&bOK); + if (bOK) { + nXpos = (int)(dVal * m_dDpiX) + PAD; + m_state = EdgeCurveY; + } + break; + + case EdgeCurveY: + // Read and a control point (Y coordinate) + dVal = sToken.toDouble(&bOK); + if (bOK) { + nYpos = (int)(dVal * m_dDpiY) + PAD; + + // Add the control point to the spline array + arrCurve.setPoint(nCurveCount++, nXpos, nYpos); + + // Check if this is the last control point + if (nCurveCount == nCurveSize) { + // Draw the edge + m_pGraph->drawEdge(sEdgeHead, sEdgeTail, arrCurve); + + // Must detach from contents since a QPointArray shares data + arrCurve.detach(); + + m_state = EndNodeEdge; + } + else { + // Another control point available + m_state = EdgeCurveX; + } + } + break; + + case EndNodeEdge: + // Discard everything else on a node or edge line + if (delim == Newline) + m_state = NodeEdgeStop; + break; + } + + return result; +} + +#include "dotfrontend.moc" diff --git a/src/dotfrontend.h b/src/dotfrontend.h new file mode 100644 index 0000000..24f14f0 --- /dev/null +++ b/src/dotfrontend.h @@ -0,0 +1,76 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ +#ifndef DOTFRONTEND_H +#define DOTFRONTEND_H + +#include <frontend.h> +#include <qpointarray.h> + +class GraphWidget; + +/** + * Front-end for executing graphviz's command-line tool. + * This tool accepts the description of a graph in the 'dot' language, and + * outputs a set of drawing instructions for the graph. + * @author Elad Lahav + */ +class DotFrontend : public Frontend +{ + Q_OBJECT + +public: + DotFrontend(GraphWidget*); + ~DotFrontend(); + + bool run(const QString&); + + static bool verify(const QString&); + +protected: + virtual ParseResult parseStdout(QString&, ParserDelim); + +private: + /** The owner graph widget on which to draw. */ + GraphWidget* m_pGraph; + + /** State values for the parser state machine. */ + enum ParserState { Graph, GraphScale, GraphWidth, GraphHeight, + NodeEdgeStop, NodeName, NodeCentreX, NodeCentreY, NodeWidth, NodeHeight, + EdgeHead, EdgeTail, EdgeCurveSize, EdgeCurveX, EdgeCurveY, + EndNodeEdge }; + + /** The current state of the parser state machine. */ + ParserState m_state; + + /** The horizontal DPI value of the graph widget. */ + double m_dDpiX; + + /** The vertical DPI value of the graph widget. */ + double m_dDpiY; +}; + +#endif diff --git a/src/dotparse.ypp b/src/dotparse.ypp new file mode 100644 index 0000000..f21b9e3 --- /dev/null +++ b/src/dotparse.ypp @@ -0,0 +1,234 @@ +/* dot.y */ + +%{ +#include <qdict.h> +#include <qptrstack.h> +#include <qlistview.h> +#include "calltreedlg.h" +#include "graphwidget.h" +#include "treewidget.h" +#include "encoder.h" + +extern FILE* yyin; +int yylex(); +void yyinit(CallTreeDlg*, FILE*, Encoder*); +void yyerror(const char*); + +static QMap<QString, QString> s_pMapAttr; +static QStack<QListViewItem> s_pParentStack; +static QListView* s_pTree; + +static GraphWidget* s_pGraph; +static TreeWidget* s_pCallTree; +static TreeWidget* s_pCallingTree; +static Encoder* s_pEncoder; + +// Avoid compiler warnings +#define YYENABLE_NLS 0 +#ifndef YYLTYPE_IS_TRIVIAL +#define YYLTYPE_IS_TRIVIAL 0 +#endif +%} + +%union { + QString* pText; +} + +%token GRAPH DIGRAPH NODE NAME STRING NUMBER DIR_EDGE UNDIR_EDGE +%token CALL_TREE CALLING_TREE +%type <pText> NAME STRING NUMBER attr_val + +%start file + +%% + +file + : call_tree calling_tree graph + +graph + : graph_type NAME '{' graph_desc_list '}' { delete $2; } + ; + +graph_type + : GRAPH + | DIGRAPH + ; + +graph_desc_list + : + | graph_desc_entry graph_desc_list + ; + +graph_desc_entry + : def_node_attr + | graph_attr + | node_record + | edge_record + ; + +def_node_attr + : NODE attributes ';' + ; + +graph_attr + : GRAPH attributes ';' + { + if (s_pMapAttr.find("kscope_zoom") != s_pMapAttr.end()) + s_pGraph->setZoom(s_pMapAttr["kscope_zoom"].toDouble()); + } + ; + +node_record + : NAME attributes ';' + { + s_pGraph->addNode(*$1); + delete $1; + s_pMapAttr.clear(); + } + ; + +edge_record + : NAME edge_type NAME attributes ';' + { + GraphWidget::CallData cd; + + cd.m_sCaller = *$1; + cd.m_sCallee = *$3; + cd.m_sFile = s_pMapAttr["kscope_file"]; + cd.m_sLine = s_pMapAttr["kscope_line"]; + cd.m_sText = s_pEncoder->decode(s_pMapAttr["kscope_text"]); + s_pGraph->addCall(cd); + + delete $1; + delete $3; + s_pMapAttr.clear(); + } + ; + +edge_type + : DIR_EDGE + | UNDIR_EDGE + ; + +attributes + : + | '[' attr_list ']' + ; + +attr_list + : + | non_empty_attr_list + ; + +non_empty_attr_list + : attr + | attr ',' attr_list + ; + +attr + : NAME '=' attr_val + { + s_pMapAttr.insert(*$1, *$3); + delete $1; + delete $3; + } + ; + +attr_val + : NAME + | STRING + | NUMBER + ; + +call_tree + : call_tree_prepare '{' root_node '}' + ; + +call_tree_prepare + : CALL_TREE { s_pTree = s_pCallTree; } + ; + +calling_tree + : calling_tree_prepare '{' root_node '}' + ; + +calling_tree_prepare + : CALLING_TREE { s_pTree = s_pCallingTree; } + ; + +root_node + : root_tree_node '{' child_list '}' + { + QListViewItem* pItem; + + pItem = s_pParentStack.pop(); + if (pItem->firstChild() != NULL) + pItem->setOpen(true); + } + ; + +root_tree_node + : NAME + { + QListViewItem* pItem; + + pItem = new QListViewItem(s_pTree, *$1); + s_pParentStack.push(pItem); + delete $1; + } + ; + +child_list + : + | child_node child_list + ; + +child_node + : tree_node tree_attributes '{' child_list '}' + { + QListViewItem* pItem; + + pItem = s_pParentStack.pop(); + if (pItem->firstChild() != NULL) + pItem->setOpen(true); + } + ; + +tree_node + : NAME + { + QListViewItem* pItem; + + pItem = new QListViewItem(s_pParentStack.top(), *$1); + s_pParentStack.push(pItem); + delete $1; + } + ; + +tree_attributes + : attributes + { + QListViewItem* pItem; + + pItem = s_pParentStack.top(); + pItem->setText(1, s_pMapAttr["kscope_file"]); + pItem->setText(2, s_pMapAttr["kscope_line"]); + pItem->setText(3, s_pEncoder->decode(s_pMapAttr["kscope_text"])); + } + ; + +%% + +void yyinit(CallTreeDlg* pDlg, FILE* pFile, Encoder* pEnc) +{ + yyin = pFile; + s_pCallTree = pDlg->m_pCalledWidget; + s_pCallingTree = pDlg->m_pCallingWidget; + s_pGraph = pDlg->m_pGraphWidget; + s_pEncoder = pEnc; +} + +void yyerror(const char* szError) +{ + fprintf(stderr, "%s\n", szError); +} diff --git a/src/dotscan.lpp b/src/dotscan.lpp new file mode 100644 index 0000000..0667d33 --- /dev/null +++ b/src/dotscan.lpp @@ -0,0 +1,36 @@ +/* dot.l */ + +%{ +#include <qstring.h> +#include "dotparse.h" +%} + +%option noyywrap + +name [a-zA-Z_][a-zA-Z0-9_]* +string \"(\\.|[^\"])*\" +space [ \t\n]+ +number [1-9][0-9]* +float [0-9]*\.[0-9]+ + +%% + +"graph" return GRAPH; +"digraph" return DIGRAPH; +"calltree" return CALL_TREE; +"callingtree" return CALLING_TREE; +"node" return NODE; +"->" return DIR_EDGE; +"--" return UNDIR_EDGE; +{name} { yylval.pText = new QString(yytext); return NAME; } +{string} { + QString str = &yytext[1]; + yylval.pText = new QString(str.left(yyleng - 2)); + return STRING; + } +{number} { yylval.pText = new QString(yytext); return NUMBER; } +{float} { yylval.pText = new QString(yytext); return NUMBER; } +{space} ; +. return yytext[0]; + +%% diff --git a/src/editormanager.cpp b/src/editormanager.cpp new file mode 100644 index 0000000..253bf6c --- /dev/null +++ b/src/editormanager.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <ktexteditor/editorchooser.h> +#include <kate/document.h> +#include "editormanager.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +EditorManager::EditorManager(QWidget* pParent, const char* szName) : + KParts::PartManager(pParent, szName) +{ + applyPrefs(); +} + +/** + * Class destructor. + */ +EditorManager::~EditorManager() +{ +} + +/** + * Creates a new document part. + * @return A pointer to the new document + */ +KTextEditor::Document* EditorManager::add() +{ + KTextEditor::Document* pDoc; + + // Create the document + pDoc = KTextEditor::EditorChooser::createDocument(this); + addPart(pDoc); + + return pDoc; +} + +/** + * Deletes a document part. + * @param pDoc The document to remove + */ +void EditorManager::remove(KTextEditor::Document* pDoc) +{ + removePart(pDoc); + delete pDoc; +} + +/** + * Applies the user preferences. + * Determines if Kate warnings are displayed in case the currently edited + * file is modified outside KScope. + * NOTE: This behaviour is determined by a static function, which is why this + * code appears here, rather then for every EditorPage object. + */ +void EditorManager::applyPrefs() +{ + Kate::Document::setFileChangedDialogsActivated( + Config().getWarnModifiedOnDisk()); +} + +#include "editormanager.moc" diff --git a/src/editormanager.h b/src/editormanager.h new file mode 100644 index 0000000..413ffed --- /dev/null +++ b/src/editormanager.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef EDITORMANAGER_H +#define EDITORMANAGER_H + +#include <qwidget.h> +#include <kparts/partmanager.h> +#include <klibloader.h> +#include <ktexteditor/document.h> + +/** + * Creates text editor parts, used to open source files. + * The EditorManager is responsible for creating parts, and managing their + * GUI integration. + * @author Elad Lahav + */ + +class EditorManager : public KParts::PartManager +{ + Q_OBJECT + +public: + EditorManager(QWidget* pParent = 0, const char* szName = 0); + ~EditorManager(); + + KTextEditor::Document* add(); + void remove(KTextEditor::Document*); + void applyPrefs(); +}; + +#endif diff --git a/src/editorpage.cpp b/src/editorpage.cpp new file mode 100644 index 0000000..5c183b9 --- /dev/null +++ b/src/editorpage.cpp @@ -0,0 +1,720 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <kdeversion.h> +#include <ktexteditor/selectioninterface.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/popupmenuinterface.h> +#include <ktexteditor/editinterface.h> +#include <kate/document.h> +#include <kate/view.h> +#include "editorpage.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pDoc The document object associated with this page + * @param pMenu A Cscope queries popup menu to use with the editor + * @param pParent The parent widget + * @param szName The widget's name + */ +EditorPage::EditorPage(KTextEditor::Document* pDoc, QPopupMenu* pMenu, + QTabWidget* pParent, const char* szName) : QHBox(pParent, szName), + m_pParentTab(pParent), + m_pDoc(pDoc), + m_bOpen(false), + m_bNewFile(false), + m_sName(""), + m_bWritable(true), /* new documents are writable by default */ + m_bModified(false), + m_nLine(0), + m_bSaveNewSizes(false) +{ + KTextEditor::PopupMenuInterface* pMenuIf; + KTextEditor::ViewCursorInterface* pCursorIf; + + // Create code-completion objects (will be deleted by QObject destructor) + m_pCompletion = new SymbolCompletion(this, this); + + // Set read-only mode, if required + if (Config().getReadOnlyMode()) + m_pDoc->setReadWrite(false); + + // Create the child widgets + m_pSplit = new QSplitter(this); + m_pCtagsList = new CtagsList(m_pSplit); + m_pView = m_pDoc->createView(m_pSplit); + m_pSplit->setResizeMode(m_pCtagsList, QSplitter::KeepSize); + + // Perform tasks only when the document has been loaded completely + connect(m_pDoc, SIGNAL(completed()), this, SLOT(slotFileOpened())); + + // Be notified when the text in the editor changes + connect(m_pDoc, SIGNAL(textChanged()), this, SLOT(slotSetModified())); + connect(m_pDoc, SIGNAL(undoChanged()), this, SLOT(slotUndoChanged())); + + // Store the sizes of the child windows when the tag list is resized + // (since it may imply a move of the splitter divider) + connect(m_pCtagsList, SIGNAL(resized()), this, SLOT(slotChildResized())); + + // Go to a symbol's line if it is selected in the tag list + connect(m_pCtagsList, SIGNAL(lineRequested(uint)), this, + SLOT(slotGotoLine(uint))); + + // Add Ctag records to the tag list + connect(&m_ctags, SIGNAL(dataReady(FrontendToken*)), m_pCtagsList, + SLOT(slotDataReady(FrontendToken*))); + + // Monitor Ctags' operation + connect(&m_ctags, SIGNAL(finished(uint)), m_pCtagsList, + SLOT(slotCtagsFinished(uint))); + + // Set the context menu + pMenuIf = dynamic_cast<KTextEditor::PopupMenuInterface*>(m_pView); + if (pMenuIf) + pMenuIf->installPopup(pMenu); + + // Emit a signal whenever the cursor's position changes + pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView); + if (pCursorIf) { + connect(m_pView, SIGNAL(cursorPositionChanged()), this, + SLOT(slotCursorPosChange())); + } +} + +/** + * Class destructor. + */ +EditorPage::~EditorPage() +{ +} + +/** + * Returns a pointer to the editor document object embedded in this page. + * @returns the document pointer + */ +KTextEditor::Document* EditorPage::getDocument() +{ + return m_pDoc; +} + +/** + * Returns a pointer to the editor view object embedded in this page. + * @returns the view pointer + */ +KTextEditor::View* EditorPage::getView() +{ + return m_pView; +} + +/** + * Returns the full path of the file being edited. + * @return The path of the file associated with the Document object, empty + * string if no file is currently open + */ +QString EditorPage::getFilePath() +{ + return m_pDoc->url().path(); +} + +/** + * Returns the name of the file being edited. + * @return The name of the file associated with the Document object, empty + * string if no file is currently open + */ +QString EditorPage::getFileName() +{ + return m_sName; +} + +/** + * Determines whether this file can be modified, according to the file-system + * permissions, and KScope's global settings. + * @return true if this document can be changed, false otherwise + */ +bool EditorPage::isWritable() +{ + // Check global settings first + if (Config().getReadOnlyMode()) + return false; + + // Return FS write permissions + return m_bWritable; +} + +/** + * Determines if the file edited in this page was modified, and the changes + * were not yet saved. + * @return true if the file was modified, false otherwise + */ +bool EditorPage::isModified() +{ + return m_pDoc->isModified(); +} + +/** + * Opens a file for editing. + * @param sFileName The full path name of the file to edit. + */ +void EditorPage::open(const QString& sFileName) +{ + // Open the given file + m_bOpen = false; + m_pDoc->openURL(sFileName); +} + +/** + * Marks the page as containing a new unnamed file. + */ +void EditorPage::setNewFile() +{ + m_bNewFile = true; + emit newFile(this); +} + +/** + * Saves the edited file. + */ +void EditorPage::save() +{ + if (m_pDoc->isModified()) + m_pDoc->save(); +} + +/** + * Closes an edited file. + * @param bForce true to close the file regardless of any modifications, + * false to prompt the user in case of unsaved chnages + * @return true if the file has been closed, false if the user has aborted + */ +bool EditorPage::close(bool bForce) +{ + QString sPath; + + // To override the prompt-on-close behaviour, we need to mark the file + // as unmodified + if (bForce) + m_pDoc->setModified(false); + + // Close the file, unless the user aborts the action + sPath = m_pDoc->url().path(); + if (!m_pDoc->closeURL()) + return false; + + emit fileClosed(sPath); + return true; +} + +/** + * Applies any changes to the user preferences concerning an editor window. + */ +void EditorPage::applyPrefs() +{ + // Determine whether the editor should work in a read-only mode + if (m_bWritable) + m_pDoc->setReadWrite(!Config().getReadOnlyMode()); + + // Apply preferences to the tag list of this window + m_pCtagsList->applyPrefs(); +} + +/** + * Sets the keyboard focus to the editor part of the page. + * This method is called whenever the page is activated. It is more reasonable + * to set the focus to the editor than to the tag list. + */ +void EditorPage::setEditorFocus() +{ + m_pView->setFocus(); + slotCursorPosChange(); +} + +/** + * Sets the keyboard focus to the tag list. + * This method is called when the "Go To Tag" menu command is invoked. + */ +void EditorPage::setTagListFocus() +{ + m_pCtagsList->slotSetFocus(); +} + +/** + * Sets a bookmark at the given line. + * @param nLine The line to mark + */ +void EditorPage::addBookmark(uint nLine) +{ + KTextEditor::MarkInterface* pMarkIf; + + pMarkIf = dynamic_cast<KTextEditor::MarkInterface*>(m_pDoc); + if (pMarkIf) + pMarkIf->setMark(nLine, KTextEditor::MarkInterface::markType01); +} + +/** + * Retrieves a list of all bookmarks in this page. + */ +void EditorPage::getBookmarks(FileLocationList& fll) +{ + KTextEditor::MarkInterface* pMarkIf; + QPtrList<KTextEditor::Mark> plMarks; + KTextEditor::Mark* pMark; + + // Get the marks interface + pMarkIf = dynamic_cast<KTextEditor::MarkInterface*>(m_pDoc); + if (!pMarkIf) + return; + + // Find all bookmarks + plMarks = pMarkIf->marks(); + for (pMark = plMarks.first(); pMark; pMark = plMarks.next()) { + if (pMark->type == KTextEditor::MarkInterface::markType01) + fll.append(new FileLocation(getFilePath(), pMark->line, 0)); + } +} + +/** + * Returns the currently selected text in an open file. + * @return The selected text, or a null string if no text is currently + * selected + */ +QString EditorPage::getSelection() +{ + KTextEditor::SelectionInterface* pSelect; + + // Get the selected text + pSelect = dynamic_cast<KTextEditor::SelectionInterface*>(m_pDoc); + if (!pSelect || !pSelect->hasSelection()) + return QString::null; + + // Return the selected text + return pSelect->selection(); +} +/** + * Returns a the complete word defined by the current cursor position. + * Attempts to extract a valid C symbol from the location of the cursor, by + * starting at the current line and column, and looking forward and backward + * for non-symbol characters. + * @return A C symbol under the cursor, if any, or QString::null otherwise + */ +QString EditorPage::getWordUnderCursor(uint* pPosInWord) +{ + KTextEditor::ViewCursorInterface* pCursor; + KTextEditor::EditInterface* pEditIf; + QString sLine; + uint nLine, nCol, nFrom, nTo, nLast, nLength; + QChar ch; + + // Get a cursor object + pCursor = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView); + if (pCursor == NULL) + return QString::null; + + // Get a pointer to the edit interface + pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc); + if (!pEditIf) + return QString::null; + + // Get the line on which the cursor is positioned + pCursor->cursorPositionReal(&nLine, &nCol); + sLine = pEditIf->textLine(nLine); + + // Find the beginning of the current word + for (nFrom = nCol; nFrom > 0;) { + ch = sLine.at(nFrom - 1); + if (!ch.isLetter() && !ch.isDigit() && ch != '_') + break; + + nFrom--; + } + + // Find the end of the current word + nLast = sLine.length(); + for (nTo = nCol; nTo < nLast;) { + ch = sLine.at(nTo); + if (!ch.isLetter() && !ch.isDigit() && ch != '_') + break; + + nTo++; + } + + // Mark empty words + nLength = nTo - nFrom; + if (nLength == 0) + return QString::null; + + // Return the in-word position, if required + if (pPosInWord != NULL) + *pPosInWord = nCol - nFrom; + + // Extract the word under the cursor from the entire line + return sLine.mid(nFrom, nLength); +} + +/** + * Combines getSelection() and getWordUnderCursor() to return a suggested + * text for queries. + * The function first looks if any text is selected. If so, the selected text + * is returned. Otherwise, the word under the cursor location is returned, if + * one exists. + * @return Either the currently selected text, or the word under the cursor, + * or QString::null if both options fail + */ +QString EditorPage::getSuggestedText() +{ + QString sText; + + sText = getSelection(); + if (sText == QString::null) + sText = getWordUnderCursor(); + + return sText; +} + +/** + * Returns the contents of the requested line. + * Truncates the leading and trailing white spaces. + * @param nLine The line number + * @return The text of the requested line, if successful, QString::null + * otherwise + */ +QString EditorPage::getLineContents(uint nLine) +{ + KTextEditor::EditInterface* pEditIf; + QString sLine; + + // Cannot accept line 0 + if (nLine == 0) + return QString::null; + + // Get a pointer to the edit interface + pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc); + if (!pEditIf) + return QString::null; + + // Get the line on which the cursor is positioned + sLine = pEditIf->textLine(nLine - 1); + return sLine.stripWhiteSpace(); +} + +/** + * Moves the editing caret to the beginning of a given line. + * @param nLine The line number to move to + */ +void EditorPage::slotGotoLine(uint nLine) +{ + // Ensure there is an open document + if (!m_bOpen) + return; + + // Set the cursor to the requested line + if (!setCursorPos(nLine)) + return; + + // Update Ctags view + m_pCtagsList->gotoLine(nLine); + + // Set the focus to the selected line + m_pView->setFocus(); +} + +/** + * Sets this editor as the current page, when the edited file's name is + * selected in the "Window" menu. + */ +void EditorPage::slotMenuSelect() +{ + m_pParentTab->setCurrentPage(m_pParentTab->indexOf(this)); +} + +/** + * Displays a list of possible completions for the symbol currently under the + * cursor. + */ +void EditorPage::slotCompleteSymbol() +{ + m_pCompletion->slotComplete(); +} + +/** + * Stores the sizes of the child widgets whenever they are changed. + * This slot is connected to the resized() signal of the CtagsList child + * widget. + */ +void EditorPage::slotChildResized() +{ + SPLIT_SIZES si; + + // Only store sizes when allowed to + if (!m_bSaveNewSizes) { + m_bSaveNewSizes = true; + return; + } + + // Get the current widths of the child widgets + si = m_pSplit->sizes(); + if (si.count() == 2) + Config().setEditorSizes(si); +} + +/** + * Sets the visibility status and sizes of the child widgets. + * @param bShowTagList true to show the tag list, false otherwise + * @param si The new sizes to use + */ +void EditorPage::setLayout(bool bShowTagList, const SPLIT_SIZES& si) +{ + // Make sure sizes are not stored during this process + m_bSaveNewSizes = false; + + // Adjust the layout + m_pCtagsList->setShown(bShowTagList); + if (bShowTagList) + m_pSplit->setSizes(si); +} + +/** + * Returns the current position of the cursor. + * @param nLine Holds the line on which the cursor is currently located + * @param nCol Holds the column on which the cursor is currently located + * @return true if successful, false otherwise (cursor interface was not + * obtained) + */ +bool EditorPage::getCursorPos(uint& nLine, uint& nCol) +{ + KTextEditor::ViewCursorInterface* pCursorIf; + + // Acquire the view cursor + pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView); + if (pCursorIf == NULL) + return false; + + // Get the cursor position (adjusted to 1-based counting) + pCursorIf->cursorPosition(&nLine, &nCol); + nLine++; + nCol++; + + return true; +} + +/** + * Moves the cursor to a given position. + * @param nLine The cursor's new line number + * @param nCol The cursor's new column number + * @return true if successful, false otherwise (cursor interface was not + * obtained) + */ +bool EditorPage::setCursorPos(uint nLine, uint nCol) +{ + Kate::View* pKateView; + KTextEditor::ViewCursorInterface* pCursorIf; + + // Cannot accept line 0 + if (nLine == 0) + return false; + + // Adjust to 0-based counting + nLine--; + nCol--; + + // Acquire the view cursor + pCursorIf = dynamic_cast<KTextEditor::ViewCursorInterface*>(m_pView); + if (pCursorIf == NULL) + return false; + + // NOTE: The following code is a fix to a bug in Kate, which wrongly + // calculates the column number in setCursorPosition. + pKateView = dynamic_cast<Kate::View*>(m_pView); + if (pKateView != NULL) { + KTextEditor::EditInterface* pEditIf; + const char* szLine; + uint nRealCol; + uint nTabAdjust; + + // Get a pointer to the edit interface + pEditIf = dynamic_cast<KTextEditor::EditInterface*>(m_pDoc); + if (!pEditIf) + return false; + + nRealCol = 0; + + // Check for out of bound line numbers + if (nLine < pEditIf->numLines()) { + // Get the contents of the requested line + szLine = pEditIf->textLine(nLine).latin1(); + + // Check for empty line + if (szLine != NULL) { + // The number of columns which a tab character adds + nTabAdjust = pKateView->tabWidth() - 1; + + // Calculate the real column, based on the tab width + for (; nRealCol < nCol && szLine[nRealCol] != 0; nRealCol++) { + if (szLine[nRealCol] == '\t') + nCol -= nTabAdjust; + } + } + } + else { + // Marker set beyond end of file, move to the last line + nLine = pEditIf->numLines() - 1; + } + // Set the cursor position + pCursorIf->setCursorPositionReal(nLine, nRealCol); + } + else { + // Non-Kate editors: set the cursor position normally + pCursorIf->setCursorPosition(nLine, nCol); + } + + return true; +} + +void EditorPage::setTabWidth(uint nTabWidth) +{ + Kate::Document* pKateDoc; + Kate::Command* pKateCmd; + QString sCmd, sResult; + + pKateDoc = dynamic_cast<Kate::Document*>(m_pDoc); + if ((pKateDoc) && + (pKateCmd = pKateDoc->queryCommand("set-tab-width"))) { + sCmd.sprintf("set-tab-width %u", nTabWidth); + pKateCmd->exec((Kate::View*)m_pView, sCmd, sResult); + } +} + +/** + * Called when a document has completed loading. + * Determines the file's properties and refreshes the tag list of the editor + * window. + * This slot is connected to the completed() signal of the document object. + * The signal is emitted when a new file is opened, or when a modified file is + * saved. + */ +void EditorPage::slotFileOpened() +{ + QFileInfo fi(m_pDoc->url().path()); + + // Get file information + m_sName = fi.fileName(); + m_bWritable = fi.isWritable(); + + // Set read/write or read-only mode + m_pDoc->setReadWrite(!Config().getReadOnlyMode() && m_bWritable); + + // Refresh the tag list + m_pCtagsList->clear(); + m_ctags.run(m_pDoc->url().path()); + + // Check if this is a modified file that has just been saved + if (m_bModified) + emit fileSaved(m_pDoc->url().path(), m_bNewFile); + + // Notify that the document has loaded + m_bOpen = true; + m_bModified = false; + emit fileOpened(this, m_pDoc->url().path()); + + // Set initial position of the cursor + m_nLine = 0; + slotCursorPosChange(); + + // This is no longer a new file + m_bNewFile = false; +} + +/** + * Marks a file as modified when the contents of the editor change. + * This slot is conncted to the textChanged() signal of the Document object. + * In addition to marking the file, this method also emits the modified() + * signal. + */ +void EditorPage::slotSetModified() +{ + // Only perform tasks if the file is not already marked + if (!m_bModified && m_pDoc->isModified()) { + m_bModified = true; + emit modified(this, m_bModified); + +#if KDE_IS_VERSION(3,3,0) + Kate::DocumentExt* pKateDoc; + + // If the editor is a Kate part, check whether it was modified on + // disk as well, and issue a warning if so + pKateDoc = dynamic_cast<Kate::DocumentExt*>(m_pDoc); + if (pKateDoc) + pKateDoc->slotModifiedOnDisk(dynamic_cast<Kate::View*>(m_pView)); +#endif + } + + // Start/restart the auto-completion timer + m_pCompletion->slotAutoComplete(); +} + +/** + * Marks a file as not modified if all undo levels have been applied. + * This slot is conncted to the undoChanged() signal of the Document object. + * In addition to marking the file, this method also emits the modified() + * signal. + */ +void EditorPage::slotUndoChanged() +{ + // Check if the file contents have been fully restored + if (m_bModified && !m_pDoc->isModified()) { + m_bModified = false; + emit modified(this, m_bModified); + } +} + +/** + * Handles changes in the cursor position. + * Emits a signal with the new line and column numbers. + */ +void EditorPage::slotCursorPosChange() +{ + uint nLine, nCol; + + // Find the new line and column number, and emit the signal + if (!getCursorPos(nLine, nCol)) + return; + + emit cursorPosChanged(nLine, nCol); + + // Select the relevant symbol in the tag list + if (Config().getAutoTagHl() && (m_nLine != nLine)) { + m_pCtagsList->gotoLine(nLine); + m_nLine = nLine; + } + + // Abort code completion on cursor changes during the completion + // process + m_pCompletion->abort(); +} + +#include "editorpage.moc" diff --git a/src/editorpage.h b/src/editorpage.h new file mode 100644 index 0000000..0af3aaf --- /dev/null +++ b/src/editorpage.h @@ -0,0 +1,215 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef EDITORPAGE_H +#define EDITORPAGE_H + +#include <qwidget.h> +#include <qhbox.h> +#include <qsplitter.h> +#include <qtabwidget.h> +#include <qpopupmenu.h> +#include <ktexteditor/document.h> +#include <ktexteditor/view.h> +#include <ktexteditor/markinterfaceextension.h> +#include "ctagsfrontend.h" +#include "ctagslist.h" +#include "kscopeconfig.h" +#include "symbolcompletion.h" +#include "projectbase.h" + +/** + * An editor window based on the system's current editing application. + * The page is divided into two panes. One holds an embedded editor, and the + * other holds a list of tags (generated by Ctags) of the file currently being + * edited. + * The widget creates an instance of the editor application, and uses its + * document and view objects that allow KScope to control it. A page also + * Each page is inserted in a separate tab in the EditorTabs widget. + * @author Elad Lahav + */ + +class EditorPage : public QHBox, SymbolCompletion::Interface +{ + Q_OBJECT + +public: + EditorPage(KTextEditor::Document*, QPopupMenu*, QTabWidget* pParent = 0, + const char* szName = 0); + ~EditorPage(); + + void open(const QString&); + void setNewFile(); + void save(); + bool close(bool bForce = false); + void applyPrefs(); + void setEditorFocus(); + void setTagListFocus(); + void addBookmark(uint); + void getBookmarks(FileLocationList&); + + KTextEditor::Document* getDocument(); + KTextEditor::View* getView(); + QString getFilePath(); + QString getFileName(); + bool isWritable(); + bool isModified(); + QString getSelection(); + QString getSuggestedText(); + QString getLineContents(uint); + void setLayout(bool bShowTagList, const SPLIT_SIZES&); + bool getCursorPos(uint&, uint&); + bool setCursorPos(uint, uint nCol = 1); + void setTabWidth(uint); + + virtual QString getWordUnderCursor(uint* pPosInWord = NULL); + + /** + * Implements the SymbolCompletion interface method for returning an + * object that supports KTextEditor::CodeCompletionInterface. + * @return A pointer to the View object of the editor + */ + virtual QObject* getCCObject() { return m_pView; } + + /** + * @return true if a previously unsaved file is currently being edited, + * false otherwise + */ + bool isNewFile() { return m_bNewFile; } + + /** The identifier of the Window menu item which activates this page. */ + int m_nMenuId; + +public slots: + void slotGotoLine(uint); + void slotMenuSelect(); + void slotCompleteSymbol(); + +signals: + /** + * Emitted when a file has been fully loaded into the editor. + * @param pPage The emitting object + * @param sPath The full path of the loaded file + */ + void fileOpened(EditorPage* pPage, const QString& sPath); + + /** + * Emitted when an editor is opened for editing a new file. + * @param pPage The emitting object + */ + void newFile(EditorPage* pPage); + + /** + * Emitted when the 'modified' status of the editor changes. + * This happens when the contents of the editor change, or when the file + * being edited is saved. + * @param pPage The emitting object + * @param bModified true if the new state is 'modified', false if the + * new state is 'unmodified' + */ + void modified(EditorPage* pPage, bool bModified); + + /** + * Emitted when the position of the cursor changes. + * @param nLine The new line number + * @param nCol The new column number + */ + void cursorPosChanged(uint nLine, uint nCol); + + /** + * Emitted when a file is saved after it was modified. + * Indicates the project's cross-reference database needs to be updated. + * @param sPath The full path of the saved file + * @param bIsNew true if this is a new file, false otherwise + */ + void fileSaved(const QString& sPath, bool bIsNew); + + /** + * Emitted when a file is closed. + * @param sPath The full path of the closed file + */ + void fileClosed(const QString& sPath); + +private: + /** The tab widget holding this page. */ + QTabWidget* m_pParentTab; + + /** A Ctags process to use on the edited source file. */ + CtagsFrontend m_ctags; + + /** An adjustable splitter for separating the tag list from the editor + part. */ + QSplitter* m_pSplit; + + /** A list view for displaying Ctags results. */ + CtagsList* m_pCtagsList; + + /** The document part of the editor. */ + KTextEditor::Document* m_pDoc; + + /** The view part of the editor. */ + KTextEditor::View* m_pView; + + /** Whether a source file is currently loaded. */ + bool m_bOpen; + + /** Whether the file being edited is a new one (i.e., never saved + before.) */ + bool m_bNewFile; + + /** The name of the file being edited. */ + QString m_sName; + + /** true if the file system allows this file to be modified, false + otherwise. */ + bool m_bWritable; + + /** This variable is required in addition to m_pDoc->isModified() so + that the modified() signal is emitted only once. */ + bool m_bModified; + + /** The current line position of the cursor. */ + uint m_nLine; + + /** Provides symbol completion. */ + SymbolCompletion* m_pCompletion; + + /** Determines whether size changes in the child widgets should be + stored in the global configuration file. + Needs to be explicitly set to false before _each_ operation that + does not wish to change the defaults. */ + bool m_bSaveNewSizes; + +private slots: + void slotChildResized(); + void slotFileOpened(); + void slotSetModified(); + void slotUndoChanged(); + void slotCursorPosChange(); +}; + +#endif diff --git a/src/editortabs.cpp b/src/editortabs.cpp new file mode 100644 index 0000000..5af9be1 --- /dev/null +++ b/src/editortabs.cpp @@ -0,0 +1,640 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kurldrag.h> +#include <kate/document.h> +#include "editortabs.h" +#include "kscopepixmaps.h" +#include "queryview.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +EditorTabs::EditorTabs(QWidget* pParent, const char* szName) : + TabWidget(pParent, szName), + m_pCurPage(NULL), + m_pWindowMenu(NULL), + m_nWindowMenuItems(0), + m_nNewFiles(0) +{ + // Display close buttons + setHoverCloseButton(true); + + // Accept file drops + setAcceptDrops(true); + + // Close an editor page when its close button is clicked + connect(this, SIGNAL(closeRequest(QWidget*)), this, + SLOT(slotRemovePage(QWidget*))); + + // Set an editor page as the active part, when its tab is selected + connect(this, SIGNAL(currentChanged(QWidget*)), this, + SLOT(slotCurrentChanged(QWidget*))); + + // Start dragging a file from a tab + connect(this, SIGNAL(initiateDrag(QWidget*)), this, + SLOT(slotInitiateDrag(QWidget*))); +} + +/** + * Class destructor. + */ +EditorTabs::~EditorTabs() +{ +} + +/** + * @param pWindowMenu Pointer to the main window's "Window" menu (used to + * add an activation menu item for each editor page) + */ +void EditorTabs::setWindowMenu(QPopupMenu* pWindowMenu) +{ + m_pWindowMenu = pWindowMenu; + connect(pWindowMenu, SIGNAL(aboutToShow()), this, + SLOT(slotFillWindowMenu())); + connect(pWindowMenu, SIGNAL(activated(int)), this, + SLOT(slotSetCurrentPage(int))); +} + +/** + * Adds a new editor page to the tab widget. + * @param pNewPage The page to add + */ +void EditorTabs::addEditorPage(EditorPage* pNewPage) +{ + // Create a new tab and set is as the current one + insertTab(pNewPage, ""); + showPage(pNewPage); + + // Add the file edited by this page to the map, and display its name, + // once the file is opened + connect(pNewPage, SIGNAL(fileOpened(EditorPage*, const QString&)), this, + SLOT(slotAttachFile(EditorPage*, const QString&))); + + // Handle new unnamed files + connect(pNewPage, SIGNAL(newFile(EditorPage*)), this, + SLOT(slotNewFile(EditorPage*))); + + // Change tab icon when a file is modified + connect(pNewPage, SIGNAL(modified(EditorPage*, bool)), this, + SLOT(slotFileModified(EditorPage*, bool))); + + // If this is the first page, the current page will not be set by the + // signal handler, so we need to do it manually + if (count() == 1) + slotCurrentChanged(pNewPage); +} + +/** + * Finds and displays a page editing the given file. + * NOTE: The bForceChange parameters is used as a fix for the GUI merge + * problem arising when the found page is the current one. + * @param sFileName The name of the file to search + * @param bForceChange If set to true, the method will emit the signal + * editorChanged() even if the found page is the + * current one + * @return The editor page object, if found, NULL otherwise + */ +EditorPage* EditorTabs::findEditorPage(const QString& sFileName, + bool bForceChange) +{ + EditorMap::iterator itr; + EditorPage* pPage; + bool bEmit; + + // Find the page according to the associated file name + itr = m_mapEdit.find(sFileName); + if (itr == m_mapEdit.end()) + return NULL; + + // Set the page as the current one + pPage = *itr; + bEmit = (bForceChange && (pPage == m_pCurPage)); + showPage(pPage); + + // Emit the editorChanged() signal, if required + if (bEmit) + emit editorChanged(NULL, m_pCurPage); + + return *itr; +} + +/** + * Returns the page associated with the selected tab. + * @return The current editor page + */ +EditorPage* EditorTabs::getCurrentPage() +{ + return (EditorPage*)currentPage(); +} + +/** + * Deletes the currently active page. + * Finds the current page, closes its editor window and deletes the page. + * If other editors are open, another page becomes active. + */ +void EditorTabs::removeCurrentPage() +{ + QWidget* pPage; + + // Get the active page, if any + pPage = currentPage(); + if (pPage == NULL) + return; + + // Close the editor window + removePage(pPage, false); +} + +/** + * Removes all editor pages. + * @return true if successful, false if the user aborts the operation + */ +bool EditorTabs::removeAllPages() +{ + QWidget* pPage; + + // Check if there are any modified files + if (getModifiedFilesCount()) { + // Prompt the user to save these files + switch (KMessageBox::questionYesNoCancel(NULL, + i18n("Some files contain unsaved changes.\nWould you like to " + "save these files?"))) { + case KMessageBox::Yes: + // Save files + slotSaveAll(); + break; + + case KMessageBox::No: + // Close files, ignoring changes + break; + + case KMessageBox::Cancel: + // Abort + return false; + } + } + + // Avoid warning about modification on disk + Kate::Document::setFileChangedDialogsActivated(false); + + // Iterate pages until none is left + while ((pPage = currentPage()) != NULL) + removePage(pPage, true); + + // Restore kate warning if enabled + Kate::Document::setFileChangedDialogsActivated( + Config().getWarnModifiedOnDisk()); + + // All pages were successfully removed + return true; +} + +/** + * Keeps track of the currently active editor page, and notifies on a change + * in the active page. + * This slot is connected to the currentChanged() signal of the QTabWidget + * object. + * @param pWidget The new active page + */ +void EditorTabs::slotCurrentChanged(QWidget* pWidget) +{ + EditorPage* pOldPage; + + // TODO: + // For some reason, this slot is being called twice for every external + // tab activation (e.g., through the Window menu). + // We avoid it, but this really needs to be fixed properly. + if (pWidget == m_pCurPage) + return; + + // Set the new active page + pOldPage = m_pCurPage; + m_pCurPage = (EditorPage*)pWidget; + + if (m_pCurPage) { + // Set the keyboard focus to the editor part of the page + m_pCurPage->setEditorFocus(); + + // Adjust the splitter sizes + m_pCurPage->setLayout(Config().getShowTagList(), + Config().getEditorSizes()); + } + + /* Notify the main window */ + emit editorChanged(pOldPage, m_pCurPage); +} + +/** + * Updates the tab of an editor page to reflect the newly opened file. + * This slot is attached to the fileOpened() signal of an EditorPage object. + * @param pEditPage Pointer to the calling object + * @param sFilePath The full path of the file edited in this page + */ +void EditorTabs::slotAttachFile(EditorPage* pEditPage, + const QString& sFilePath) +{ + // Set the appropriate tab icon, according to the file permissions + if (pEditPage->isWritable()) + setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRW)); + else + setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRO)); + + // Do nothing if the file name has not changed + if (m_mapEdit[sFilePath] == pEditPage) + return; + + // Set the tab caption to the file name, and a tool-tip to the full path + changeTab(pEditPage, pEditPage->getFileName()); + setTabToolTip(pEditPage, sFilePath); + + // Associate the EditorPage object with its file name + m_mapEdit[sFilePath] = pEditPage; +} + +/** + * Marks a page as containing a new unnamed file. + * This slot is attached to the newFile() signal of an EditorPage object. + * @param pEditPage Pointer to the calling object + */ +void EditorTabs::slotNewFile(EditorPage* pEditPage) +{ + QString sCaption; + + // Set the tab caption to mark a new file + m_nNewFiles++; + sCaption = i18n("Untitled ") + QString::number(m_nNewFiles); + changeTab(pEditPage, + Pixmaps().getPixmap(KScopePixmaps::TabRW), + sCaption); + setTabToolTip(pEditPage, i18n("New unsaved file")); +} + +/** + * Applies the user's colour and font preferences to all pages. + */ +void EditorTabs::applyPrefs() +{ + EditorPage* pPage; + int i; + + // Iterate editor pages + for (i = 0; i < count(); i++) { + pPage = (EditorPage*)page(i); + pPage->applyPrefs(); + setTabIconSet(pPage, Pixmaps().getPixmap(pPage->isWritable() ? + KScopePixmaps::TabRW : KScopePixmaps::TabRO)); + } +} + +/** + * Fills a list with the paths and cursor positions of all files currently + * open. + * @param list The list to fill + */ +void EditorTabs::getOpenFiles(FileLocationList& list) +{ + int i; + EditorPage* pPage; + uint nLine, nCol; + + // Iterate over all editor pages + for (i = 0; i < count(); i++) { + // Obtain file and cursor position information + pPage = (EditorPage*)page(i); + if (!pPage->getCursorPos(nLine, nCol)) { + nLine = 1; + nCol = 1; + } + + // Create a new list item + list.append(new FileLocation(pPage->getFilePath(), nLine, nCol)); + } +} + +/** + * Constructs a list bookmarks set to open files. + * Used to store all currently set bookmarks when a session is closed. + * @param fll The list to fill + */ +void EditorTabs::getBookmarks(FileLocationList& fll) +{ + int i; + EditorPage* pPage; + + // Iterate over all editor pages + for (i = 0; i < count(); i++) { + pPage = (EditorPage*)page(i); + pPage->getBookmarks(fll); + } +} + +/** + * Assigns bookmarks to open files. + * Called when a session is opened, to restore any bookmarks set to existing + * editor pages. + * @param fll A list of bookmark positions + */ +void EditorTabs::setBookmarks(FileLocationList& fll) +{ + FileLocation* pLoc; + EditorMap::iterator itr; + EditorPage* pPage; + + // Iterate over the list of bookmarks + for (pLoc = fll.first(); pLoc; pLoc = fll.next()) { + itr = m_mapEdit.find(pLoc->m_sPath); + // Get the relevant page, if any + if (itr != m_mapEdit.end()) { + pPage = *itr; + pPage->addBookmark(pLoc->m_nLine); + } + } +} + +/** + * Fills a QueryView object with the list of currently active bookmarks. + * @param pView The widget to use for displaying bookmarks + */ +void EditorTabs::showBookmarks(QueryView* pView) +{ + int i; + EditorPage* pPage; + FileLocationList fll; + FileLocation* pLoc; + + fll.setAutoDelete(true); + + // Iterate over all editor pages + for (i = 0; i < count(); i++) { + // Obtain file and cursor position information + pPage = (EditorPage*)page(i); + pPage->getBookmarks(fll); + + // Populate the view + for (pLoc = fll.first(); pLoc; pLoc = fll.next()) { + pView->addRecord("", pLoc->m_sPath, + QString::number(pLoc->m_nLine + 1), + pPage->getLineContents(pLoc->m_nLine + 1)); + } + + fll.clear(); + } +} + +/** + * Removes an editor page. + * If there are unsaved changes, the user is prompted, and the file is closed + * according to the user's choice. + * This slot is connected to the clicked() signal of the tab's close button. + * @param pPage The EditorPage object to remove + */ +void EditorTabs::slotRemovePage(QWidget* pPage) +{ + removePage(pPage, false); +} + +/** + * Handles the "View->Show/Hide Tag List" menu item. + * Shows/hides the tag list for the current page, and sets the default values + * for all pages. + */ +void EditorTabs::slotToggleTagList() +{ + EditorPage* pPage; + + // Change the default value + Config().setShowTagList(!Config().getShowTagList()); + + // Apply for the current page, if any + if ((pPage = (EditorPage*)currentPage()) != NULL) { + pPage->setLayout(Config().getShowTagList(), + Config().getEditorSizes()); + } +} + +/** + * Handles drag events over an empty tab widget, or over the tab bar. + * The event is accepted if the dragged object is a list of file paths. + * @param pEvent The drag move event object + */ +void EditorTabs::dragMoveEvent(QDragMoveEvent* pEvent) +{ + KURL::List list; + bool bAccept; + + bAccept = KURLDrag::decode(pEvent, list); + pEvent->accept(bAccept); +} + +/** + * Handles file drops over an empty tab widget, or over the tab bar. + * @param pEvent The drop event object + */ +void EditorTabs::dropEvent(QDropEvent* pEvent) +{ + emit filesDropped(pEvent); +} + +/** + * Called when an editor tab is dragged from the tab widget. + * Initialises the drag operation with a URL that corresponds to the path of + * the file being edited in the corresponding page. + * This slot is connected to the initiateDrag() signal emitted by the tab + * widget. + * @param pWidget The page whose tab is being dragged + */ +void EditorTabs::slotInitiateDrag(QWidget* pWidget) +{ + KURL url; + KURLDrag* pDrag; + + // Create a URL list containing the appropriate file path + url.setPath(((EditorPage*)pWidget)->getFilePath()); + pDrag = new KURLDrag(KURL::List(url), this); + + // Start the drag + pDrag->dragCopy(); +} + +/** + * Changes the tab icon of a modified file. + * @param pEditPage The editor page whose file was modified + * @param bModified true if the file has changed its status to modified, + * false otherwise (i.e., when undo operations restore it + * to its original contents.) + */ +void EditorTabs::slotFileModified(EditorPage* pEditPage, bool bModified) +{ + if (bModified) + setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabSave)); + else + setTabIconSet(pEditPage, Pixmaps().getPixmap(KScopePixmaps::TabRW)); +} + +/** + * Counts the number of pages containing modified files. + * @return The number of modified files + */ +int EditorTabs::getModifiedFilesCount() +{ + int i, nResult; + + // Iterate through pages + for (i = 0, nResult = 0; i < count(); i++) { + if (((EditorPage*)page(i))->isModified()) + nResult++; + } + + return nResult; +} + +/** + * Saves all files open for editing. + */ +void EditorTabs::slotSaveAll() +{ + int i; + + // Iterate through pages + for (i = 0; i < count(); i++) + ((EditorPage*)page(i))->save(); +} + +/** + * Selects the page to the left of the current one. + */ +void EditorTabs::slotGoLeft() +{ + int nIndex; + + nIndex = currentPageIndex(); + if (nIndex > 0) { + nIndex--; + setCurrentPage(nIndex); + } +} + +/** + * Selects the page to the right of the current one. + */ +void EditorTabs::slotGoRight() +{ + int nIndex; + + nIndex = currentPageIndex(); + if (nIndex < count() - 1) { + nIndex++; + setCurrentPage(nIndex); + } +} + +/** + * Fills the main window's "Window" menu with the current list of file tabs. + * This slot is attached to the aboutToShow() signal, emitted by the Window + * popup menu. + */ +void EditorTabs::slotFillWindowMenu() +{ + QString sLabel; + int i; + + // Delete old menu items + // NOTE: We can't use aboutToHide() to do that, since it is emitted + // _before_ the activated() signal + for (i = 0; i < m_nWindowMenuItems; i++) + m_pWindowMenu->removeItem(i); + + // Add new items + for (i = 0; i < count(); i++) { + sLabel = (i < 10) ? QString("&%1 %2").arg(i).arg(label(i)) : label(i); + m_pWindowMenu->insertItem(sLabel, i); + } + + // Store the number of items added + m_nWindowMenuItems = i; +} + +/** + * Sets the current page to the given one. + * This slot is attached to the activated() signal, emitted by the "Window" + * popup menu. The tab number to switch to is given by the menu item ID. + * Note that we do not trust setCurrentPage() to filter out the IDs of other + * menu items (which are supposed to be negative numbers). + */ +void EditorTabs::slotSetCurrentPage(int nId) +{ + if (nId >= 0 && nId < count()) + setCurrentPage(nId); +} + +/** + * Closes an edited file, and removes its page. + * Once a file has been closed, its page is removed from the tab widget stack, + * its menu item in the "Windows" menu is deleted and all other references to + * it are removed. + * Note that the operation may fail if the user chooses not to close the file + * when prompted for unsaved changes. + * @param pPage The EditorPage object to remove + * @param bForce true to close the page even if there are unsaved changes, + * false otherwise + * @return true if the page was removed, false otherwise + */ +bool EditorTabs::removePage(QWidget* pPage, bool bForce) +{ + EditorPage* pEditPage; + QString sFilePath; + + // Store the file path for later + pEditPage = (EditorPage*)pPage; + sFilePath = pEditPage->getFilePath(); + + // Close the edited file (may fail if the user aborts the action) + if (!pEditPage->close(bForce)) + return false; + + // Remove the page and all references to it + m_mapEdit.remove(sFilePath); + TabWidget::removePage(pPage); + + // Update the new state if no other page exists (if another page has + // become active, it will update the new state, so there is no need for + // special handling) + if (currentPage() == NULL) + slotCurrentChanged(NULL); + + // Notify the page has been removed + emit editorRemoved(pEditPage); + return true; +} + +#include "editortabs.moc" diff --git a/src/editortabs.h b/src/editortabs.h new file mode 100644 index 0000000..67d0c17 --- /dev/null +++ b/src/editortabs.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef EDITORTABS_H +#define EDITORTABS_H + +#include <qwidget.h> +#include <qpopupmenu.h> +#include "tabwidget.h" +#include "editorpage.h" +#include "projectmanager.h" + +typedef QMap<QString, EditorPage*> EditorMap; +class QueryView; + +/** + * A tab widget that holds several editor windows. + * This class provides the main widget in the KScope window. All editors are + * opened as pages of the tab widgets. + * @author Elad Lahav + */ + +class EditorTabs : public TabWidget +{ + Q_OBJECT + +public: + EditorTabs(QWidget* pParent = 0, const char* szName = 0); + ~EditorTabs(); + + void setWindowMenu(QPopupMenu*); + void addEditorPage(EditorPage*); + EditorPage* findEditorPage(const QString&, bool bForceChange = false); + EditorPage* getCurrentPage(); + void removeCurrentPage(); + bool removeAllPages(); + void applyPrefs(); + void getOpenFiles(FileLocationList&); + void getBookmarks(FileLocationList&); + void setBookmarks(FileLocationList&); + void showBookmarks(QueryView*); + +public slots: + void slotRemovePage(QWidget*); + void slotToggleTagList(); + void slotSaveAll(); + void slotGoLeft(); + void slotGoRight(); + +signals: + /** + * Emitted when the current editor page changes. + * @param pOld The previous current page + * @param pNew The new current page + */ + void editorChanged(EditorPage* pOld, EditorPage* pNew); + + /** + * Emitted when an editor page is closed. + * @param pPage The removed page + */ + void editorRemoved(EditorPage* pPage); + + /** + * Indicates that files were dragged and dropped over the tab widget. + * @param pEvent The drop event information + */ + void filesDropped(QDropEvent* pEvent); + +protected: + virtual void dragMoveEvent(QDragMoveEvent*); + virtual void dropEvent(QDropEvent*); + +private: + /** Links a file name with an editor page that has this file open. */ + EditorMap m_mapEdit; + + /** We need to keep track of the current page in order to implement the + editorChanged() signal. */ + EditorPage* m_pCurPage; + + /** A popup menu with Cscope operations for the editor windows. */ + QPopupMenu* m_pWindowMenu; + + /** The number of items added to the window menu (used for removing old + items). */ + int m_nWindowMenuItems; + + /** A counter for creating unique tab captions for new files. */ + int m_nNewFiles; + + int getModifiedFilesCount(); + bool removePage(QWidget*, bool); + +private slots: + void slotCurrentChanged(QWidget*); + void slotAttachFile(EditorPage*, const QString&); + void slotNewFile(EditorPage*); + void slotFileModified(EditorPage*, bool); + void slotInitiateDrag(QWidget*); + void slotFillWindowMenu(); + void slotSetCurrentPage(int); +}; + +#endif diff --git a/src/encoder.cpp b/src/encoder.cpp new file mode 100644 index 0000000..5d04744 --- /dev/null +++ b/src/encoder.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "qstring.h" +#include "encoder.h" + +#define CHAR_TO_HEX(c) ((c) < 0xA ? '0' + (c) : ('A' - 0xA) + (c)) +#define HEX_TO_CHAR(h) ((h) > 'A' ? (h) - ('A' - 0xA) : (h) - '0') + +/** + * Class constructor. + */ +Encoder::Encoder() : m_pBuf(NULL), m_nBufLen(0) +{ +} + +/** + * Class destructor. + */ +Encoder::~Encoder() { + if (m_pBuf) + delete[] m_pBuf; +} + +/** + * Encodes a string. + * @param str The string to encode + * @return The hex-encoded ASCII string + */ +const char* Encoder::encode(const QString& str) +{ + const char* szStr; + int nLen, i, j; + + szStr = str.latin1(); + nLen = str.length(); + + // Ensure the buffer is big enough to contain the result + resize((nLen * 2) + 1); + + // Encode the string + for (i = 0, j = 0; i < nLen; i++, j += 2) { + m_pBuf[j] = CHAR_TO_HEX(szStr[i] >> 4); + m_pBuf[j + 1] = CHAR_TO_HEX(szStr[i] & 0x0f); + } + + m_pBuf[j] = 0; + return m_pBuf; +} + +/** + * Decodes a string. + * @param str The string to decode + * @return The decoded string. + */ +const char* Encoder::decode(const QString& str) +{ + const char* szStr; + int nLen, i, j; + + szStr = str.latin1(); + nLen = str.length(); + + // Ensure the buffer is big enough to contain the result + nLen /= 2; + resize(nLen + 1); + + // Decode the string + for (i = 0, j = 0; i < nLen; i++, j += 2) { + m_pBuf[i] = HEX_TO_CHAR(szStr[j]) << 4; + m_pBuf[i] |= HEX_TO_CHAR(szStr[j + 1]); + } + + m_pBuf[i] = 0; + return m_pBuf; +} + +/** + * Sets a new size to the buffer. + * @param nNewLen The new size of the buffer + */ +void Encoder::resize(int nNewLen) +{ + if (m_nBufLen < nNewLen) { + if (m_pBuf) + delete[] m_pBuf; + + m_pBuf = new char[nNewLen]; + } +} diff --git a/src/encoder.h b/src/encoder.h new file mode 100644 index 0000000..2e35cde --- /dev/null +++ b/src/encoder.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sf.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef __ENCODER_H +#define __ENCODER_H + +/** + * Translates strings to hex-encoded ASCII, and vice-versa. + * @author Elad Lahav + */ +class Encoder +{ +public: + Encoder(); + ~Encoder(); + const char* encode(const QString&); + const char* decode(const QString&); + +private: + /** A buffer to contain the result of encoding/decoding. */ + char* m_pBuf; + + /** The buffer's length. */ + int m_nBufLen; + + void resize(int); +}; + +#endif diff --git a/src/file_ro.png b/src/file_ro.png Binary files differnew file mode 100644 index 0000000..6d0d29d --- /dev/null +++ b/src/file_ro.png diff --git a/src/file_rw.png b/src/file_rw.png Binary files differnew file mode 100644 index 0000000..8312c6b --- /dev/null +++ b/src/file_rw.png diff --git a/src/file_save.png b/src/file_save.png Binary files differnew file mode 100644 index 0000000..41b3f43 --- /dev/null +++ b/src/file_save.png diff --git a/src/filelist.cpp b/src/filelist.cpp new file mode 100644 index 0000000..59492ce --- /dev/null +++ b/src/filelist.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlineedit.h> +#include <qfileinfo.h> +#include <klocale.h> +#include "filelist.h" +#include "kscope.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +FileList::FileList(QWidget* pParent, const char* szName) : + SearchList(1, pParent, szName), + m_sRoot("/") +{ + // Set the list's columns + m_pList->addColumn(""); + m_pList->addColumn(i18n("File")); + m_pList->addColumn(i18n("Path")); + + // Sort only when asked to by the user + if (Config().getAutoSortFiles()) + m_pList->setSortColumn(1); + else + m_pList->setSortColumn(m_pList->columns() + 1); + + m_pList->setAllColumnsShowFocus(true); + + // Set colours and font + applyPrefs(); +} + +/** + * Class destructor. + */ +FileList::~FileList() +{ +} + +/** + * Adds a single entry to the file list. + * Implements the addItem() virtual method of the FileListTarget base + * class. When a FileList object is given as a parameter to + * ProjectManager::fillList(), this method is called for each file included + * in the project. A new list item is created, containing the file's name and + * path, and is added to the list. + * @param sFilePath The full path of a source file + */ +void FileList::addItem(const QString& sFilePath) +{ + QString sFileType, sFileName, sPath; + int nTypePos; + + // Extract the file name + sFileName = sFilePath.mid(sFilePath.findRev('/') + 1); + + // Get the file's extension (empty string for file names without an + // extension) + nTypePos = sFileName.findRev('.'); + if (nTypePos > -1) + sFileType = sFileName.mid(nTypePos + 1); + + // If a root path has been set, use a $ sign instead of that part of the + // path + sPath = sFilePath; + if (m_sRoot != "/") + sPath.replace(m_sRoot, "$"); + + // Create the list item + new QListViewItem(m_pList, sFileType, sFileName, sPath); +} + +/** + * Searches the list for the given file path. + * @param sPath The full path of the file to find + * @return true if the file was found in the list, false otherwise + */ +bool FileList::findFile(const QString& sPath) +{ + QString sFindPath(sPath); + + if (m_sRoot != "/") + sFindPath.replace(m_sRoot, "$"); + + return (m_pList->findItem(sFindPath, 2) != NULL); +} + +/** + * Removes all items from the file list. + */ +void FileList::clear() +{ + m_pList->clear(); + m_pEdit->setText(""); +} + +/** + * Opens a file for editing when its entry is clicked in the file list. + * @param pItem The clicked list item + */ +void FileList::processItemSelected(QListViewItem* pItem) +{ + QString sPath; + + // Get the file path (replace the root symbol, if required) + sPath = pItem->text(2); + if (sPath.startsWith("$")) + sPath.replace("$", m_sRoot); + + // Submit a request to open the file for editing + emit fileRequested(sPath, 0); +} + +/** + * Sets the list's colours and font, according the user's preferences. + */ +void FileList::applyPrefs() +{ + // Apply colour settings + m_pList->setPaletteBackgroundColor(Config().getColor( + KScopeConfig::FileListBack)); + m_pList->setPaletteForegroundColor(Config().getColor( + KScopeConfig::FileListFore)); + m_pList->setFont(Config().getFont(KScopeConfig::FileList)); +} + +/** + * Associates a root directory with this list. + * For each file in the list, the part of the path corresponding to the root + * is replaced with a $ sign. + * @param sRoot The new root path + */ +void FileList::setRoot(const QString& sRoot) +{ + QListViewItem* pItem; + QString sPath; + + // Update all items in the list + for (pItem = m_pList->firstChild(); pItem != NULL; + pItem = pItem->nextSibling()) { + sPath = pItem->text(2); + + // Restore the full path + sPath.replace("$", m_sRoot); + + // Replace the root with a $ sign + if (sRoot != "/") + sPath.replace(sRoot, "$"); + + pItem->setText(2, sPath); + } + + // Store the new root + m_sRoot = sRoot; +} + +/** + * Constructs a tool-tip for the given item. + * @param pItem The item for which a tip is required + * @param sTip The constructed tip string (on return) + * @return Always true + */ +bool FileList::getTip(QListViewItem* pItem, QString& sTip) +{ + sTip = pItem->text(2); + return true; +} + +#include "filelist.moc" diff --git a/src/filelist.h b/src/filelist.h new file mode 100644 index 0000000..8585dc6 --- /dev/null +++ b/src/filelist.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef FILELIST_H +#define FILELIST_H + +#include <qwidget.h> +#include "searchlist.h" +#include "projectmanager.h" + +/** + * Implements a searchable list of files. + * The file list is composed of a list view, and a search box, into which the + * user can enter a file name. The name is matched against the contents of + * the list, and matching items are selected. + * @author Elad Lahav + */ + +class FileList : public SearchList, public FileListTarget +{ + Q_OBJECT + +public: + FileList(QWidget* pParent = 0, const char* szName = 0); + ~FileList(); + + virtual void addItem(const QString&); + bool findFile(const QString&); + void clear(); + void applyPrefs(); + void setRoot(const QString&); + virtual bool getTip(QListViewItem*, QString&); + +signals: + /** + * Emitted when a file is selected, by either double-clicking a list + * item, or by highlighting an item and pressing the ENTER key. + * @param sPath The full path of the selected file + * @param nLine Line number, always set to 0 + */ + void fileRequested(const QString& sPath, uint nLine); + +protected: + virtual void processItemSelected(QListViewItem*); + +private: + /** A common root path for all items in the list. */ + QString m_sRoot; +}; + +#endif diff --git a/src/fileview.cpp b/src/fileview.cpp new file mode 100644 index 0000000..029c20a --- /dev/null +++ b/src/fileview.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qpushbutton.h> +#include <qfileinfo.h> +#include <qtabwidget.h> +#include <kfiledialog.h> +#include "fileview.h" +#include "filelist.h" +#include "kscopepixmaps.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + * @param fl Widget creation flags + */ +FileView::FileView(QWidget* pParent, const char* szName, WFlags fl) : + FileViewLayout(pParent, szName, fl), + m_pCurBranch(0), + m_sRoot("") +{ + QWidget* pPage; + + // Set the tab widget icons + pPage = m_pTabWidget->page(0); + m_pTabWidget->setTabIconSet(pPage, GET_PIXMAP(TabFileList)); + pPage = m_pTabWidget->page(1); + m_pTabWidget->setTabIconSet(pPage, GET_PIXMAP(TabFileTree)); + + // Create a single column for the file tree + m_pFileTree->addColumn(""); + + // Send the fileRequested() signal whenever a file is selected in either + // the list or the tree + connect(m_pFileList, SIGNAL(fileRequested(const QString&, uint)), this, + SIGNAL(fileRequested(const QString&, uint))); + connect(m_pFileTree, SIGNAL(doubleClicked(QListViewItem*)), + this, SLOT(slotTreeItemSelected(QListViewItem*))); + connect(m_pFileTree, SIGNAL(returnPressed(QListViewItem*)), this, + SLOT(slotTreeItemSelected(QListViewItem*))); +} + +/** + * Class destructor. + */ +FileView::~FileView() +{ +} + +/** + * Sets a new common root path to both the file list and the tree. + * @param sRoot The full path of the new root + */ +void FileView::setRoot(const QString& sRoot) +{ + // Nothing to do if the given root is the same as the old one + if (sRoot == m_sRoot) + return; + + m_sRoot = sRoot; + + // Remove the current branch + if (m_pCurBranch) + m_pFileTree->removeBranch(m_pCurBranch); + + // Update the file list + m_pFileList->setRoot(sRoot); + + // Nothing more to do for an empty root directory + if (sRoot.isEmpty()) + return; + + // Create and open a new branch, with the newly specified root + QFileInfo fi(sRoot); + m_pCurBranch = m_pFileTree->addBranch(KURL(sRoot), fi.fileName()); + m_pCurBranch->setChildRecurse(false); + m_pFileTree->setOpen(m_pCurBranch->root(), true); +} + +/** + * Clears the contents of the file view and file tree. + */ +void FileView::clear() +{ + m_pFileList->clear(); + setRoot(""); +} + +/** + * Emits the fileRequested() signal when a file name is selected in the file + * tree. An item is selected by either double-clicking it or by hittin + * "ENTER" when it is highlighted. + * This slot is connected to the doubleClicked() and returnPressed() signals + * of the KFileTreeView object. + * @param pItem The selected tree item + */ +void FileView::slotTreeItemSelected(QListViewItem* pItem) +{ + KFileTreeViewItem* pTreeItem; + + pTreeItem = (KFileTreeViewItem*)pItem; + if (pTreeItem && !pTreeItem->isDir()) + emit fileRequested(pTreeItem->path(), 0); +} + +#include "fileview.moc" diff --git a/src/fileview.h b/src/fileview.h new file mode 100644 index 0000000..5fc1fe3 --- /dev/null +++ b/src/fileview.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef FILEVIEW_H +#define FILEVIEW_H + +#include <kfiletreeview.h> +#include "fileviewlayout.h" + +/** + * A tabbed widget that contains a file list and a file tree. + * The list is an object of type FileList, which displays all files included + * in the current project. The tree is a standard KFileTreeView, which can + * browse through the entire file system. Optionally, the root of the tree + * can be set per project. + * @author Elad Lahav + */ + +class FileView : public FileViewLayout +{ + Q_OBJECT + +public: + FileView(QWidget* pParent = 0, const char* szName = 0, WFlags fl = 0); + ~FileView(); + + /** + * @return The file list widget which is a child of this widget. + */ + FileList* getFileList() { return m_pFileList; } + + void setRoot(const QString&); + void clear(); + +signals: + /** + * Emitted when a file is selected, by either double-clicking a list + * item, or by highlighting an item and pressing the ENTER key. + * @param sPath The full path of the selected file + * @param nLine Line number, always set to 0 + */ + void fileRequested(const QString& sPath, uint nLine); + +private: + /** The current branch in the file tree. */ + KFileTreeBranch* m_pCurBranch; + + /** The current root of the file tree. */ + QString m_sRoot; + +private slots: + void slotTreeItemSelected(QListViewItem*); +}; + +#endif + diff --git a/src/fileviewlayout.ui b/src/fileviewlayout.ui new file mode 100644 index 0000000..24bb1f5 --- /dev/null +++ b/src/fileviewlayout.ui @@ -0,0 +1,136 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>FileViewLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>FileViewLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>364</width> + <height>639</height> + </rect> + </property> + <property name="caption"> + <string>Form1</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>m_pTabWidget</cstring> + </property> + <property name="toolTip" stdset="0"> + <string></string> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string></string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="FileList"> + <property name="name"> + <cstring>m_pFileList</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Project File List</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string></string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="KFileTreeView"> + <property name="name"> + <cstring>m_pFileTree</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>File Tree</string> + </property> + </widget> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>FileList</class> + <header location="local">filelist.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> + <customwidget> + <class>KFileTreeView</class> + <header location="global">kfiletreeview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>filelist.h</includehint> + <includehint>kfiletreeview.h</includehint> +</includehints> +</UI> diff --git a/src/frontend.cpp b/src/frontend.cpp new file mode 100644 index 0000000..fee1c1b --- /dev/null +++ b/src/frontend.cpp @@ -0,0 +1,365 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfileinfo.h> +#include <qdir.h> +#include <klocale.h> +#include "frontend.h" + +/** + * Class constructor. + * @param nRecordSize The number of fields in each record + * @param bAutoDelete (Optional) true to delete the object when the process + * terminates, false (default) otherwise + */ +Frontend::Frontend(uint nRecordSize, bool bAutoDelete) : KProcess(), + m_nRecords(0), + m_pHeadToken(NULL), + m_pTailToken(NULL), + m_pCurToken(NULL), + m_bAutoDelete(bAutoDelete), + m_bInToken(false), + m_nRecordSize(nRecordSize) +{ + // Parse data on the standard output + connect(this, SIGNAL(receivedStdout(KProcess*, char*, int)), this, + SLOT(slotReadStdout(KProcess*, char*, int))); + + // Parse data on the standard error + connect(this, SIGNAL(receivedStderr(KProcess*, char*, int)), this, + SLOT(slotReadStderr(KProcess*, char*, int))); + + // Delete the process object when the process exits + connect(this, SIGNAL(processExited(KProcess*)), this, + SLOT(slotProcessExit(KProcess*))); +} + +/** + * Class destructor. + */ +Frontend::~Frontend() +{ + // Delete all pending tokens + while (m_pHeadToken) + removeToken(); +} + +/** + * Executes the back-end process. + * @param sName The name of the process (for error messages) + * @param slArgs A list containing the command-line arguments + * @param sWorkDir (Optional) working directory + * @param bBlock (Optional) true to block, false otherwise + * @return true if the process was executed successfully, false otherwise + */ +bool Frontend::run(const QString& sName, const QStringList& slArgs, + const QString& sWorkDir, bool bBlock) +{ + // Cannot start if another controlled process is currently running + if (isRunning()) { + m_sError = i18n("Cannot restart while another process is still " + "running"); + return false; + } + + // Reset variables + m_nRecords = 0; + m_bKilled = false; + + // Setup the command-line arguments + clearArguments(); + *this << slArgs; + + // Set the working directory, if requested + if (!sWorkDir.isEmpty()) + setWorkingDirectory(sWorkDir); + + // Execute the child process + if (!start(bBlock ? KProcess::Block : KProcess::NotifyOnExit, + KProcess::All)) { + m_sError = sName + i18n(": Failed to start process"); + return false; + } + + m_sError = i18n("No error"); + return true; +} + +/** + * Kills the process, and emits the aborted() signal. + * This function should not be called unless the process needs to be + * interrupted. + */ +void Frontend::kill() +{ + m_bKilled = true; + KProcess::kill(); + + emit aborted(); +} + +/** + * Appends a token to the end of the token list. + * @param pToken The token to add + */ +void Frontend::addToken(FrontendToken* pToken) +{ + // Check if this is the firt token + if (m_pHeadToken == NULL) { + m_pHeadToken = pToken; + m_pTailToken = pToken; + } + else { + // Not the first token, append and reset the tail token + m_pTailToken->m_pNext = pToken; + m_pTailToken = pToken; + } +} + +/** + * Removes and deletes the token at the head of the token list. + */ +void Frontend::removeToken() +{ + FrontendToken* pToken; + + if (m_pHeadToken == NULL) + return; + + pToken = m_pHeadToken; + m_pHeadToken = m_pHeadToken->m_pNext; + delete pToken; + + if (m_pHeadToken == NULL) + m_pTailToken = NULL; +} + +/** + * Removes tokens from the head of the list, according to the size of a + * record. + */ +void Frontend::removeRecord() +{ + uint i; + + for (i = 0; (i < m_nRecordSize) && (m_pHeadToken != NULL); i++) + removeToken(); +} + +/** + * Extracts tokens of text out of a given buffer. + * @param ppBuf Points to the buffer to parse, and is set to the + * beginning of the next token, upon return + * @param pBufSize Points to the size of the buffer, and is set to the + * remaining size, upon return + * @param sResult Holds the token's text, upon successful return + * @param delim Holds the delimiter by which the token's end was + * determined + * @return true if a token was extracted up to the given delimter(s), false + * if the buffer ended before a delimiter could be identified + */ +bool Frontend::tokenize(char** ppBuf, int* pBufSize, QString& sResult, + ParserDelim& delim) +{ + int nSize; + char* pBuf; + bool bDelim, bWhiteSpace, bFoundToken = false; + + // Iterate buffer + for (nSize = *pBufSize, pBuf = *ppBuf; (nSize > 0) && !bFoundToken; + nSize--, pBuf++) { + // Test if this is a delimiter character + switch (*pBuf) { + case '\n': + bDelim = ((m_delim & Newline) != 0); + bWhiteSpace = true; + delim = Newline; + break; + + case ' ': + bDelim = ((m_delim & Space) != 0); + bWhiteSpace = true; + delim = Space; + break; + + case '\t': + bDelim = ((m_delim & Tab) != 0); + bWhiteSpace = true; + delim = Tab; + break; + + default: + bDelim = false; + bWhiteSpace = false; + } + + if (m_bInToken && bDelim) { + m_bInToken = false; + *pBuf = 0; + bFoundToken = true; + } + else if (!m_bInToken && !bWhiteSpace) { + m_bInToken = true; + *ppBuf = pBuf; + } + } + + // Either a token was found, or the search through the buffer was + // finished without a delimiter character + if (bFoundToken) { + sResult = *ppBuf; + *ppBuf = pBuf; + *pBufSize = nSize; + } + else if (m_bInToken) { + sResult = QString::fromLatin1(*ppBuf, *pBufSize); + } + else { + sResult = QString::null; + } + + return bFoundToken; +} + +/** + * Handles text sent by the back-end process to the standard error stream. + * By default, this method emits the error() signal with the given text. + * @param sText The text sent to the standard error stream + */ +void Frontend::parseStderr(const QString& sText) +{ + emit error(sText); +} + +/** + * Deletes the process object upon the process' exit. + */ +void Frontend::slotProcessExit(KProcess*) +{ + // Allow specialised clean-up by inheriting classes + finalize(); + + // Signal the process has terminated + emit finished(m_nRecords); + + // Delete the object, if required + if (m_bAutoDelete) + delete this; +} + +/** + * Reads data written on the standard output by the controlled process. + * This is a private slot called attached to the readyReadStdout() signal of + * the controlled process, which means that it is called whenever data is + * ready to be read from the process' stream. + * The method reads whatever data is queued, and sends it to be interpreted + * by parseStdout(). + */ +void Frontend::slotReadStdout(KProcess*, char* pBuffer, int nSize) +{ + char* pLocalBuf; + QString sToken; + bool bTokenEnded; + ParserDelim delim; + + // Do nothing if waiting for process to die + if (m_bKilled) + return; + + pLocalBuf = pBuffer; + + // Iterate over the given buffer + while (nSize > 0) { + // Create a new token, if the last iteration has completed one + if (m_pCurToken == NULL) + m_pCurToken = new FrontendToken(); + + // Extract text until the requested delimiter + bTokenEnded = tokenize(&pLocalBuf, &nSize, sToken, delim); + + // Add the extracted text to the current token + m_pCurToken->m_sData += sToken; + + // If the buffer has ended before the requested delimiter, we need + // to wait for more output from the process + if (!bTokenEnded) + return; + + // Call the process-specific parser function + switch (parseStdout(m_pCurToken->m_sData, delim)) { + case DiscardToken: + // Token should not be saved + delete m_pCurToken; + break; + + case AcceptToken: + // Store token in linked list + addToken(m_pCurToken); + break; + + case RecordReady: + // Store token, and notify the target object that an entry can + // be read + m_nRecords++; + addToken(m_pCurToken); + emit dataReady(m_pHeadToken); + + // Delete all tokens in the entry + removeRecord(); + break; + + case Abort: + kill(); + nSize = 0; + break; + } + + m_pCurToken = NULL; + } +} + +/** + * Reads data written on the standard error by the controlled process. + * This is a private slot called attached to the readyReadStderr() signal of + * the controlled process, which means that it is called whenever data is + * ready to be read from the process' stream. + * The method reads whatever data is queued, and sends it to be interpreted + * by parseStderr(). + */ +void Frontend::slotReadStderr(KProcess*, char* pBuffer, int nSize) +{ + QString sBuf; + + // Do nothing if waiting for process to die + if (m_bKilled) + return; + + sBuf.setLatin1(pBuffer, nSize); + parseStderr(sBuf); +} + +#include "frontend.moc" diff --git a/src/frontend.h b/src/frontend.h new file mode 100644 index 0000000..246128a --- /dev/null +++ b/src/frontend.h @@ -0,0 +1,212 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef FRONTEND_H +#define FRONTEND_H + +#include <qobject.h> +#include <kprocess.h> + + +/** + * Represents a single token in the parsed output stream. + * @author Elad Lahav + */ + +class FrontendToken +{ +public: + /** + * Class constructor. + */ + FrontendToken() : m_pNext(NULL) {} + + /** + * @return The text associated with this token + */ + const QString& getData() const { return m_sData; } + + /** + * @return A pointer to the next token in the strem. + */ + FrontendToken* getNext() const { return m_pNext; } + +protected: + /** Free text associated with the token. */ + QString m_sData; + + /** A pointer to the next token in the stream. */ + FrontendToken* m_pNext; + + friend class Frontend; +}; + +/** + * Abstract base class that provides a front-end to console-based programmes. + * Provides a parsing infrastructure which is based on a list of records, all + * of the same structure. Each record is composed of a number of delimited + * fields (tokens.) + * @author Elad Lahav + */ + +class Frontend : public KProcess +{ + Q_OBJECT + +public: + Frontend(uint, bool bAutoDelete = false); + ~Frontend(); + + virtual bool run(const QString&, const QStringList&, + const QString& sWorkDir = "", bool bBlock = false); + void kill(); + + /** + * @return An string describing the error which made run() fail + */ + const QString& getRunError() { return m_sError; } + +signals: + /** + * Indicates tokens can be read. + * The Frontend object parses the back-end output and creates a list of + * tokens. This signal is emitted when a batch of characters has been + * converted into a token list. + * @param pToken The head of the token list + */ + void dataReady(FrontendToken* pToken); + + /** + * Emitted when the back-end process terminates. + * @param nRecords The number of complete records parsed + */ + void finished(uint nRecords); + + /** + * Indicates that the Cscope process was terminated. + */ + void aborted(); + + /** + * This signal is used to report the progress of the back-end process. + * @param nProgress The current progress value + * @param nTotal The progress value that indicates the process + * is finished + */ + void progress(int nProgress, int nTotal); + + /** + * Emitted when an error message is produced by the back-end process. + */ + void error(const QString& sMsg); + +protected: + /** A set of possible delimiters for parsing process output. */ + enum ParserDelim { Newline = 0x01, Space = 0x02, Tab = 0x04, + WSpace = Space | Tab, All = WSpace | Newline }; + + /** Defines the set of return values for parseStdout(). Determines what + needs to be done with a new token passed to this method. */ + enum ParseResult { + DiscardToken /** Delete this token */, + AcceptToken /** Add this token to the list */, + RecordReady /** This token completes a record */, + Abort /** Kill the process */ + }; + + /** Number of complete records read so far. */ + uint m_nRecords; + + /** The head of the list of parsed output tokens. */ + FrontendToken* m_pHeadToken; + + /** The tail of the list of parsed output tokens. */ + FrontendToken* m_pTailToken; + + /** An iterator on the list of parsed output tokens. */ + FrontendToken* m_pCurToken; + + /** The current delimiters used for parsing the output. */ + ParserDelim m_delim; + + /** An error string produced if run() fails. */ + QString m_sError; + + /** + * Handles a text token received on the Standard Output stream of the + * controlled process. + * This is called by slotReadStdout whenever a new token is recognised. + * Inheriting classes should implement this method to parse the resutling + * stream of tokens. + * @param sToken A part of the text received on the Standard Output, + * disected according to current delimiter settings + * @param delim The delimiter that ended this token + * @result A ParseResult value, indicating what should be done with the + * new token + */ + virtual ParseResult parseStdout(QString& sToken, ParserDelim delim) = 0; + + virtual void parseStderr(const QString&); + + /** + * Called when the process exits. + * Allows inheriting classes to implement process termination handlers. + */ + virtual void finalize() {} + +protected slots: + virtual void slotProcessExit(KProcess*); + +private: + /** Determines whether the object should be deleted once the process has + exited */ + bool m_bAutoDelete; + + /** Determines whether the parser is in the middle of a token, or between + two tokens */ + bool m_bInToken; + + /** The number of fields in each parsed record. Should be defined for + every sub-class. */ + uint m_nRecordSize; + + /** This flag is raised when kill() is called. It signifies that even + though the process may not be dead yet, it should be considered as + such. */ + bool m_bKilled; + + void addToken(FrontendToken*); + void removeToken(); + void removeRecord(); + bool tokenize(char**, int*, QString&, ParserDelim&); + +private slots: + void slotReadStdout(KProcess*, char*, int); + void slotReadStderr(KProcess*, char*, int); +}; + +#endif diff --git a/src/graphedge.cpp b/src/graphedge.cpp new file mode 100644 index 0000000..283a5fe --- /dev/null +++ b/src/graphedge.cpp @@ -0,0 +1,306 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <math.h> +#include <stdlib.h> +#include <qpainter.h> +#include "graphedge.h" +#include "graphnode.h" + +int GraphEdge::RTTI = 1002; + +// Some definitions required by the ConvexHull class +typedef int (*CompFunc)(const void*, const void*); +#define ISLEFT(P0, P1, P2) \ + (P1.x() - P0.x()) * (P2.y() - P0.y()) - \ + (P2.x() - P0.x()) * (P1.y() - P0.y()) +#define FARTHEST(P0, P1, P2) \ + ((P1.x() - P0.x()) * (P1.x() - P0.x()) - \ + (P1.y() - P0.y()) * (P1.y() - P0.y())) - \ + ((P2.x() - P0.x()) * (P2.x() - P0.x()) - \ + (P2.y() - P0.y()) * (P2.y() - P0.y())) + + +/** + * An array of QPoint objects that can compute the convex hull surrounding all + * points in the array. + * @author Elad Lahav + */ +class ConvexHull : public QPointArray +{ +public: + /** + * Class constructor. + */ + ConvexHull() : QPointArray() {} + + /** + * Computes the convex hull of the points stored in the array, using + * Graham's scan. + * @param arrHull Holds the coordinates of the convex hull, upon return + */ + void compute(QPointArray& arrHull) { + uint i, nPivot, nTop; + + // Find the pivot point + nPivot = 0; + for (i = 1; i < size(); i++) { + if ((*this)[i].y() < (*this)[nPivot].y()) { + nPivot = i; + } + else if ((*this)[i].y() == (*this)[nPivot].y() && + (*this)[i].x() < (*this)[nPivot].x()) { + nPivot = i; + } + } + + // Sort points in radial order, relative to the pivot + s_ptPivot = (*this)[nPivot]; + (*this)[nPivot] = (*this)[0]; + (*this)[0] = s_ptPivot; + qsort(&(*this).data()[1], (*this).size() - 1, sizeof(QPoint), + (CompFunc)compRadial); + + // Initialise Graham's scan algorithm + arrHull.resize(size() + 1); + arrHull[0] = (*this)[0]; + arrHull[1] = (*this)[1]; + nTop = 1; + + // Compute the convex hull + for (i = 2; i < size();) { + // TODO: According to the algorithm, the condition should be >0 + // for pushing the point into the stack. For some reason, it works + // only with <0. Why? + if (ISLEFT(arrHull[nTop - 1], arrHull[nTop], (*this)[i]) < 0) { + arrHull[++nTop] = (*this)[i]; + i++; + } + else { + nTop--; + } + } + + // Close the hull + arrHull[++nTop] = (*this)[0]; + arrHull.truncate(nTop + 1); + } + +private: + /** The current pivot point, required by compRadial. */ + static QPoint s_ptPivot; + + /** + * Compares two points based on their angle relative to the current + * pivot point. + * This function is passed as the comparison function of qsort(). + * @param pPt1 A pointer to the first point + * @param pPt2 A pointer to the second point + * @return >0 if the first point is to the left of the second, <0 otherwise + */ + static int compRadial(const QPoint* pPt1, const QPoint* pPt2) { + int nResult; + + // Determine which point is to the left of the other. If the angle is + // the same, the greater point is the one farther from the pivot + nResult = ISLEFT(s_ptPivot, (*pPt1), (*pPt2)); + if (nResult == 0) + return FARTHEST(s_ptPivot, (*pPt1), (*pPt2)); + + return nResult; + } +}; + +QPoint ConvexHull::s_ptPivot; + +/** + * Class constructor. + * @param pCanvas The canvas on which to draw the edge + * @param pHead The edge's starting point + * @param pTail The edge's end point + */ +GraphEdge::GraphEdge(QCanvas* pCanvas, GraphNode* pHead, GraphNode* pTail) : + QCanvasPolygonalItem(pCanvas), + m_pHead(pHead), + m_pTail(pTail), + m_arrPoly(4) +{ +} + +/** + * Class destructor. + */ +GraphEdge::~GraphEdge() +{ + // Classes derived from QCanvasPolygonalItem must call hide() in their + // detructor (according to the Qt documentation) + hide(); +} + +/** + * Calculates the area surrounding the edge, and the bounding rectangle of + * the edge's polygonal head. + * The calculated area is used to find items on the canvas and to display + * tips. The bounding rectangle defines the tip's region (@see QToolTip). + * TODO: The function assumes that the we can simply append the polygon's + * array to that of the splines. Is this always the case, or should we sort + * the points of the polygon in radial order? + * @param arrCurve The control points of the edge's spline + * @param ai Used to calculate the arrow head polygon + */ +void GraphEdge::setPoints(const QPointArray& arrCurve, const ArrowInfo& ai) +{ + ConvexHull ch; + uint i; + int nXpos, nYpos; + + // Redraw an existing edge + if (m_arrArea.size() > 0) + invalidate(); + + // Store the point array for drawing + m_arrCurve = arrCurve; + + // Calculate the arrowhead's polygon + makeArrowhead(ai); + + // Compute the convex hull of the edge + ch.resize(m_arrCurve.size() + m_arrPoly.size() - 2); + ch.putPoints(0, m_arrCurve.size() - 1, m_arrCurve); + ch.putPoints(m_arrCurve.size() - 1, m_arrPoly.size() - 1, m_arrPoly); + ch.compute(m_arrArea); + + // Calculate the head's bounding rectangle + m_rcTip = QRect(m_arrPoly[0], m_arrPoly[0]); + for (i = 1; i < m_arrPoly.size(); i++) { + nXpos = m_arrPoly[i].x(); + if (nXpos < m_rcTip.left()) + m_rcTip.setLeft(nXpos); + else if (nXpos > m_rcTip.right()) + m_rcTip.setRight(nXpos); + + nYpos = m_arrPoly[i].y(); + if (nYpos < m_rcTip.top()) + m_rcTip.setTop(nYpos); + else if (nYpos > m_rcTip.bottom()) + m_rcTip.setBottom(nYpos); + } +} + +/** + * Sets the call information associated with this edge. + * @param sFile The call's file path + * @param sLine The call's line number + * @param sText The call's text + */ +void GraphEdge::setCallInfo(const QString& sFile, const QString& sLine, + const QString& sText) +{ + m_sFile = sFile; + m_sLine = sLine; + m_sText = sText; +} + +/** + * Constructs a tool-tip string for this edge. + * @return The tool-tip text + */ +QString GraphEdge::getTip() const +{ + QString sTip; + + sTip = m_sText + "<br><i>" + m_sFile + "</i>:" + m_sLine; + return sTip; +} + +/** + * Draws the spline as a sequence of cubic Bezier curves. + * @param painter Used for drawing the item on the canvas view + */ +void GraphEdge::drawShape(QPainter& painter) +{ + uint i; + + // Draw the polygon + painter.drawConvexPolygon(m_arrPoly); + + // Draw the Bezier curves + for (i = 0; i < m_arrCurve.size() - 1; i += 3) + painter.drawCubicBezier(m_arrCurve, i); + +#if 0 + // Draws the convex hull of the edge + QPen pen = painter.pen(); + QBrush br = painter.brush(); + painter.setPen(QPen(QColor(255, 0, 0))); + painter.setBrush(QBrush()); + painter.drawPolygon(m_arrArea); + painter.setPen(pen); + painter.setBrush(br); +#endif +} + +/** + * Computes the coordinates of the edge's arrow head, based on its curve. + * @param ai Pre-computed values used for all edges + */ +void GraphEdge::makeArrowhead(const ArrowInfo& ai) +{ + QPoint ptLast, ptPrev; + double dX1, dY1, dX0, dY0, dX, dY, dDeltaX, dDeltaY, dNormLen; + + // The arrowhead follows the line from the second last to the last points + // in the curve + ptLast = m_arrCurve[m_arrCurve.size() - 1]; + ptPrev = m_arrCurve[m_arrCurve.size() - 2]; + + // The first and last points of the polygon are the end of the curve + m_arrPoly.setPoint(0, ptLast.x(), ptLast.y()); + m_arrPoly.setPoint(3, ptLast.x(), ptLast.y()); + + // Convert integer points to double precision values + dX1 = (double)ptLast.x(); + dY1 = (double)ptLast.y(); + dX0 = (double)ptPrev.x(); + dY0 = (double)ptPrev.y(); + + // The values (x1-x0), (y1-y0) and sqrt(1 + tan(theta)^2) are useful + dDeltaX = dX1 - dX0; + dDeltaY = dY1 - dY0; + + // The normalised length of the arrow's sides + dNormLen = ai.m_dLength / sqrt(dDeltaX * dDeltaX + dDeltaY * dDeltaY); + + // Compute the other two points + dX = dX1 - ((dDeltaX - ai.m_dTan * dDeltaY) / ai.m_dSqrt) * dNormLen; + dY = dY1 - ((dDeltaY + ai.m_dTan * dDeltaX) / ai.m_dSqrt) * dNormLen; + m_arrPoly.setPoint(1, (int)dX, (int)dY); + + dX = dX1 - ((dDeltaX + ai.m_dTan * dDeltaY) / ai.m_dSqrt) * dNormLen; + dY = dY1 - ((dDeltaY - ai.m_dTan * dDeltaX) / ai.m_dSqrt) * dNormLen; + m_arrPoly.setPoint(2, (int)dX, (int)dY); +} diff --git a/src/graphedge.h b/src/graphedge.h new file mode 100644 index 0000000..ce399b3 --- /dev/null +++ b/src/graphedge.h @@ -0,0 +1,143 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef GRAPHEDGE_H +#define GRAPHEDGE_H + +#include <qcanvas.h> + +class GraphNode; + +/** + * Information used to draw arrow heads at the end of graph edges. + */ +struct ArrowInfo +{ + /** The length of the arrow. */ + double m_dLength; + + /** The tangent of the arrow's angle from the main line. */ + double m_dTan; + + /** Holds the value sqrt(1 + dTan^2). */ + double m_dSqrt; +}; + +/** + * Draws a directed edge on a canvas. + * The edge is composed of a spline, which is its body, and a polygon, which + * is its head. + * @author Elad Lahav + */ +class GraphEdge : public QCanvasPolygonalItem +{ +public: + GraphEdge(QCanvas*, GraphNode*, GraphNode*); + ~GraphEdge(); + + void setCallInfo(const QString&, const QString&, const QString&); + void setPoints(const QPointArray&, const ArrowInfo&); + QString getTip() const; + + /** + * @return The coordinates of the convex hull surrounding the edge + */ + virtual QPointArray areaPoints() const { return m_arrArea; } + + /** + * @return The head node of the edge + */ + GraphNode* getHead() { return m_pHead; } + + /** + * @return The tail node of the edge + */ + GraphNode* getTail() { return m_pTail; } + + /** + * @return The bounding rectangle of the edge's head + */ + QRect tipRect() const { return m_rcTip; } + + /** + * @return The file path for this call + */ + const QString& getFile() const { return m_sFile; } + + /** + * @return The line number for this call + */ + uint getLine() const { return m_sLine.toUInt(); } + + /** + * @return The call's text + */ + const QString& getText() const { return m_sText; } + + /** Identifies this class among other QCanvasItem classes. */ + static int RTTI; + + /** + * @return The class identifier + */ + virtual int rtti() const { return RTTI; } + +protected: + virtual void drawShape(QPainter&); + +private: + /** The edge's starting point. */ + GraphNode* m_pHead; + + /** The edge's end point. */ + GraphNode* m_pTail; + + /** The points of the polygon part of the edge. */ + QPointArray m_arrPoly; + + /** Control points for the spline part of the edge. */ + QPointArray m_arrCurve; + + QPointArray m_arrArea; + + /** The bounding rectangle of the edge's head, used for displaying the + edge's tool-tip. */ + QRect m_rcTip; + + /** The call's source file. */ + QString m_sFile; + + /** The call's line number. */ + QString m_sLine; + + /** The call's text. */ + QString m_sText; + + void makeArrowhead(const ArrowInfo&); +}; + +#endif diff --git a/src/graphnode.cpp b/src/graphnode.cpp new file mode 100644 index 0000000..28a219d --- /dev/null +++ b/src/graphnode.cpp @@ -0,0 +1,192 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qpainter.h> +#include <qfontmetrics.h> +#include "graphnode.h" + +int GraphNode::RTTI = 1001; + +/** + * Class constructor. + * @param pCanvas The owner canvas + * @param sFunc The node's function + * @param bMultiCall Whether this node represents multiple calls + */ +GraphNode::GraphNode(QCanvas* pCanvas, const QString& sFunc, bool bMultiCall) : + QCanvasPolygon(pCanvas), + m_sFunc(sFunc), + m_bMultiCall(bMultiCall), + m_bDfsFlag(false) +{ + // Every node deletes its out-edges only + m_dictOutEdges.setAutoDelete(true); +} + +/** + * Class destructor. + */ +GraphNode::~GraphNode() +{ +} + +/** + * Finds an edge leaving this node and reaching the given node. + * If such an edge does not exist, a new one is created. + * @param pTail The destination node + * @return The edge that ends at the given node + */ +GraphEdge* GraphNode::addOutEdge(GraphNode* pTail) +{ + GraphEdge* pEdge; + + // Look for the edge + if ((pEdge = m_dictOutEdges.find(pTail->getFunc())) == NULL) { + // Create a new edge + pEdge = new GraphEdge(canvas(), this, pTail); + m_dictOutEdges.insert(pTail->getFunc(), pEdge); + pTail->m_dictInEdges.replace(m_sFunc, pEdge); + } + + // Return the new/constructed edge + return pEdge; +} + +/** + * Performs a weak depth-first-search on the graph. + * The search continues along all edges, both incoming and outgoing. + */ +void GraphNode::dfs() +{ + // Stop if this node is already marked + if (m_bDfsFlag) + return; + + // Mark the node as visited + m_bDfsFlag = true; + + // Continue along outgoing edges + QDictIterator<GraphEdge> itrOut(m_dictOutEdges); + for (; itrOut.current(); ++itrOut) + (*itrOut)->getTail()->dfs(); + + // Continue along incoming edges + QDictIterator<GraphEdge> itrIn(m_dictInEdges); + for (; itrIn.current(); ++itrIn) + (*itrIn)->getHead()->dfs(); +} + +/** + * Deletes all outgoing edges. + * Uses the auto-delete property of the dictionary. + */ +void GraphNode::removeOutEdges() +{ + m_dictOutEdges.clear(); +} + +/** + * Deletes all incoming edges. + * To avoid double deletions, the function lets the head node of the edge remove + * it. + */ +void GraphNode::removeInEdges() +{ + QDictIterator<GraphEdge> itr(m_dictInEdges); + + // Delete edges through their head nodes + for (; itr.current(); ++itr) + (*itr)->getHead()->m_dictOutEdges.remove(m_sFunc); + + // remove edges from the local dictionary (will not delete them) + m_dictInEdges.clear(); +} + +/** + * Returns the first found node connected to this one. + * This function is used with multi-call nodes for retrieving the parent node. + * @param pNode + * @param bCalled + */ +void GraphNode::getFirstNeighbour(GraphNode*& pNode, bool& bCalled) +{ + QDictIterator<GraphEdge> itrIn(m_dictInEdges); + QDictIterator<GraphEdge> itrOut(m_dictOutEdges); + + if (itrIn.current()) { + pNode = itrIn.current()->getHead(); + bCalled = false; + } + else if (itrOut.current()) { + pNode = itrOut.current()->getTail(); + bCalled = true; + } + else { + pNode = NULL; + } +} + +/** + * Modifies the bounding rectangle of the node. + * @param rect The new coordinates to set + */ +void GraphNode::setRect(const QRect& rect) +{ + QPointArray arr(4); + + m_rect = rect; + + arr.setPoint(0, m_rect.topLeft()); + arr.setPoint(1, m_rect.topRight()); + arr.setPoint(2, m_rect.bottomRight()); + arr.setPoint(3, m_rect.bottomLeft()); + setPoints(arr); +} + +/** + * Draws the node. + * @param painter Used for drawing the item on the canvas view + */ +void GraphNode::drawShape(QPainter& painter) +{ + const QPen& pen = painter.pen(); + const QFont& font = painter.font(); + + // Draw the rectangle + painter.setPen(QPen(Qt::black)); + painter.drawRect(m_rect); + + // Draw the text + painter.setPen(pen); + painter.setFont(m_font); + if (m_bMultiCall) + painter.drawText(m_rect, Qt::AlignCenter, "..."); + else + painter.drawText(m_rect, Qt::AlignCenter, m_sFunc); + + painter.setFont(font); +} diff --git a/src/graphnode.h b/src/graphnode.h new file mode 100644 index 0000000..9f48639 --- /dev/null +++ b/src/graphnode.h @@ -0,0 +1,123 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef GRAPHNODE_H +#define GRAPHNODE_H + +#include <qcanvas.h> +#include <qdict.h> +#include "graphedge.h" + +/** + * A canvas item that draws the name of a function insider a filled rectangle. + * This item represents a function in the call graph. + * @author Elad Lahav + */ +class GraphNode : public QCanvasPolygon +{ +public: + GraphNode(QCanvas* pCanvas, const QString&, bool bMultiCall = false); + ~GraphNode(); + + GraphEdge* addOutEdge(GraphNode*); + void dfs(); + void removeOutEdges(); + void removeInEdges(); + void getFirstNeighbour(GraphNode*&, bool&); + + /** + * @param rect The bounding rectangle of the node + */ + void setRect(const QRect& rect); + + /** + * @param font The font to use for drawing the text + */ + void setFont(const QFont& font) { m_font = font; } + + /** + * @return The name of the function + */ + const QString& getFunc() const { return m_sFunc; } + + /** + * @return true for a multiple-call node, false otherwise + */ + bool isMultiCall() { return m_bMultiCall; } + + /** + * @return The set of outgoing edges + */ + QDict<GraphEdge>& getOutEdges() { return m_dictOutEdges; } + + /** + * @return true if this node was already visited during the current DFS, + * false otherwise + */ + bool dfsVisited() { return m_bDfsFlag; } + + /** + * Clears the 'DFS-visited' flag, in preparation for the next DFS. + */ + void dfsReset() { m_bDfsFlag = false; } + + /** Identifies this class among other QCanvasItem classes. */ + static int RTTI; + + /** + * @return The class identifier + */ + virtual int rtti() const { return RTTI; } + +protected: + virtual void drawShape(QPainter&); + +private: + /** Function name. */ + QString m_sFunc; + + /** A list of outgoing edges indexed by destination. */ + QDict<GraphEdge> m_dictOutEdges; + + /** A list of incoming edges indexed by destination. */ + QDict<GraphEdge> m_dictInEdges; + + /** The bounding rectangle for the node. */ + QRect m_rect; + + /** The font to use for drawing the text. */ + QFont m_font; + + /** true for a multiple-call node, false otherwise. */ + bool m_bMultiCall; + + /** Determines whether this node was visited during a depth-first + search. */ + bool m_bDfsFlag; +}; + +#endif diff --git a/src/graphprefdlg.cpp b/src/graphprefdlg.cpp new file mode 100644 index 0000000..c8d381c --- /dev/null +++ b/src/graphprefdlg.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qspinbox.h> +#include "graphprefdlg.h" +#include "preferencesdlg.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +GraphPrefDlg::GraphPrefDlg(QWidget* pParent, const char* szName) : + GraphPrefLayout(pParent, szName, true, 0) +{ + m_pMaxDegSpin->setValue(Config().getGraphMaxNodeDegree()); +} + +/** + * Class destructor. + */ +GraphPrefDlg::~GraphPrefDlg() +{ +} + +/** + * @return The maximal degree value set in the spin box + */ +int GraphPrefDlg::getMaxNodeDegree() +{ + return m_pMaxDegSpin->value(); +} + +/** + * Displays the general preferences dialogue, showing the "Colours" page. + * This slot is connected to the clicked() signal of the colours button. + */ +void GraphPrefDlg::slotFontClicked() +{ + PreferencesDlg dlg(PreferencesDlg::Fonts); + + dlg.exec(); +} + +/** + * Displays the general preferences dialogue, showing the "Fonts" page. + * This slot is connected to the clicked() signal of the fonts button. + */ +void GraphPrefDlg::slotColorClicked() +{ + PreferencesDlg dlg(PreferencesDlg::Colors); + + dlg.exec(); +} + +#include "graphprefdlg.moc" + diff --git a/src/graphprefdlg.h b/src/graphprefdlg.h new file mode 100644 index 0000000..7a4a3c0 --- /dev/null +++ b/src/graphprefdlg.h @@ -0,0 +1,54 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef GRAPHPREFDLG_H +#define GRAPHPREFDLG_H + +#include "graphpreflayout.h" + +/** + * A dialogue that allows the user to configure the appearance and behaviour + * of the call graph. + * @author Elad Lahav + */ +class GraphPrefDlg : public GraphPrefLayout +{ + Q_OBJECT + +public: + GraphPrefDlg(QWidget* pParent = 0, const char* szName = 0); + ~GraphPrefDlg(); + + int getMaxNodeDegree(); + +protected slots: + virtual void slotFontClicked(); + virtual void slotColorClicked(); +}; + +#endif + diff --git a/src/graphpreflayout.ui b/src/graphpreflayout.ui new file mode 100644 index 0000000..a94a206 --- /dev/null +++ b/src/graphpreflayout.ui @@ -0,0 +1,262 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>GraphPrefLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>GraphPrefLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>328</width> + <height>164</height> + </rect> + </property> + <property name="caption"> + <string>Call Graph Preferences</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Maximal In/Out Node Degree</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>81</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pMaxDegSpin</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Colours</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>131</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pColorButton</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Fonts</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>121</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pFontButton</cstring> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>GraphPrefLayout</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>GraphPrefLayout</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>m_pColorButton</sender> + <signal>clicked()</signal> + <receiver>GraphPrefLayout</receiver> + <slot>slotColorClicked()</slot> + </connection> + <connection> + <sender>m_pFontButton</sender> + <signal>clicked()</signal> + <receiver>GraphPrefLayout</receiver> + <slot>slotFontClicked()</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotColorClicked()</slot> + <slot access="protected">slotFontClicked()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/graphwidget.cpp b/src/graphwidget.cpp new file mode 100644 index 0000000..00ca733 --- /dev/null +++ b/src/graphwidget.cpp @@ -0,0 +1,1162 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <math.h> +#include <stdlib.h> +#include <qfile.h> +#include <qpainter.h> +#include <qtooltip.h> +#include <klocale.h> +#include <kmessagebox.h> +#include "graphwidget.h" +#include "graphnode.h" +#include "graphedge.h" +#include "kscopeconfig.h" +#include "queryviewdlg.h" +#include "encoder.h" +#include "progressdlg.h" + +const char* GRAPH_DIRS[] = { "TB", "LR", "BT", "RL" }; + +const char TMP_TMPL[] = "/tmp/kscope_dot.XXXXXX"; +#define TMP_TMPL_SIZE (sizeof(TMP_TMPL) + 1) + +/** + * Displays a tool tip on the graph. + * Note that we cannot use the standard tool tip class here, since graph + * items are neither rectangular nor is their position known in advance. + * @author Elad Lahav + */ +class GraphTip : public QToolTip +{ +public: + /** + * Class constructor. + * @param pWidget Owner graph widget + */ + GraphTip(GraphWidget* pWidget) : QToolTip(pWidget->viewport()), + m_pGraphWidget(pWidget) {} + + /** + * Class destructor. + */ + virtual ~GraphTip() {} + +protected: + /** + * Called when the pre-conditions for a tool tip are met. + * Asks the owner for a tip to display and, if one is returned, shows + * the tool tip. + * @param ptPos Current mouse position + */ + virtual void maybeTip(const QPoint& ptPos) { + QString sText; + QRect rc; + + // Display a tip, if required by the owner + sText = m_pGraphWidget->getTip(ptPos, rc); + if (sText != QString::null) + tip(rc, sText); + } + +private: + /** The parent graph widget. */ + GraphWidget* m_pGraphWidget; +}; + +/** + * Provides a menu separator with text. + * The separator is added with QMenuData::insertItem(QWidget*). + * @author Elad Lahav + */ +class MenuLabel : public QLabel +{ +public: + /** + * Class constructor. + * @param sText The text to display + * @param pParent The parent widget + */ + MenuLabel(const QString& sText, QWidget* pParent) : + QLabel(sText, pParent) { + // Set the appropriate visual properties + setFrameShape(MenuBarPanel); + setAlignment(AlignHCenter | AlignVCenter); + setIndent(0); + } +}; + +ArrowInfo GraphWidget::s_ai; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +GraphWidget::GraphWidget(QWidget* pParent, const char* szName) : + QCanvasView(pParent, szName), + m_progress(this), + m_dot(this), + m_dZoom(1.0), + m_nMaxNodeDegree(10), // will be overriden by CallTreeDlg + m_nMultiCallNum(0), + m_pProgressDlg(NULL) +{ + // Automatically delete nodes when they are removed + m_dictNodes.setAutoDelete(true); + + // Create a canvas + setCanvas(new QCanvas(this)); + canvas()->setBackgroundColor(Config().getColor(KScopeConfig::GraphBack)); + + // Create a persistent Cscope process + m_pCscope = new CscopeFrontend(); + + // Add records output by the Cscope process + connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this, + SLOT(slotDataReady(FrontendToken*))); + + // Display query progress information + connect(m_pCscope, SIGNAL(progress(int, int)), this, + SLOT(slotProgress(int, int))); + + // Draw the graph when the process has finished + connect(m_pCscope, SIGNAL(finished(uint)), this, + SLOT(slotFinished(uint))); + + // Show a multi-call node when a query results in too many records + connect(m_pCscope, SIGNAL(aborted()), this, + SLOT(slotAborted())); + + // Redraw the graph when Dot exits + connect(&m_dot, SIGNAL(finished(uint)), this, SLOT(slotDotFinished())); + + // Create the node popup menu + m_pNodePopup = new QPopupMenu(this); + + m_pNodePopup->insertItem(new MenuLabel(i18n("<b>Called Functions</b>"), + m_pNodePopup)); + m_pNodePopup->insertItem(i18n("Show"), this, + SLOT(slotShowCalled())); + m_pNodePopup->insertItem(i18n("List/Filter..."), this, + SLOT(slotListCalled())); + m_pNodePopup->insertItem(i18n("Hide"), this, + SLOT(slotHideCalled())); + + m_pNodePopup->insertItem(new MenuLabel(i18n("<b>Calling Functions</b>"), + m_pNodePopup)); + m_pNodePopup->insertItem(i18n("Show"), this, + SLOT(slotShowCalling())); + m_pNodePopup->insertItem(i18n("List/Filter..."), this, + SLOT(slotListCalling())); + m_pNodePopup->insertItem(i18n("Hide"), this, + SLOT(slotHideCalling())); + + m_pNodePopup->insertItem(new MenuLabel(i18n("<b>This Function</b>"), + m_pNodePopup)); + m_pNodePopup->insertItem(i18n("Find Definition"), this, + SLOT(slotFindDef())); + m_pNodePopup->insertItem(i18n("Remove"), this, SLOT(slotRemoveNode())); + + // Create the multi-call node popup menu + m_pMultiCallPopup = new QPopupMenu(this); + m_pMultiCallPopup->insertItem(i18n("List..."), this, + SLOT(slotMultiCallDetails())); + m_pMultiCallPopup->insertSeparator(); + m_pMultiCallPopup->insertItem(i18n("Remove"), this, + SLOT(slotRemoveNode())); + + // Create the edge menu + m_pEdgePopup = new QPopupMenu(this); + m_pEdgePopup->insertItem(i18n("Open Call"), this, SLOT(slotOpenCall())); + + (void)new GraphTip(this); +} + +/** + * Class destructor. + */ +GraphWidget::~GraphWidget() +{ +} + +/** + * Creates a root node for the graph. + * The root node defines the connected component which is always displayed + * (all other connected components are removed when they are no longer + * strongly connected to the root). + * @param sFunc The function name for the root node + */ +void GraphWidget::setRoot(const QString& sFunc) +{ + // Insert a new node to the graph + addNode(sFunc); + draw(); +} + +/** + * Locates a node by its name and, if one does not exist, creates a new node. + * @param sFunc The name of a function + * @return The node corresponding to the given name + */ +GraphNode* GraphWidget::addNode(const QString& sFunc, bool bMultiCall) +{ + GraphNode* pNode; + + // Look for a node with the given name + if ((pNode = m_dictNodes.find(sFunc)) == NULL) { + // Node not found, create it + pNode = new GraphNode(canvas(), sFunc, bMultiCall); + m_dictNodes.insert(sFunc, pNode); + } + + // Return the found/created node + return pNode; +} + +/** + * Adds a call to the graph. + * A call is made between two functions, the caller and the callee. + * @param data Contains information on the call + */ +void GraphWidget::addCall(const CallData& data) +{ + GraphNode* pCaller, * pCallee; + GraphEdge* pEdge; + + // Find the relevant nodes (create new nodes if necessary) + pCaller = addNode(data.m_sCaller); + pCallee = addNode(data.m_sCallee); + + // Create a new edge + pEdge = pCaller->addOutEdge(pCallee); + pEdge->setCallInfo(data.m_sFile, data.m_sLine, data.m_sText); +} + +/** + * Creates a special node representing multiple calls to/from a function. + * Such a node is creates when the number of calls to/from a function exceeds + * a certain number. Thus the graph does not become too cluttered. + * A multiple call node can be replaced by some/all of the actual calls by + * using the "Details..." action in the node's popup menu. + * @param sFunc The parent function + * @param bCalled true if the multiple calls are called from that function, + * false if they are calling the function + */ +void GraphWidget::addMultiCall(const QString& sFunc, bool bCalled) +{ + QString sMulti; + GraphNode* pCaller, * pCallee; + GraphEdge* pEdge; + + // Create a unique name for the new node. + // The name is of the form 0XXX, where XXX is a hexadecimal number. + // We assume that no function starts with a digit, and that there are no + // more than 0xfff multi-call nodes in the graph. + sMulti.sprintf("0%.3x", m_nMultiCallNum); + m_nMultiCallNum = (m_nMultiCallNum + 1) & 0xfff; + + // Find the relevant nodes (create new nodes if necessary) + if (bCalled) { + pCaller = addNode(sFunc); + pCallee = addNode(sMulti, true); + } + else { + pCaller = addNode(sMulti, true); + pCallee = addNode(sFunc); + } + + // Create a new edge + pEdge = pCaller->addOutEdge(pCallee); +} + +/** + * Draws the graph on the canvas using the graphviz engine. + * A new canvas is created, so all items need to be regenerated. + * TODO: Can we use the same canvas and only reposition existing items? + */ +void GraphWidget::draw() +{ + QWMatrix mtx; + char szTempFile[TMP_TMPL_SIZE]; + int nFd; + FILE* pFile; + + // Do nothing if drawing process has already started + if (m_dot.isRunning()) + return; + + // Apply the zoom factor + mtx.scale(m_dZoom, m_dZoom); + setWorldMatrix(mtx); + + // Do not draw until the Dot process finishes + setUpdatesEnabled(false); + + // Open a temporary file + strcpy(szTempFile, TMP_TMPL); + nFd = mkstemp(szTempFile); + if ((pFile = fdopen(nFd, "w")) == NULL) + return; + + // Remember the file name (so it can be deleted later) + m_sDrawFilePath = szTempFile; + + // Write the graph contents to the temporary file + { + QTextStream str(pFile, IO_WriteOnly); + write(str, "graph", "--", false); + } + + // Close the file + fclose(pFile); + + // Draw the graph + if (m_dot.run(szTempFile)) { + // Create the progress dialogue + m_pProgressDlg = new ProgressDlg(i18n("KScope"), + i18n("Generating graph, please wait"), this); + m_pProgressDlg->setMinimumDuration(1000); + m_pProgressDlg->setValue(0); + + // TODO: + // Implement cancel (what do we do when the drawing process is + // terminated, even though the nodes and edges were already added by + // Cscope?) + // m_pProgressDlg->setAllowCancel(true); + } +} + +/** + * Stores a graph on a file. + * The file uses the dot language to describe the graph. + * @param pFile An open file to write to + */ +void GraphWidget::save(FILE* pFile) +{ + // Write the graph using the dot language + QTextStream str(pFile, IO_WriteOnly); + write(str, "digraph", "->", true); +} + +/** + * Exports a graph to a dot file. + * @param sFile The full path of the file to export to + */ +void GraphWidget::save(const QString& sFile) +{ + QFile file(sFile); + + // Open/create the file + if (!file.open(IO_WriteOnly)) + return; + + QTextStream str(&file); + write(str, "digraph", "->", false); +} + +/** + * Changes the zoom factor. + * @param bIn true to zoom in, false to zoom out + */ +void GraphWidget::zoom(bool bIn) +{ + QWMatrix mtx; + + // Set the new zoom factor + if (bIn) + m_dZoom *= 2.0; + else + m_dZoom /= 2.0; + + // Apply the transformation matrix + mtx.scale(m_dZoom, m_dZoom); + setWorldMatrix(mtx); +} + +/** + * Determines the initial zoom factor. + * This method is called from the file parser and therefore does not redraw + * the widget. + * @param dZoom The zoom factor to use + */ +void GraphWidget::setZoom(double dZoom) +{ + m_dZoom = dZoom; +} + +/** + * Changes the graph's direction 90 degrees counter-clockwise. + */ +void GraphWidget::rotate() +{ + QString sDir; + int i; + + // Get the current direction + sDir = Config().getGraphOrientation(); + + // Find the next direction + for (i = 0; i < 4 && sDir != GRAPH_DIRS[i]; i++); + if (i == 4) + i = 0; + else + i = (i + 1) % 4; + + // Set the new direction + sDir = GRAPH_DIRS[i]; + Config().setGraphOrientation(sDir); +} + +/** + * Checks if a tool tip is required for the given position. + * NOTE: We currently return a tool tip for edges only + * @param ptPos The position to query + * @param rc Holds the tip's rectangle, upon return + * @return The tip's text, or QString::null if no tip is required + */ +QString GraphWidget::getTip(const QPoint& ptPos, QRect& rc) +{ + QPoint ptRealPos, ptTopLeft, ptBottomRight; + QCanvasItemList il; + QCanvasItemList::Iterator itr; + GraphEdge* pEdge; + QString sText, sFile, sLine; + + ptRealPos = viewportToContents(ptPos); + ptRealPos /= m_dZoom; + pEdge = NULL; + + // Check if there is an edge at this position + il = canvas()->collisions(ptRealPos); + for (itr = il.begin(); itr != il.end(); ++itr) { + pEdge = dynamic_cast<GraphEdge*>(*itr); + if (pEdge != NULL) + break; + } + + // No tip if no edge was found + if (pEdge == NULL) + return QString::null; + + // Set the rectangle for the tip (the tip is closed when the mouse leaves + // this area) + rc = pEdge->tipRect(); + ptTopLeft = rc.topLeft(); + ptBottomRight = rc.bottomRight(); + ptTopLeft *= m_dZoom; + ptBottomRight *= m_dZoom; + ptTopLeft = contentsToViewport(ptTopLeft); + ptBottomRight = contentsToViewport(ptBottomRight); + rc = QRect(ptTopLeft, ptBottomRight); + + // Create a tip for this edge + return pEdge->getTip(); +} + +/** + * Resizes the canvas. + * @param nWidth The new width + * @param nHiehgt The new height + */ +void GraphWidget::resize(int nWidth, int nHeight) +{ + canvas()->resize(nWidth + 2, nHeight + 2); +} + +/** + * Displays a node on the canvas. + * Sets the parameters used for drawing the node on the canvas. + * @param sFunc The function corresponding to the node to draw + * @param rect The coordinates of the node's rectangle + */ +void GraphWidget::drawNode(const QString& sFunc, const QRect& rect) +{ + GraphNode* pNode; + + // Find the node + pNode = addNode(sFunc); + + // Set the visual aspects of the node + pNode->setRect(rect); + pNode->setZ(2.0); + pNode->setPen(QPen(Qt::black)); + pNode->setFont(Config().getFont(KScopeConfig::Graph)); + + if (pNode->isMultiCall()) + pNode->setBrush(Config().getColor(KScopeConfig::GraphMultiCall)); + else + pNode->setBrush(Config().getColor(KScopeConfig::GraphNode)); + + // Draw the node + pNode->show(); +} + +/** + * Displays an edge on the canvas. + * Sets the parameters used for drawing the edge on the canvas. + * @param sCaller Identifies the edge's head node + * @param sCallee Identifies the edge's tail node + * @param arrCurve Control points for the edge's spline + */ +void GraphWidget::drawEdge(const QString& sCaller, const QString& sCallee, + const QPointArray& arrCurve) +{ + GraphNode* pCaller, * pCallee; + GraphEdge* pEdge; + + // Find the edge + pCaller = addNode(sCaller); + pCallee = addNode(sCallee); + pEdge = pCaller->addOutEdge(pCallee); + + // Set the visual aspects of the edge + pEdge->setPoints(arrCurve, s_ai); + pEdge->setZ(1.0); + pEdge->setPen(QPen(Qt::black)); + pEdge->setBrush(QBrush(Qt::black)); + + // Draw the edge + pEdge->show(); +} + +#define PI 3.14159265 + +/** + * Sets and computes values used for drawing arrows. + * Initialises the static ArroInfo structure, which is passed in drawEdge(). + * @param nLength The arrow head length + * @param nDegrees The angle, in degrees, between the base line and each + * of the arrow head's sides + */ +void GraphWidget::setArrowInfo(int nLength, int nDegrees) +{ + double dRad; + + // Turn degrees into radians + dRad = ((double)nDegrees) * PI / 180.0; + + s_ai.m_dLength = (double)nLength; + s_ai.m_dTan = tan(dRad); + s_ai.m_dSqrt = sqrt(1 + s_ai.m_dTan * s_ai.m_dTan); +} + +/** + * Draws the contents of the canvas on this view. + * NOTE: This method is overriden to fix a strange bug in Qt that leaves + * a border around the canvas part of the view. It should be deleted once + * this bug is fixed. + * TODO: Is there a better way of erasing the border? + * @param pPainter Used to paint on the view + * @param nX The horizontal origin of the area to draw + * @param nY The vertical origin of the area to draw + * @param nWidth The width of the area to draw + * @param nHeight The height of the area to draw + */ +void GraphWidget::drawContents(QPainter* pPainter, int nX, int nY, + int nWidth, int nHeight) +{ + // Draw the contents of the canvas + QCanvasView::drawContents(pPainter, nX, nY, nWidth, nHeight); + + // Erase the canvas's area border + if (canvas() != NULL) { + QRect rect = canvas()->rect(); + pPainter->setBrush(QBrush()); // Null brush + pPainter->setPen(Config().getColor(KScopeConfig::GraphBack)); + pPainter->drawRect(-1, -1, rect.width() + 2, rect.height() + 2); + } +} + +/** + * Handles mouse clicks over the graph view. + * @param pEvent Includes information on the mouse press event + */ +void GraphWidget::contentsMousePressEvent(QMouseEvent* pEvent) +{ + QPoint ptRealPos; + QCanvasItemList il; + QCanvasItemList::Iterator itr; + QString sFunc; + GraphNode* pNode; + GraphEdge* pEdge; + + pNode = NULL; + pEdge = NULL; + + // Handle right-clicks only + if (pEvent->button() != Qt::RightButton) { + QCanvasView::contentsMousePressEvent(pEvent); + return; + } + + // Take the zoom factor into consideration + ptRealPos = pEvent->pos(); + ptRealPos /= m_dZoom; + + // Check if an item was clicked + il = canvas()->collisions(ptRealPos); + for (itr = il.begin(); itr != il.end(); ++itr) { + if (dynamic_cast<GraphNode*>(*itr) != NULL) + pNode = dynamic_cast<GraphNode*>(*itr); + else if (dynamic_cast<GraphEdge*>(*itr) != NULL) + pEdge = dynamic_cast<GraphEdge*>(*itr); + } + + // Handle clicks over different types of items + if (pNode != NULL) { + // Show a context menu for nodes + showNodeMenu(pNode, pEvent->globalPos()); + } + else if (pEdge != NULL) { + // Show a context menu for edges + showEdgeMenu(pEdge, pEvent->globalPos()); + } + else { + // Take the default action + QCanvasView::contentsMousePressEvent(pEvent); + } +} + +/** + * Writes a description of the graph to the given stream, using the Dot + * language. + * The method allows for both directed graphs and non-directed graphs, the + * latter are required for drawing purposes (since Dot will not produce the + * arrow heads and the splines terminate before reaching the nodes). + * @param str The stream to write to + * @param sType Either "graph" or "digraph" + * @param sEdge The edge connector ("--" or "->") + * @param bWriteCall true to write call information, false otherwise + */ +void GraphWidget::write(QTextStream& str, const QString& sType, + const QString& sEdge, bool bWriteCall) +{ + QFont font; + QDictIterator<GraphNode> itr(m_dictNodes); + GraphEdge* pEdge; + Encoder enc; + + font = Config().getFont(KScopeConfig::Graph); + + // Header + str << sType << " G {\n"; + + // Graph attributes + str << "\tgraph [rankdir=" << Config().getGraphOrientation() << ", " + << "kscope_zoom=" << m_dZoom + << "];\n"; + + // Default node attributes + str << "\tnode [shape=box, height=\"0.01\", style=filled, " + << "fillcolor=\"" << Config().getColor(KScopeConfig::GraphNode).name() + << "\", " + << "fontcolor=\"" << Config().getColor(KScopeConfig::GraphText).name() + << "\", " + << "fontname=\"" << font.family() << "\", " + << "fontsize=" << QString::number(font.pointSize()) + << "];\n"; + + // Iterate over all nodes + for (; itr.current(); ++itr) { + // Write a node + str << "\t" << itr.current()->getFunc() << ";\n"; + + // Iterate over all edges leaving this node + QDictIterator<GraphEdge> itrEdge(itr.current()->getOutEdges()); + for (; itrEdge.current(); ++itrEdge) { + pEdge = itrEdge.current(); + str << "\t" << pEdge->getHead()->getFunc() << sEdge + << pEdge->getTail()->getFunc(); + + // Write call information + if (bWriteCall) { + str << " [" + << "kscope_file=\"" << pEdge->getFile() << "\"," + << "kscope_line=" << pEdge->getLine() << "," + << "kscope_text=\"" << enc.encode(pEdge->getText()) << "\"" + << "]"; + } + + str << ";\n"; + } + } + + // Close the graph + str << "}\n"; +} + +/** + * Removes all edges attached to a function node at the given direction. + * Any strongly connected components that are no longer connected to that + * function are deleted. + * @param pNode The node for which to remove the edges + * @param bOut true for outgoing edges, false for incoming + */ +void GraphWidget::removeEdges(GraphNode* pNode, bool bOut) +{ + // Remove the edges + if (bOut) + pNode->removeOutEdges(); + else + pNode->removeInEdges(); + + // Remove all graph components no longer connected to this one + removeDisconnected(pNode); +} + +/** + * Removes all edges and nodes that are not weakly connected to the given node. + * This function is called to clean up the graph after edges were removed from + * the given node. + * @param pNode The node to which all other nodes have to be connected + */ +void GraphWidget::removeDisconnected(GraphNode* pNode) +{ + QDictIterator<GraphNode> itr(m_dictNodes); + + // Find all weakly connected components attached to this node + pNode->dfs(); + + // Delete all unmarked nodes, reset marked ones + while (itr.current()) { + if (!(*itr)->dfsVisited()) { + m_dictNodes.remove((*itr)->getFunc()); + } + else { + (*itr)->dfsReset(); + ++itr; + } + } +} + +/** + * Shows a popup menu for a node. + * This menu is shown after a node has been right-clicked. + * @param pNode The node for which to show the menu + * @param ptPos The position of the menu + */ +void GraphWidget::showNodeMenu(GraphNode* pNode, const QPoint& ptPos) +{ + // Remember the node + m_pMenuItem = pNode; + + // Show the popup menu. + if (pNode->isMultiCall()) + m_pMultiCallPopup->popup(ptPos); + else + m_pNodePopup->popup(ptPos); +} + +/** + * Shows a popup menu for an edge. + * This menu is shown after an edge has been right-clicked. + * @param pEdge The edge for which to show the menu + * @param ptPos The position of the menu + */ +void GraphWidget::showEdgeMenu(GraphEdge* pEdge, const QPoint& ptPos) +{ + // Remember the edge + m_pMenuItem = pEdge; + + // Show the popup menu. + m_pEdgePopup->popup(ptPos); +} + +/** + * Redraws the widget when new instructions are available. + * This slot is connected to the finished() signal emitted by the dot front- + * end. + */ +void GraphWidget::slotDotFinished() +{ + // Delete the temporary file + if (m_sDrawFilePath != "") { + QFile::remove(m_sDrawFilePath); + m_sDrawFilePath = ""; + } + + // Delete the progress dialogue + if (m_pProgressDlg) { + delete m_pProgressDlg; + m_pProgressDlg = NULL; + } + + setUpdatesEnabled(true); + canvas()->update(); +} + +/** + * Adds an entry to the tree, as the child of the active item. + * Called by a CscopeFrontend object, when a new entry was received in its + * whole from the Cscope back-end process. The entry contains the data of a + * function calling the function described by the active item. + * @param pToken The first token in the entry + */ +void GraphWidget::slotDataReady(FrontendToken* pToken) +{ + CallData data; + QString sFunc; + + // Get the file name + data.m_sFile = pToken->getData(); + pToken = pToken->getNext(); + + // Get the function name + sFunc = pToken->getData(); + pToken = pToken->getNext(); + + // Get the line number (do not accept global information on a call tree) + data.m_sLine = pToken->getData(); + if (data.m_sLine.toUInt() == 0) + return; + + pToken = pToken->getNext(); + + // Get the line's text + data.m_sText = pToken->getData(); + + // Determine the caller and the callee + if (m_bCalled) { + data.m_sCaller = m_sQueriedFunc; + data.m_sCallee = sFunc; + } + else { + data.m_sCaller = sFunc; + data.m_sCallee = m_sQueriedFunc; + } + + // Add the call to the graph + addCall(data); +} + +/** + * Displays search progress information. + * This slot is connected to the progress() signal emitted by a + * CscopeFrontend object. + * @param nProgress The current progress value + * @param nTotal The expected final value + */ +void GraphWidget::slotProgress(int nProgress, int nTotal) +{ + m_progress.setProgress(nProgress, nTotal); +} + +/** + * Disables the expandability feature of an item, if no functions calling it + * were found. + * @param nRecords Number of records reported by the query + */ +void GraphWidget::slotFinished(uint /*nRecords*/) +{ + // Destroy the progress bar + m_progress.finished(); + + // Redraw the graph + draw(); +} + +/** + * Adds a multiple call node when a query results in too many entries. + * This slot is attached to the aborted() signal of the Cscope process. + */ +void GraphWidget::slotAborted() +{ + KMessageBox::information(this, i18n("The query produced too many results.\n" + "A multiple-call node will appear in the graph instead.\n" + "Hint: The maximum number of in/out edges\n" + "can be adjusted by clicking the dialogue's \"Preferences\" button")); + + addMultiCall(m_sQueriedFunc, m_bCalled); + draw(); +} + +/** + * Shows functions called from the current function node. + * This slot is connected to the "Show Called Functions" popup menu + * action. + */ +void GraphWidget::slotShowCalled() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Run a query for called functions + m_sQueriedFunc = pNode->getFunc(); + m_bCalled = true; + m_pCscope->query(CscopeFrontend::Called, m_sQueriedFunc, true, + Config().getGraphMaxNodeDegree()); +} + +/** + * Shows a list of function calls from the current node. + * The list is displayed in a query dialogue. The user can the select which + * calls should be displayed in the graph. + * This slot is connected to the "List Called Functions" popup menu + * action. + */ +void GraphWidget::slotListCalled() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + QueryViewDlg dlg(0, (QWidget*)parent()); + + // Show the query view dialogue + dlg.query(CscopeFrontend::Called, pNode->getFunc()); + if (dlg.exec() != QDialog::Accepted) + return; + + // The OK button was clicked, replace current calls with the listed ones + pNode->removeOutEdges(); + + QueryView::Iterator itr; + CallData data; + + data.m_sCaller = pNode->getFunc(); + + // Add all listed calls + for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) { + data.m_sCallee = itr.getFunc(); + data.m_sFile = itr.getFile(); + data.m_sLine = itr.getLine(); + data.m_sText = itr.getText(); + + addCall(data); + } + + // Clean-up and redraw the graph + removeDisconnected(pNode); + draw(); +} + +/** + * Hides functions called from the current function node. + * This slot is connected to the "Hide Called Functions" popup menu + * action. + */ +void GraphWidget::slotHideCalled() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Remove edges and redraw the graph + removeEdges(pNode, true); + draw(); +} + +/** + * Shows functions calling tothe current function node. + * This slot is connected to the "Show Calling Functions" popup menu + * action. + */ +void GraphWidget::slotShowCalling() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Run a query for called functions + m_sQueriedFunc = pNode->getFunc(); + m_bCalled = false; + m_pCscope->query(CscopeFrontend::Calling, m_sQueriedFunc, true, + Config().getGraphMaxNodeDegree()); +} + +/** + * Shows a list of function calls to the current node. + * The list is displayed in a query dialogue. The user can the select which + * calls should be displayed in the graph. + * This slot is connected to the "List Calling Functions" popup menu + * action. + */ +void GraphWidget::slotListCalling() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + QueryViewDlg dlg(0, (QWidget*)parent()); + + // Show the query view dialogue + dlg.query(CscopeFrontend::Calling, pNode->getFunc()); + if (dlg.exec() != QDialog::Accepted) + return; + + // The OK button was clicked, replace current calls with the listed ones + pNode->removeInEdges(); + + QueryView::Iterator itr; + CallData data; + + data.m_sCallee = pNode->getFunc(); + + // Add all listed calls + for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) { + data.m_sCaller = itr.getFunc(); + data.m_sFile = itr.getFile(); + data.m_sLine = itr.getLine(); + data.m_sText = itr.getText(); + + addCall(data); + } + + // Clean-up and redraw the graph + removeDisconnected(pNode); + draw(); +} + +/** + * Hides functions calling to the current function node. + * This slot is connected to the "Hide CallingFunctions" popup menu + * action. + */ +void GraphWidget::slotHideCalling() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Remove edges and redraw the graph + removeEdges(pNode, false); + draw(); +} + +/** + * Looks up the definition of the current function node. + * This slot is connected to the "Find Definition" popup menu action. + */ +void GraphWidget::slotFindDef() +{ + GraphNode* pNode; + QueryViewDlg* pDlg; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Create a query view dialogue + pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this); + + // Display a line when it is selected in the dialogue + connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this, + SIGNAL(lineRequested(const QString&, uint))); + + // Start the query + pDlg->query(CscopeFrontend::Definition, pNode->getFunc()); +} + +/** + * Deletes a node from the graph (alogn with all edges connected to this + * node). + * The node removed is the one over which the context menu was invoked. + * This slot is connected to the "Remove" popup menu action. + */ +void GraphWidget::slotRemoveNode() +{ + GraphNode* pNode; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL) + return; + + // Remove all incoming edges + pNode->removeInEdges(); + + // Remove the node (also deletes the object and its outgoing edges) + m_dictNodes.remove(pNode->getFunc()); + + // Redraw the graph + draw(); +} + +/** + * Shows the list of calls that is represented by a single multi-call node. + * This slot handles the "Details..." command of the multi-call node menu. + */ +void GraphWidget::slotMultiCallDetails() +{ + GraphNode* pNode, * pParent; + bool bCalled; + + // Make sure the menu item is a node + pNode = dynamic_cast<GraphNode*>(m_pMenuItem); + if (pNode == NULL || !pNode->isMultiCall()) + return; + + // Get the required information from the node + pNode->getFirstNeighbour(pParent, bCalled); + if (!pParent) + return; + + QueryViewDlg dlg(0, (QWidget*)parent()); + + dlg.query(bCalled ? CscopeFrontend::Calling : CscopeFrontend::Called, + pParent->getFunc()); + dlg.exec(); +} + +/** + * Emits a signal to open an editor at the file and line matching the call + * information of the current edge. + * This slot is connected to the "Open Call" popup menu action (for edges). + */ +void GraphWidget::slotOpenCall() +{ + GraphEdge* pEdge; + QString sFile, sLine; + + // Make sure the menu item is an edge + pEdge = dynamic_cast<GraphEdge*>(m_pMenuItem); + if (pEdge != NULL && pEdge->getFile() != "") + emit lineRequested(pEdge->getFile(), pEdge->getLine()); +} + +#include "graphwidget.moc" diff --git a/src/graphwidget.h b/src/graphwidget.h new file mode 100644 index 0000000..119ddbb --- /dev/null +++ b/src/graphwidget.h @@ -0,0 +1,213 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef GRAPHWIDGET_H +#define GRAPHWIDGET_H + +#include <qcanvas.h> +#include <qpopupmenu.h> +#include <qdict.h> +#include "cscopefrontend.h" +#include "graphnode.h" +#include "dotfrontend.h" + +class ProgressDlg; + +/** + * A widget that displays call tree graphs generated by graphviz. + * This class is based on a QCanvasView widget, and displays two types of + * canvas items: GraphNode, which draws the name of a function inside a + * polygon, and ArrowEdge, which is a directed graph edge shaped like an + * arrow. + * The call tree graph is populated using the addNode() method. The first + * call creates a root node. Subsequent calls add nodes which represent either + * functions called by a previously inserted node, or that are calling such + * a node. A directed edge is created to depict the relationship between a + * node and its parent. + * Drawing is done through the embedded Agraph_t object (a graph, as defined + * by the graphviz libraray). When the draw() method is called, the graph is + * layed out in memory. The class then uses the CodeGenerator class to + * obtain a set of instructions on how to actually draw the graph. These + * instructions are used to create the appropriate canvas items. + * An application _must_ call GraphWidget::init() before attempting to use + * this class. It should also call GraphWidget::fini() when it no longer needs + * any of these widgets. + * @author Elad Lahav + */ +class GraphWidget : public QCanvasView +{ + Q_OBJECT + +public: + GraphWidget(QWidget* pParent = 0, const char* szName = 0); + ~GraphWidget(); + + /** + * Information on a function call, as produced by a Cscope query. + * This structure is used for adding calls to the graph. + * @see addCall() + */ + struct CallData + { + /** The name of the calling function. */ + QString m_sCaller; + + /** The name of the called function. */ + QString m_sCallee; + + /** Path of the file in which the call appears. */ + QString m_sFile; + + /** The line number of the call. */ + QString m_sLine; + + /** The call's text. */ + QString m_sText; + }; + + /** Graph orientation values. */ + enum Orientation { Portrait, Landscape }; + + void setRoot(const QString&); + GraphNode* addNode(const QString&, bool bMultiCall = false); + void addCall(const CallData&); + void addMultiCall(const QString&, bool); + void draw(); + void save(FILE*); + void save(const QString&); + void zoom(bool); + void setZoom(double); + void rotate(); + QString getTip(const QPoint&, QRect&); + + void resize(int, int); + void drawNode(const QString&, const QRect&); + void drawEdge(const QString&, const QString&, const QPointArray&); + + /** + * Adjusts the maximal number of calling/called functions shown for + * every node (@see m_nMaxNodeDegree). + * @param nMaxNodeDegree The new value to set + */ + void setMaxNodeDegree(int nMaxNodeDegree) { m_nMaxNodeDegree = + nMaxNodeDegree; } + + static void setArrowInfo(int, int); + +signals: + /** + * Emitted when the user makes a request to view the contents of a + * location in the source code. + * This can be the location of a call, the definition of a function, + * etc. + * @param sPath The full path of the file to show + * @param nLine The line number in this file + */ + void lineRequested(const QString& sPath, uint nLine); + +protected: + virtual void drawContents(QPainter*, int, int, int, int); + virtual void contentsMousePressEvent(QMouseEvent*); + +private: + /** The graph is stored as a map of nodes indexed by their names. + Each node holds a list of outgoing edges. */ + QDict<GraphNode> m_dictNodes; + + /** A Cscope process to use for running queries. */ + CscopeFrontend* m_pCscope; + + /** Displays query progress information. */ + CscopeProgress m_progress; + + /** A Dot process used to draw the graph. */ + DotFrontend m_dot; + + /** Remembers the function the was last queried for calling/called + functions. */ + QString m_sQueriedFunc; + + /** Remembers whether the last query was for calling or called + functions. */ + bool m_bCalled; + + /** The node over which the popup menu has been invoked. */ + QCanvasPolygonalItem* m_pMenuItem; + + /** A popup menu that appears when a node is right-clicked. */ + QPopupMenu* m_pNodePopup; + + /** A popup menu that appears when a node is right-clicked. */ + QPopupMenu* m_pMultiCallPopup; + + /** A popup menu that appears when an edge is right-clicked. */ + QPopupMenu* m_pEdgePopup; + + /** The zoom factor for the graph. */ + double m_dZoom; + + /** Maximal number of in/out edges per node. If this number is exceeded, + the graph shows a single "multi-call" node. */ + int m_nMaxNodeDegree; + + /** Holds information used to draw arrow heads. */ + static ArrowInfo s_ai; + + /** Used for generating unique names for multi-call nodes. */ + uint m_nMultiCallNum; + + /** Holds the path of the temporary dot file used for drawing the graph. */ + QString m_sDrawFilePath; + + /** Allows lengthy drawing operations to be cancelled. */ + ProgressDlg* m_pProgressDlg; + + void write(QTextStream&, const QString&, const QString&, bool); + void removeEdges(GraphNode*, bool); + void removeDisconnected(GraphNode*); + void showNodeMenu(GraphNode*, const QPoint&); + void showEdgeMenu(GraphEdge*, const QPoint&); + +private slots: + void slotDotFinished(); + void slotDataReady(FrontendToken*); + void slotProgress(int, int); + void slotFinished(uint); + void slotAborted(); + void slotShowCalled(); + void slotListCalled(); + void slotHideCalled(); + void slotShowCalling(); + void slotListCalling(); + void slotHideCalling(); + void slotFindDef(); + void slotRemoveNode(); + void slotMultiCallDetails(); + void slotOpenCall(); +}; + +#endif diff --git a/src/hi16-app-kscope.png b/src/hi16-app-kscope.png Binary files differnew file mode 100644 index 0000000..7659966 --- /dev/null +++ b/src/hi16-app-kscope.png diff --git a/src/hi32-app-kscope.png b/src/hi32-app-kscope.png Binary files differnew file mode 100644 index 0000000..54d2af0 --- /dev/null +++ b/src/hi32-app-kscope.png diff --git a/src/historypage.cpp b/src/historypage.cpp new file mode 100644 index 0000000..eabd6b6 --- /dev/null +++ b/src/historypage.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <klocale.h> +#include "historypage.h" +#include "historyview.h" + +int HistoryPage::s_nMaxPageID = 0; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +HistoryPage::HistoryPage(QWidget* pParent, const char* szName) : + QueryPageBase(pParent, szName), + m_nPageID(++s_nMaxPageID) +{ + m_pView = new HistoryView(this); + + connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this, + SIGNAL(lineRequested(const QString&, uint))); + + // Set colours and font + applyPrefs(); +} + +/** + * Class destructor. + */ +HistoryPage::~HistoryPage() +{ + if (s_nMaxPageID == m_nPageID) + s_nMaxPageID--; +} + +/** + * Creates a new position history record at the top of the list. + * @param sFile The file name associated with the record + * @param nLine The line number + * @param sText The text of the file at the given line + */ +void HistoryPage::addRecord(const QString& sFile, uint nLine, + const QString& sText) +{ + HistoryItem* pItem, * pNextItem; + + pItem = (HistoryItem*)m_pView->currentItem(); + if (pItem != NULL) { + // Do not add duplicate items + if ((pItem->text(1) == sFile) && (pItem->text(2).toUInt() == nLine)) + return; + + // Remove all items above the current one, so the new item is added to + // the top of the list + pItem = pItem->m_pPrevSibling; + while (pItem != NULL) { + pNextItem = pItem; + pItem = pItem->m_pPrevSibling; + delete pNextItem; + } + } + + // Create the new item at the top of the list + m_pView->addRecord("", sFile, QString::number(nLine), sText, NULL); +} + +/** + * Creates a new history item. + * This version is used when history records are read from a file. + * @param sFile The file name + * @param sLine The line number + * @param sText The contents of the line + */ +void HistoryPage::addRecord(const QString&, const QString& sFile, + const QString& sLine, const QString& sText) +{ + m_pView->addRecord("", sFile, sLine, sText, NULL); +} + +/** + * Creates a tab caption for this page, based on the unique page ID. + * @param bBrief true to use brief caption names, false otherwise + */ +QString HistoryPage::getCaption(bool bBrief) const +{ + return (bBrief ? QString(i18n("HIS ")) : QString(i18n("History "))) + + QString::number(m_nPageID); +} + +/** + * Creates a unique file name for saving the contents of the history page. + * @return The unique file name to use + */ +QString HistoryPage::getFileName(const QString&) const +{ + return QString("History_") + QString::number(m_nPageID); +} + +#include "historypage.moc" diff --git a/src/historypage.h b/src/historypage.h new file mode 100644 index 0000000..9ff614f --- /dev/null +++ b/src/historypage.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef HISTORYPAGE_H +#define HISTORYPAGE_H + +#include "querypagebase.h" + +/** + * A QueryWidget page for holding position history. + * @author Elad Lahav + */ +class HistoryPage : public QueryPageBase +{ + Q_OBJECT + +public: + HistoryPage(QWidget* pParent = 0, const char* szName = 0); + ~HistoryPage(); + + void addRecord(const QString&, uint, const QString&); + + virtual QString getCaption(bool bBrief = false) const; + +protected: + virtual void addRecord(const QString&, const QString&, const QString&, + const QString&); + virtual QString getFileName(const QString&) const; + + /** + * @return Always true, since History files do not contain a header + */ + virtual bool readHeader(QTextStream&) { return true; } + + /** + * This method does nothing, since History files do not contain a header. + */ + virtual void writeHeader(QTextStream&) {} + +private: + /** A unique ID used to create a tab caption for this page. */ + int m_nPageID; + + /** Used to generate the unique page ID for each object. */ + static int s_nMaxPageID; +}; + +#endif diff --git a/src/historyview.cpp b/src/historyview.cpp new file mode 100644 index 0000000..519c4dc --- /dev/null +++ b/src/historyview.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "historyview.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +HistoryView::HistoryView(QWidget* pParent, const char* szName) : + QueryView(pParent, szName) +{ + // Disable sorting + setSortColumn(-1); + + // Don't show the "Function" column + setColumnWidthMode(0, QListView::Manual); + setColumnWidth(0, 0); +} + +/** + * Class destructor. + */ +HistoryView::~HistoryView() +{ +} + +/** + * Creates a new list item showing a history record. + * @param sFunc The name of the function + * @param sFile The file path + * @param sLine The line number in the above file + * @param sText The line's text + */ +void HistoryView::addRecord(const QString& /* sFunc */, const QString& sFile, + const QString& sLine, const QString& sText, QListViewItem*) +{ + HistoryItem* pItem; + + pItem = new HistoryItem(this, sFile, sLine, sText); + setSelected(pItem, true); +} + +/** + * Moves to the previous item in the history, selecting it for display. + * Note that this function move to the item which chronologically precedes + * the current one, which, in list view terms, is the next item. + */ +void HistoryView::selectPrev() +{ + QListViewItem* pItem; + + // Get the current item + pItem = currentItem(); + + // Select the next item in the list + if (pItem != NULL && pItem->nextSibling() != NULL) { + pItem = pItem->nextSibling(); + select(pItem); + } +} + +/** + * Moves to the next item in the history, selecting it for display. + * Note that this function move to the item which chronologically succedes + * the current one, which, in list view terms, is the previous item. + */ +void HistoryView::selectNext() +{ + HistoryItem* pItem; + + // Get the current item + pItem = (HistoryItem*)currentItem(); + + // Select the previous item in the list + if (pItem != NULL && pItem->m_pPrevSibling != NULL) { + pItem = pItem->m_pPrevSibling; + select(pItem); + } +} + +/** + * Deletes the item on which a popup-menu has been invoked. + * This slot is connected to the remove() signal of the QueryResultsMenu + * object. + * @param pItem The item to remove + */ +void HistoryView::slotRemoveItem(QListViewItem* pItem) +{ + HistoryItem* pCurItem, * pNextItem; + + pCurItem = (HistoryItem*)pItem; + if ((pNextItem = (HistoryItem*)pCurItem->nextSibling()) != NULL) + pNextItem->m_pPrevSibling = pCurItem->m_pPrevSibling; + + delete pCurItem; +} + +#include "historyview.moc" diff --git a/src/historyview.h b/src/historyview.h new file mode 100644 index 0000000..38a0c46 --- /dev/null +++ b/src/historyview.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef HISTORYVIEW_H +#define HISTORYVIEW_H + +#include "queryview.h" + +/** + * A list view item for holding position history records. + * A QListViewItem cannot reference its preceding item, which is required to + * create a stack-like history list. Therefore a HistoryItem object + * stores a pointer to the item just above it in the list. The pointer is + * persistent, since the list cannot be sorted. + * @author Elad Lahav + */ + +class HistoryItem : public QListViewItem +{ +public: + /** + * Class constructor. + * @param pList The parent list view + * @param sFile The file path in this record + * @param sLine The line number + * @param sText The contents of the line in the given file + */ + HistoryItem(QListView* pList, QString sFile, QString sLine, + QString sText) : + QListViewItem(pList, "", sFile, sLine, sText), + m_pPrevSibling(NULL) { + HistoryItem* pNext; + + // Mark the new item as the predecessor of its next sibling + if ((pNext = (HistoryItem*)nextSibling()) != NULL) + pNext->m_pPrevSibling = this; + } + + /** The item immediately above this one in the list. */ + HistoryItem* m_pPrevSibling; +}; + +/** + * A list view widget for holding position history. + * Position history is kept in a stack-like list. Positions are always added + * to the top of the list, immediately before the current item. If the + * current item is not the top one, all items above it are purged first. + * To keep the stack-like structure, the list cannot be sorted. + * @author Elad Lahav + */ +class HistoryView : public QueryView +{ +Q_OBJECT +public: + HistoryView(QWidget* pParent = 0, const char* szName = 0); + ~HistoryView(); + + virtual void addRecord(const QString&, const QString&, const QString&, + const QString&, QListViewItem*); + virtual void selectNext(); + virtual void selectPrev(); + +protected slots: + virtual void slotRemoveItem(QListViewItem*); +}; + +#endif diff --git a/src/kscope.cpp b/src/kscope.cpp new file mode 100644 index 0000000..4a4ab60 --- /dev/null +++ b/src/kscope.cpp @@ -0,0 +1,1754 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfile.h> +#include <kfiledialog.h> +#include <kmenubar.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <klineedit.h> +#include <kinputdialog.h> +#include <kxmlguifactory.h> +#include <kstatusbar.h> +#include <kurldrag.h> +#include <kkeydialog.h> +#include "kscope.h" +#include "kscopeconfig.h" +#include "projectmanager.h" +#include "editortabs.h" +#include "fileview.h" +#include "filelist.h" +#include "querywidget.h" +#include "editormanager.h" +#include "cscopefrontend.h" +#include "ctagslist.h" +#include "newprojectdlg.h" +#include "openprojectdlg.h" +#include "preferencesdlg.h" +#include "dirscanner.h" +#include "querypage.h" +#include "calltreedlg.h" +#include "calltreemanager.h" +#include "kscopepixmaps.h" +#include "progressdlg.h" +#include "projectfilesdlg.h" +#include "cscopemsgdlg.h" +#include "symboldlg.h" +#include "symbolcompletion.h" +#include "queryviewdlg.h" +#include "graphwidget.h" +#include "makedlg.h" +#include "welcomedlg.h" +#include "bookmarksdlg.h" +#include "kscopeactions.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +KScope::KScope(QWidget* pParent, const char* szName) : + KParts::DockMainWindow(pParent, szName), + m_pCscopeBuild(NULL), + m_sCurFilePath(""), + m_nCurLine(0), + m_pProgressDlg(NULL), + m_bUpdateGUI(true), + m_bCscopeVerified(false), + m_bRebuildDB(false), + m_pMakeDlg(NULL) +{ + QString sPath; + + // Load configuration + Config().load(); + + // Create the main child widgets + m_pEditTabs = new EditorTabs(this, NULL); + m_pQueryWidget = new QueryWidget(this); + m_pFileView = new FileView(this); + m_pFileList = m_pFileView->getFileList(); + m_pMsgDlg = new CscopeMsgDlg(this); + m_pQueryDock = createDockWidget("Query Window", QPixmap()); + m_pFileViewDock = createDockWidget("File List Window", QPixmap()); + + // Connect menu and toolbar items with the object's slots + m_pActions = new KScopeActions(this); + m_pActions->init(); + m_pActions->slotEnableProjectActions(false); + + // Show a toolbar show/hide menu + setStandardToolBarMenuEnabled(true); + + // Create the initial GUI (no active part) + setXMLFile("kscopeui.rc"); + createShellGUI(); + + // Create all child widgets + initMainWindow(); + + // Create control objects + m_pProjMgr = new ProjectManager(); + m_pEditMgr = new EditorManager(this); + m_pCallTreeMgr = new CallTreeManager(this); + + // Initialise the icon manager + Pixmaps().init(); + + // Open a file for editing when selected in the project's file list or the + // file tree + connect(m_pFileView, SIGNAL(fileRequested(const QString&, uint)), this, + SLOT(slotShowEditor(const QString&, uint))); + + // Delete an editor page object after it is removed + connect(m_pEditTabs, SIGNAL(editorRemoved(EditorPage*)), + this, SLOT(slotDeleteEditor(EditorPage*))); + + connect(m_pEditTabs, SIGNAL(filesDropped(QDropEvent*)), this, + SLOT(slotDropEvent(QDropEvent*))); + + // Set an editor as the active part whenever its owner tab is selected + connect(m_pEditTabs, SIGNAL(editorChanged(EditorPage*, EditorPage*)), + this, SLOT(slotChangeEditor(EditorPage*, EditorPage*))); + + // Display a file at a specific line when selected in a query list + connect(m_pQueryWidget, SIGNAL(lineRequested(const QString&, uint)), + this, SLOT(slotQueryShowEditor(const QString&, uint))); + + // Display the symbol dialogue when the user opens a new query page + connect(m_pQueryWidget, SIGNAL(newQuery()), + this, SLOT(slotQueryReference())); + + // Rebuild the project database after a certain time period has elapsed + // since the last save + connect(&m_timerRebuild, SIGNAL(timeout()), this, SLOT(slotRebuildDB())); + + // Display a file at a specific line when selected in a call tree dialogue + connect(m_pCallTreeMgr, SIGNAL(lineRequested(const QString&, uint)), + this, SLOT(slotQueryShowEditor(const QString&, uint))); + + // Store main window settings when closed + setAutoSaveSettings(); + + // Initialise arrow head drawing + GraphWidget::setArrowInfo(20, 15); + + // Use a maximised window the first time + if (Config().isFirstTime()) + showMaximized(); + + // Show the Welcome message + if (Config().showWelcomeDlg()) { + show(); + slotShowWelcome(); + } + + // If this is the first time the user has launched KScope, prompt him/her + // to configure the global parameters + if (Config().isFirstTime()) + slotConfigure(); +} + +/** + * Class destructor. + */ +KScope::~KScope() +{ + // Save configuration + Config().store(); + Config().storeWorkspace(this); + + delete m_pCallTreeMgr; + delete m_pEditMgr; + delete m_pCscopeBuild; + delete m_pProjMgr; + + if (m_pMakeDlg != NULL) + delete m_pMakeDlg; +} + +/** + * Positions child widgets into their docking stations, and performs some + * other main window initialisation. + */ +void KScope::initMainWindow() +{ + KStatusBar* pStatus; + KDockWidget* pMainDock; + QPopupMenu* pPopup; + + // Create the status bar + pStatus = statusBar(); + pStatus->insertItem(i18n(" Line: N/A Col: N/A "), 0, 0, true); + + // Create the main dock for the editor tabs widget + pMainDock = createDockWidget("Editors Window", QPixmap()); + pMainDock->setWidget(m_pEditTabs); + pMainDock->setDockSite(KDockWidget::DockCorner); + setMainDockWidget(pMainDock); + setView(pMainDock); + pMainDock->setEnableDocking(KDockWidget::DockNone); + + // Create the query window dock + m_pQueryDock->setWidget(m_pQueryWidget); + m_pQueryDock->manualDock(pMainDock, KDockWidget::DockBottom, 65); + + // Update the relevant shell action when the dock is hidden through its + // close button + connect(m_pQueryDock, SIGNAL(headerCloseButtonClicked()), m_pActions, + SLOT(slotQueryDockClosed())); + + // Create the file view dock + m_pFileViewDock->setWidget(m_pFileView); + m_pFileViewDock->manualDock(pMainDock, KDockWidget::DockRight, 80); + + // Update the relevant shell action when the dock is hidden through its + // close button + connect(m_pFileViewDock, SIGNAL(headerCloseButtonClicked()), m_pActions, + SLOT(slotFileViewDockClosed())); + + // Associate the "Window" menu with the editor tabs widdget + pPopup = (QPopupMenu*)factory()->container("window", this); + m_pEditTabs->setWindowMenu(pPopup); + + // Associate the "Query" popup menu with the query widget + pPopup = (QPopupMenu*)factory()->container("query_popup", this); + m_pQueryWidget->setPageMenu(pPopup, m_pActions->getLockAction()); + + // Restore dock configuration + Config().loadWorkspace(this); + m_bHideQueryOnSelection = m_pQueryDock->isHidden(); + m_pActions->initLayoutActions(); +} + +/** + * Handles the "File->Quit" command. Closes the main window, which terminates + * the application. + */ +void KScope::slotClose() +{ + // Destroy the main window + KParts::DockMainWindow::close(); +} + +/** + * Called when a request has been issued to close the main window. + * Tries to close the active project. + * @return true if the main window can be closed, false otherwise + */ +bool KScope::queryClose() +{ + bool bResult; + + m_bUpdateGUI = false; + bResult = slotCloseProject(); + m_bUpdateGUI = true; + + return bResult; +} + +/** + * Handles the "Project->New..." command. + * Prompts the user for the name and folder for the project, and then creates + * the project. + */ +void KScope::slotCreateProject() +{ + NewProjectDlg dlg(true, this); + ProjectBase::Options opt; + QString sProjPath; + + // Prompt the user to close any active projects + if (m_pProjMgr->curProject()) { + if (KMessageBox::questionYesNo(0, + i18n("The current project needs to be closed before a new one is" + " created.\nWould you like to close it now?")) != + KMessageBox::Yes) { + return; + } + + // Try to close the project. + if (!slotCloseProject()) + return; + } + + // Display the "New Project" dialog + if (dlg.exec() != QDialog::Accepted) + return; + + // Create and open the new project + dlg.getOptions(opt); + if (m_pProjMgr->create(dlg.getName(), dlg.getPath(), opt, sProjPath)) + openProject(sProjPath); +} + +/** + * Handles the "Project->Open..." command. + * Prompts the user for a project file ("cscope.proj"), and opens the + * selected project. + */ +void KScope::slotOpenProject() +{ + OpenProjectDlg dlg; + QString sPath; + + if (dlg.exec() == QDialog::Rejected) + return; + + sPath = dlg.getPath(); + + // Check if the path refers to a permanent or temporary project + if (QFileInfo(sPath).isDir()) + openProject(sPath); + else + openCscopeOut(sPath); +} + +/** + * Handles the "Project->Add/Remove Files..." command. + * Opens the project's files dialog, which allows the user to add and remove + * source files. + */ +void KScope::slotProjectFiles() +{ + ProjectBase* pProj; + + // A project must be open + pProj = m_pProjMgr->curProject(); + if (!pProj) + return; + + // Cannot update the file list of a temporary project + if (pProj->isTemporary()) { + KMessageBox::error(0, i18n("The Add/Remove Files dialogue is not " + "available for temporary projects.")); + return; + } + + // Display the files dialog + ProjectFilesDlg dlg((Project*)pProj, this); + if (dlg.exec() != QDialog::Accepted) + return; + + // Update the project's file list + if (pProj->storeFileList(&dlg)) + slotProjectFilesChanged(); +} + +/** + * Handles the "Project->Properties..." command. + * Opens the project's properties dialog, which allows the user to change + * some attributes of the current project. + * source files. + */ +void KScope::slotProjectProps() +{ + ProjectBase* pProj; + ProjectBase::Options opt; + + // A project must be open + pProj = m_pProjMgr->curProject(); + if (!pProj) + return; + + // No properties for a temporary project + if (pProj->isTemporary()) { + KMessageBox::error(0, i18n("The Project Properties dialogue is not " + "available for temporary projects.")); + return; + } + + // Create the properties dialog + NewProjectDlg dlg(false, this); + pProj->getOptions(opt); + dlg.setProperties(pProj->getName(), pProj->getPath(), opt); + + // Display the properties dialog + if (dlg.exec() != QDialog::Accepted) + return; + + // Set new properties + dlg.getOptions(opt); + pProj->setOptions(opt); + + // Reset the CscopeFrontend class and the builder object + initCscope(); + + // Set auto-completion parameters + SymbolCompletion::initAutoCompletion(opt.bACEnabled, opt.nACMinChars, + opt.nACDelay, opt.nACMaxEntries); + + // Set per-project command-line arguments for Ctags + CtagsFrontend::setExtraArgs(opt.sCtagsCmd); + + // Set the source root + m_pFileView->setRoot(pProj->getSourceRoot()); +} + +/** + * Handles the "Cscope->Open Cscope.out..." menu command. + * Prompts the user for a Cscope.out file, and, if successful, opens a new + * session for working with this file. + */ +void KScope::slotProjectCscopeOut() +{ + QString sFilePath; + + // Prompt for a Cscope.out file + sFilePath = KFileDialog::getOpenFileName(); + if (sFilePath.isEmpty()) + return; + + // Open a temporary project + openCscopeOut(sFilePath); +} + +/** + * Handles the "Cscope->References..." menu command. + * Prompts the user for a symbol name, and initiates a query to find all + * references to that symbol. + */ +void KScope::slotQueryReference() +{ + slotQuery(SymbolDlg::Reference, true); +} + +/** + * Handles the "Cscope->Definition..." menu command. + * Prompts the user for a symbol name, and initiates a query to find the + * global definition of that symbol. + */ +void KScope::slotQueryDefinition() +{ + slotQuery(SymbolDlg::Definition, true); +} + +/** + * Handles the "Cscope->Called Functions..." menu command. + * Prompts the user for a function name, and initiates a query to find all + * function calls from that function. + */ +void KScope::slotQueryCalled() +{ + slotQuery(SymbolDlg::Called, true); +} + +/** + * Handles the "Cscope->Calling Functions..." menu command. + * Prompts the user for a function name, and initiates a query to find all + * functions calling that function. + */ +void KScope::slotQueryCalling() +{ + slotQuery(SymbolDlg::Calling, true); +} + +/** + * Handles the "Cscope->Find Text..." menu command. + * Prompts the user for a string, and initiates a query to find all +occurances + * of that string. + */ +void KScope::slotQueryText() +{ + slotQuery(SymbolDlg::Text, true); +} + +/** + * Handles the "Cscope->Find EGrep Pattern..." menu command. + * Prompts the user for a regular expression, and initiates a query to find + * all strings matching that pattern. + */ +void KScope::slotQueryPattern() +{ + slotQuery(SymbolDlg::Pattern, true); +} + +/** + * Handles the "Cscope->Find File..." menu command. + * Prompts the user for a file name, and initiates a query to find all files + * having that name. + */ +void KScope::slotQueryFile() +{ + slotQuery(SymbolDlg::FileName, true); +} + +/** + * Handles the "Cscope->Find Including Files..." menu command. + * Prompts the user for a file name, and initiates a query to find all files + * having an '#include' directive to that file. + */ +void KScope::slotQueryIncluding() +{ + slotQuery(SymbolDlg::Including, true); +} + +/** + * Handles the "Cscope->Quick Definition" menu command. + * Initiates a query to find the global definition of the symbol currently + * selected or under the cursor. The user is prompted only if no symbol can + * be found. + */ +void KScope::slotQueryQuickDef() +{ + QString sSymbol; + QueryViewDlg* pDlg; + uint nType; + bool bCase; + + // Get the requested symbol and query type + nType = SymbolDlg::Definition; + if (!getSymbol(nType, sSymbol, bCase, false)) + return; + + // Create a modeless query view dialogue + pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this); + + // Display a line when it is selected in the dialogue + connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotShowEditor(const QString&, uint))); + + // Start the query + pDlg->query(nType, sSymbol); +} + +/** + * Handles the "Cscope->Call Tree..." menu command. + * Displays a tree of functions calling the requested function. + */ +void KScope::slotCallTree() +{ + slotQuery(SymbolDlg::CallTree, true); +} + +/** + * Handles the "Cscope->Rebuild Database..." command. + * Rebuilds Cscope's database for the current project. + */ +void KScope::slotRebuildDB() +{ + ProjectBase* pProj; + + pProj = m_pProjMgr->curProject(); + if (!pProj) + return; + + if (!pProj->dbExists()) { + m_pProgressDlg = new ProgressDlg(i18n("KScope"), i18n("Please wait " + "while KScope builds the database"), this); + m_pProgressDlg->setAllowCancel(false); + m_pProgressDlg->setValue(0); + } + + m_pCscopeBuild->rebuild(); +} + +/** + * Handles the "Settings->Configure Shortcuts..." command. + * Displays the prferences dialog, which allows the user + * to change the shortcuts for KScope. + */ +void KScope::slotShortcuts() +{ + KKeyDialog::configure(actionCollection(), this); +} + +/** + * Handles the "Settings->Configure KScope..." command. + * Displays the prferences dialog, which allows the user to set different + * configuration parameters for KScope. + */ +void KScope::slotConfigure() +{ + PreferencesDlg dlg; + + // Apply the preferences if either the "Apply" or the "OK" buttons are + // clicked + connect(&dlg, SIGNAL(applyPref()), this, SLOT(slotApplyPref())); + + // Show the dialog + if (dlg.exec() == QDialog::Accepted) { + // Verify Cscope's installation + verifyCscope(); + } +} + +/** + * Refreshes the file list when files are added to or removed from a project, + * and rebuilds the Cscope database. + * This slot is attached to the fileListChanged() signal emitted by + * the ProjectManager object. + */ +void KScope::slotProjectFilesChanged() +{ + QStringList slArgs; + + // Refresh the file list + m_pFileList->setUpdatesEnabled(false); + m_pFileList->clear(); + m_pProjMgr->curProject()->loadFileList(m_pFileList); + m_pFileList->setUpdatesEnabled(true); + + // Rebuild the symbol database + if (isAutoRebuildEnabled()) + slotRebuildDB(); +} + +/** + * Adds a list of files to the current project. + * This slot is connected to the filesAdded() signal of the ProjectManager + * object. Once files are added to the project, they are also added to the + * file list, and the project's database is rebuilt. + * @param slFiles The list of file paths added to the project + */ +void KScope::slotFilesAdded(const QStringList& slFiles) +{ + QStringList::const_iterator itr; + + // Add the file paths to the project's file list + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) + m_pFileList->addItem(*itr); + + // Rebuild the database + if (isAutoRebuildEnabled()) + slotRebuildDB(); +} + +/** + * Promts the user for a symbol, an starts a new Cscope query. + * @param nType The numeric query type code + * @param bPrompt true to always prompt for a symbol, false to try to + * obtain the symbol automatically + */ +void KScope::slotQuery(uint nType, bool bPrompt) +{ + QString sSymbol; + CallTreeDlg* pCallTreeDlg; + bool bCase; + + // Get the requested symbol and query type + if (!getSymbol(nType, sSymbol, bCase, bPrompt)) + return; + + if (nType == SymbolDlg::CallTree) { + // Create and display a call tree dialogue + pCallTreeDlg = m_pCallTreeMgr->addDialog(); + pCallTreeDlg->setRoot(sSymbol); + pCallTreeDlg->show(); + } + else { + // Run the requested query + nType = SymbolDlg::getQueryType(nType); + m_pQueryWidget->initQuery(nType, sSymbol, bCase); + + // Ensure Query Window is visible + toggleQueryWindow(true); + } +} + +/** + * Opens a project. + * If another project is currently active, it is closed first. + * @param sDir The directory of the project to open. + */ +void KScope::openProject(const QString& sDir) +{ + QString sProjDir; + ProjectBase* pProj; + QStringList slQueryFiles; + QStringList slCallTreeFiles; + QStringList slArgs; + ProjectBase::Options opt; + + // Close the current project (may return false if the user clicks on the + // "Cancel" button while prompted to save a file) + if (!slotCloseProject()) + return; + + // Open the project in the project manager + sProjDir = QDir::cleanDirPath(sDir); + if (!m_pProjMgr->open(sProjDir)) + return; + + // Change main window title + pProj = m_pProjMgr->curProject(); + setCaption(pProj->getName()); + + // Set the root of the file tree + m_pFileView->setRoot(pProj->getSourceRoot()); + + // Initialise Cscope and create a builder object + initCscope(); + + // Set auto-completion parameters + pProj->getOptions(opt); + SymbolCompletion::initAutoCompletion(opt.bACEnabled, opt.nACMinChars, + opt.nACDelay, opt.nACMaxEntries); + + // Set per-project command-line arguments for Ctags + CtagsFrontend::setExtraArgs(opt.sCtagsCmd); + + // Create an initial query page + m_pQueryWidget->addQueryPage(); + + // Enable project-related actions + m_pActions->slotEnableProjectActions(true); + + // If this is a new project (i.e., no source files are yet included), + // display the project files dialogue + if (pProj->isEmpty()) { + slotProjectFiles(); + return; + } + + // Fill the file list with all files in the project. + m_pFileList->setUpdatesEnabled(false); + pProj->loadFileList(m_pFileList); + m_pFileList->setUpdatesEnabled(true); + + // Restore the last session + restoreSession(); + + // Rebuild the cross-reference database + if (isAutoRebuildEnabled()) { + // If Cscope installation was not yet verified, postpone the build + // process + if (m_bCscopeVerified) + slotRebuildDB(); + else + m_bRebuildDB = true; + } +} + +/** + * Opens a temporary project for a Cscope.out file. + * @param sFilePath The full path of the Cscope.out file + * @return true if successful, false otherwise + */ +bool KScope::openCscopeOut(const QString& sFilePath) +{ + ProjectBase* pProj; + + // Close the current project (may return false if the user clicks on the + // "Cancel" button while prompted to save a file) + if (!slotCloseProject()) + return false; + + // Open a temporary project for this cscope.out file + if (!m_pProjMgr->openCscopeOut(sFilePath)) + return false; + + // Change main window title + pProj = m_pProjMgr->curProject(); + setCaption(pProj->getName()); + + // Set the root folder in the file tree + m_pFileView->setRoot(pProj->getSourceRoot()); + + // Initialise Cscope and create a builder object + initCscope(); + + // Create an initial query page + m_pQueryWidget->addQueryPage(); + + // Enable project-related actions + m_pActions->slotEnableProjectActions(true); + + // Fill the file list with all files in the project. + m_pFileList->setUpdatesEnabled(false); + pProj->loadFileList(m_pFileList); + m_pFileList->setUpdatesEnabled(true); + + return true; +} + +/** + * Opens the most recently used project. + * This method is called when KScope starts, but only if the relevant + * configuration flag (Reload Last Project) is set. + */ +void KScope::openLastProject() +{ + const QStringList slProjects = Config().getRecentProjects(); + QString sPath; + + if (slProjects.empty()) + return; + + // Get the project's path + sPath = *slProjects.begin(); + + // Check if the path refers to a temporary project + if (!QFileInfo(sPath).isDir()) { + openCscopeOut(sPath); + return; + } + + openProject(sPath); +} + +/** + * Reopens all files which were open when the project was last closed. + * In order to reduce the time required by this operation, the GUI of all + * but the last editor part is not merged with that of the main window. + */ +void KScope::restoreSession() +{ + ProjectBase* pProj; + Project::Session sess; + FileLocation* pLoc; + EditorPage* pPage; + + // A session is available for persistent projects only + pProj = m_pProjMgr->curProject(); + if (!pProj || pProj->isTemporary()) + return; + + // Make sure all FileLocation objects are deleted + sess.fllOpenFiles.setAutoDelete(true); + sess.fllBookmarks.setAutoDelete(true); + + // Load the session + ((Project*)pProj)->loadSession(sess); + + // Do not update the GUI when loading the editor parts of the initially + // hidden windows + m_bUpdateGUI = false; + + for (pLoc = sess.fllOpenFiles.first(); pLoc != NULL; + pLoc = sess.fllOpenFiles.next()) { + if (QFile::exists(pLoc->m_sPath)) { + pPage = addEditor(pLoc->m_sPath); + pPage->setCursorPos(pLoc->m_nLine, pLoc->m_nCol); + } + } + + // Merge the GUI of the visible editor part + m_bUpdateGUI = true; + + // Set the active editor (or choose a default one) + if (m_pEditTabs->findEditorPage(sess.sLastFile, true) == NULL) + m_pEditTabs->findEditorPage(sess.fllOpenFiles.last()->m_sPath, true); + + // Reload bookmarks + m_pEditTabs->setBookmarks(sess.fllBookmarks); + + // Load previously stored queries and call trees + m_pQueryWidget->loadPages(pProj->getPath(), sess.slQueryFiles); + m_pCallTreeMgr->loadOpenDialogs(pProj->getPath(), sess.slCallTreeFiles); +} + +/** + * Shows or hides the query dock window. + * This function is only called internally, not as a result of a user's + * workspace action (e.g., clicking the "Show/Hide Query Window" toolbar + * button). Therefore it does not reflect the user's preference, which is + * kept through the m_bHideQueryOnSelection variable. + * @param bShow true to show the window, false to hide it + */ +void KScope::toggleQueryWindow(bool bShow) +{ + // Remember the user's preferences + if (bShow) + m_bHideQueryOnSelection = m_pQueryDock->isHidden(); + else + m_bHideQueryOnSelection = false; + + // Change the visibility state of the widget, if required + if (m_pQueryDock->isShown() != bShow) + m_pQueryDock->changeHideShowState(); + + // Synchronise with the menu command's state + m_pActions->slotQueryDockToggled(bShow); +} + +/** + * Parses the command line, after it was stripped of its KDE options. + * The command line may contain one of the following options: + * 1. A project file (named cscope.proj) + * 2. A Cscope cross-reference database + * 3. A list of source files + * @param pArgs Command line arguments + */ +void KScope::parseCmdLine(KCmdLineArgs* pArgs) +{ + QString sArg; + QFileInfo fi; + int i; + + // Loop over all arguments + for (i = 0; i < pArgs->count(); i++) { + // Verify the argument is a file or directory name + sArg = pArgs->arg(i); + fi.setFile(sArg); + if (!fi.exists()) + continue; + + // Handle the current argument + if (fi.isFile()) { + if (fi.fileName() == "cscope.proj") { + // Open a project file + openProject(fi.dirPath(true)); + return; + } else if (openCscopeOut(sArg)) { + // Opened the file as a cross-reference database + return; + } else { + // Assume this is a source file + slotShowEditor(sArg, 0); + } + } else if (fi.isDir()) { + // Treat the given path as a project directory + openProject(fi.absFilePath()); + return; + } + } +} + +/** + * Starts a shell script to ensure that Cscope is properly installed and to + * extract the supported command-line arguments. + */ +void KScope::verifyCscope() +{ + CscopeVerifier* pVer; + + statusBar()->message(i18n("Verifying Cscope installation...")); + + pVer = new CscopeVerifier(); + connect(pVer, SIGNAL(done(bool, uint)), this, + SLOT(slotCscopeVerified(bool, uint))); + + pVer->verify(); +} + +/** + * Initialises the CscopeFrontend class with the current project arguments, + * and creates an object used for rebuilding the symbol database. + */ +void KScope::initCscope() +{ + ProjectBase* pProj; + + // Delete the current object, if one exists + if (m_pCscopeBuild) + delete m_pCscopeBuild; + + // Initialise CscopeFrontend + pProj = m_pProjMgr->curProject(); + CscopeFrontend::init(pProj->getPath(), pProj->getArgs()); + + // Create a persistent Cscope process + m_pCscopeBuild = new CscopeFrontend(); + + // Show build progress information in the main status bar + connect(m_pCscopeBuild, SIGNAL(progress(int, int)), this, + SLOT(slotBuildProgress(int, int))); + connect(m_pCscopeBuild, SIGNAL(buildInvIndex()), this, + SLOT(slotBuildInvIndex())); + connect(m_pCscopeBuild, SIGNAL(finished(uint)), this, + SLOT(slotBuildFinished(uint))); + connect(m_pCscopeBuild, SIGNAL(aborted()), this, + SLOT(slotBuildAborted())); + + // Show errors in a modeless dialogue + connect(m_pCscopeBuild, SIGNAL(error(const QString&)), this, + SLOT(slotCscopeError(const QString&))); +} + +/** + * Closes the active project. + * Closing a project involves closing all of the editor windows (prompting + * the user for unsaved changes); terminating the Cscope process; and further + * clean-up of the project's data. + */ +bool KScope::slotCloseProject() +{ + ProjectBase* pProj; + Project::Session sess; + + // Do nothing if no project is open + pProj = m_pProjMgr->curProject(); + if (!pProj) + return true; + + // Make sure all FileLocation objects are deleted + sess.fllOpenFiles.setAutoDelete(true); + sess.fllBookmarks.setAutoDelete(true); + + // Close all open editor pages + if (m_pEditTabs->count() > 0) { + // Save session information for persistent projects + if (!pProj->isTemporary()) { + sess.sLastFile = m_pEditTabs->getCurrentPage()->getFilePath(); + m_pEditTabs->getOpenFiles(sess.fllOpenFiles); + m_pEditTabs->getBookmarks(sess.fllBookmarks); + } + + if (!m_pEditTabs->removeAllPages()) + return false; + } + + // Disable project-related actions + m_pActions->slotEnableProjectActions(false); + + // Destroy the make dialogue + if (m_pMakeDlg != NULL) { + // Save session information for persistent projects + if (!pProj->isTemporary()) { + sess.sMakeCmd = m_pMakeDlg->getCommand(); + sess.sMakeRoot = m_pMakeDlg->getDir(); + } + + delete m_pMakeDlg; + m_pMakeDlg = NULL; + } + + // Save session information for persistent projects + if (!pProj->isTemporary()) { + m_pQueryWidget->savePages(pProj->getPath(), sess.slQueryFiles); + m_pCallTreeMgr->saveOpenDialogs(pProj->getPath(), sess.slCallTreeFiles); + } + + // Close all query pages and call trees + m_pQueryWidget->slotCloseAll(); + m_pCallTreeMgr->closeAll(); + + // Store session information for persistent projects + if (!pProj->isTemporary()) + ((Project*)pProj)->storeSession(sess); + + // Close the project in the project manager, and terminate the Cscope + // process + m_pProjMgr->close(); + delete m_pCscopeBuild; + m_pCscopeBuild = NULL; + setCaption(QString::null); + + // Clear the contents of the file list + m_pFileView->clear(); + + // Reset queried symbols history + SymbolDlg::resetHistory(); + + // Remove any remaining status bar messages + statusBar()->message(""); + + return true; +} + +/** + * Handles the "Edit->Edit in External Editor" menu command. + * Invokes an external editor for the current file and line number. + */ +void KScope::slotExtEdit() +{ + QString sCmdLine; + KProcess proc; + + // Create the command line for the external editor + sCmdLine = Config().getExtEditor(); + sCmdLine.replace("%F", m_sCurFilePath); + sCmdLine.replace("%L", QString::number(m_nCurLine)); + + // Run the external editor + proc.setUseShell(true); + proc << sCmdLine; + proc.start(KProcess::DontCare); +} + +/** + * Handles the "Edit->Complete Symbol" menu command. + * Creates a list of possible completions for the symbol currently under the + * cursor. + */ +void KScope::slotCompleteSymbol() +{ + EditorPage* pPage; + + pPage = m_pEditTabs->getCurrentPage(); + if (pPage != NULL) + pPage->slotCompleteSymbol(); +} + +/** + * Handles the "Help->Show Welcome Message..." menu command. + * Displays the "Welcome" dialogue. + */ +void KScope::slotShowWelcome() +{ + WelcomeDlg dlg; + dlg.exec(); +} + +/** + * Handles the "Edit->Go To Tag" menu command. + * Sets the cursor to the edit box of the current tag list. + */ +void KScope::slotGotoTag() +{ + EditorPage* pPage; + + pPage = m_pEditTabs->getCurrentPage(); + if (pPage) + pPage->setTagListFocus(); +} + +/** + * Reports the results of the Cscope verification script. + * This slot is connected to the done() signal emitted by the CscopeVerifier + * object constructed in verifyCscope(). + */ +void KScope::slotCscopeVerified(bool bResult, uint nArgs) +{ + statusBar()->message(i18n("Verifying Cscope installation...Done"), 3000); + + // Mark the flag even if Cscope was not found, to avoid nagging the user + // (who may wish to use KScope even with Cscope disabled) + m_bCscopeVerified = true; + + // Prompt the user in case Cscope is not properly installed + if (!bResult) { + KMessageBox::error(0, i18n("Cscope may not be properly installed on " + "this system.\nPlease check the Cscope path specified in KScope's " + "configuration dialogue.")); + slotConfigure(); + return; + } + + // Set the discoverred supported command-line arguments + CscopeFrontend::setSupArgs(nArgs); + + // Build the database, if required + if (m_bRebuildDB) { + m_bRebuildDB = false; + slotRebuildDB(); + } +} + +/** + * Handles the "Project->Make..." menu command. + * Displays the make dialogue. + */ +void KScope::slotProjectMake() +{ + QString sCmd, sDir; + + // Create the make dialogue, if it does not exist + if (m_pMakeDlg == NULL) { + // Create the dialogue + m_pMakeDlg = new MakeDlg(); + + // Set make parameters for this project + m_pProjMgr->curProject()->getMakeParams(sCmd, sDir); + m_pMakeDlg->setCommand(sCmd); + m_pMakeDlg->setDir(sDir); + + // Show the relevant source location when an error link is clicked + connect(m_pMakeDlg, SIGNAL(fileRequested(const QString&, uint)), this, + SLOT(slotShowEditor(const QString&, uint))); + + // Show the dialogue + m_pMakeDlg->show(); + } + else if (m_pMakeDlg->isShown()) { + // The dialogue exists, and is visible, just raise it + m_pMakeDlg->raise(); + m_pMakeDlg->setActiveWindow(); + } + else { + // The dialogue exists but is closed, show it + m_pMakeDlg->show(); + } +} + +/** + * Handles the "Project->Remake..." menu command. + * Displays the make dialogue and runs the make command. + */ +void KScope::slotProjectRemake() +{ + // Make sure the make dialogue exists and is displayed + slotProjectMake(); + + // Run the make command + m_pMakeDlg->slotMake(); +} + +/** + * Handles the "Go->Global Bookmarks" menu command. + * Displays a dialogue with the set of all bookmarks currently set in this + * project. + */ +void KScope::slotShowBookmarks() +{ + BookmarksDlg dlg; + QString sPath; + uint nLine; + + // Load the bookmark list + m_pEditTabs->showBookmarks(dlg.getView()); + + // Show the dialogue + if (dlg.exec() != QDialog::Accepted) + return; + + // Go to the selected bookmark + dlg.getBookmark(sPath, nLine); + slotShowEditor(sPath, nLine); +} + +/** + * Prompts the user for a symbol to query. + * Shows a dialog with a line edit widget, where the user can enter a symbol + * on which to query Cscope. The meaning of the symbol depends on the type of + * query. + * @param nType The requested type of query (may be changed in the + * dialogue) + * @param sSymbol Holds the requested symbol, upon successful return + * @param bPrompt If false, the user is prompted only if a symbol cannot be + * determined automatically + * @return true if the user hs enetered a symbol, false otherwise + */ +bool KScope::getSymbol(uint& nType, QString& sSymbol, bool& bCase, + bool bPrompt) +{ + EditorPage* pPage; + QString sSuggested; + + // Set the currently selected text, if any + if ((pPage = m_pEditTabs->getCurrentPage()) != NULL) + sSuggested = pPage->getSuggestedText(); + + // Return if a symbol was found, and prompting is turned off + if (!sSuggested.isEmpty() && !bPrompt) { + sSymbol = sSuggested; + return true; + } + + // Show the symbol dialogue + sSymbol = SymbolDlg::promptSymbol(this, nType, sSuggested, bCase); + + // Cannot accept empty strings + if (sSymbol.isEmpty()) + return false; + + return true; +} + +/** + * Opens a file in a new editor tab. + * If an editor page already exists for the requested file, it is selected. + * Otherwise, a new page is created, and the requested file is loaded. + * @param sFilePath The path of the file to open + * @return A pointer to the found or newly created editor page + */ +EditorPage* KScope::addEditor(const QString& sFilePath) +{ + EditorPage* pPage; + QString sAbsFilePath; + ProjectBase* pProj; + + // If the file name is given using a relative path, we need to convert + // it to an absolute one + // TODO: Project needs a translatePath() method + pProj = m_pProjMgr->curProject(); + if (sFilePath[0] != '/' && pProj) { + sAbsFilePath = QDir::cleanDirPath(pProj->getSourceRoot() + "/" + + sFilePath); + } + else { + sAbsFilePath = QDir::cleanDirPath(sFilePath); + } + + // Do not open a new editor if one exists for this file + pPage = m_pEditTabs->findEditorPage(sAbsFilePath); + if (pPage != NULL) + return pPage; + + // Create a new page + pPage = createEditorPage(); + + // Open the requested file + pPage->open(sAbsFilePath); + + return pPage; +} + +/** + * Creates a new editor page, and adds it to the editors tab widget. + * @return A pointer to the new page + */ +EditorPage* KScope::createEditorPage() +{ + KTextEditor::Document* pDoc; + EditorPage* pPage; + QPopupMenu* pMenu; + ProjectBase* pProj; + + // Load a new document part + pDoc = m_pEditMgr->add(); + if (pDoc == NULL) + return NULL; + + // Create the new editor page + pMenu = (QPopupMenu*)factory()->container(Config().getEditorPopupName(), + this); + pPage = new EditorPage(pDoc, pMenu, m_pEditTabs); + m_pEditTabs->addEditorPage(pPage); + + // Show the file's path in the main title + connect(pPage, SIGNAL(fileOpened(EditorPage*, const QString&)), this, + SLOT(slotFileOpened(EditorPage*, const QString&))); + + // Show cursor position in the status bar + connect(pPage, SIGNAL(cursorPosChanged(uint, uint)), this, + SLOT(slotShowCursorPos(uint, uint))); + + // Rebuild the database after a file has changed + connect(pPage, SIGNAL(fileSaved(const QString&, bool)), this, + SLOT(slotFileSaved(const QString&, bool))); + + // Handle file drops + connect(pPage->getView(), SIGNAL(dropEventPass(QDropEvent*)), this, + SLOT(slotDropEvent(QDropEvent*))); + + // Apply per-project configuration + pProj = m_pProjMgr->curProject(); + if (pProj && pProj->getTabWidth() > 0) + pPage->setTabWidth(pProj->getTabWidth()); + + return pPage; +} + +/** + * @return true if database auto-rebuild is enabled for the current project, + * false otherwise + */ +inline bool KScope::isAutoRebuildEnabled() +{ + ProjectBase* pProj; + + pProj = m_pProjMgr->curProject(); + return (pProj && pProj->getAutoRebuildTime() >= 0); +} + +/** + * Deletes an editor page after it has been removed. + * The document object associated with the page is removed from the part + * manager, and the view object is removed from the GUI manager. + * This slot is connected to the editorRemoved() signal of the EditorTabs + * object. + * @param pPage The editor page to delete + */ +void KScope::slotDeleteEditor(EditorPage* pPage) +{ + guiFactory()->removeClient(pPage->getView()); + m_pEditMgr->remove(pPage->getDocument()); + delete pPage; +} + +/** + * Sets an editor part as active when its owner tab is chosen. + * Whenever a different editor tab is chosen, its editor part should become + * the active part. This means that this part's GUI is merged with the + * application's, and that it responds to actions. + * @param pOldPage The editor page that has ceased to be active + * @param pNewPage The newly chosen editor page + */ +void KScope::slotChangeEditor(EditorPage* pOldPage, EditorPage* pNewPage) +{ + KXMLGUIFactory* pFactory = guiFactory(); + + // Remove the current GUI + if (pOldPage) + pFactory->removeClient(pOldPage->getView()); + + // Set the new active part and create its GUI + if (m_bUpdateGUI && pNewPage) { + m_pEditMgr->setActivePart(pNewPage->getDocument()); + pFactory->addClient(pNewPage->getView()); + m_sCurFilePath = pNewPage->getFilePath(); + setCaption(m_pProjMgr->getProjName() + " - " + m_sCurFilePath); + } + + // Enable/disable file-related actions, if necessary + if (pOldPage && !pNewPage) + m_pActions->slotEnableFileActions(false); + else if (!pOldPage && pNewPage) + m_pActions->slotEnableFileActions(true); +} + +/** + * Opens an editor for the given file and sets the cursor to the beginning of + * the requested line. + * @param sFilePath The full path of the file to open for editing + * @param nLine The number of the line on which to position the + * cursor, or 0 to maintain the cursor in its current + * position (which does not affect the position history) + */ +void KScope::slotShowEditor(const QString& sFilePath, uint nLine) +{ + EditorPage* pPage; + + // Save current position in the position history + if (nLine != 0 && (pPage = m_pEditTabs->getCurrentPage())) { + m_pQueryWidget->addHistoryRecord(m_sCurFilePath, m_nCurLine, + pPage->getLineContents(m_nCurLine)); + } + + // Open the requested file (or select an already-open editor page) + pPage = addEditor(sFilePath); + if (pPage == NULL) + return; + + // Make sure the main window is visible + raise(); + setWindowState(windowState() & ~WindowMinimized | WindowActive); + + if (nLine != 0) { + // Set the cursor to the requested line + pPage->slotGotoLine(nLine); + + // Add the new position to the position history + m_pQueryWidget->addHistoryRecord(m_sCurFilePath, m_nCurLine, + pPage->getLineContents(m_nCurLine)); + } +} + +/** + * A wrapper around slotShowEditor, that enables auto-hiding of the query + * widget after a query result has been chosen. + * This slot is connected to the lineRequested() signal emitted by a QueryPage + * object. + * @param sFilePath The full path of the file to open for editing + * @param nLine The number of the line on which to position the cursor + */ +void KScope::slotQueryShowEditor(const QString& sFilePath, uint nLine) +{ + // Hide the query window, if it was hidden before a query was initiated + if (m_bHideQueryOnSelection) + toggleQueryWindow(false); + + // Open an editor at the requested line + slotShowEditor(sFilePath, nLine); +} + +/** + * Handles the "Go->Position History" menu command. + * Ensures that the query window is visible, and selects the active history + * page. + */ +void KScope::slotHistoryShow() +{ + toggleQueryWindow(true); + m_pQueryWidget->selectActiveHistory(); +} + +/** + * Handles the "File->New" menu command. + * Creates an editor page for a new unnamed file. + */ +void KScope::slotNewFile() +{ + EditorPage* pPage; + + // Create the new editor page + pPage = createEditorPage(); + + // Mark the page as containing a new file + pPage->setNewFile(); +} + +/** + * Handles the "File->Open" menu command. + * Prompts the user for a file name, and opens it in a new editor page. + */ +void KScope::slotOpenFile() +{ + ProjectBase* pProj; + QStringList slFiles; + QStringList::Iterator itr; + + // Prompt the user for the file(s) to open. + pProj = m_pProjMgr->curProject(); + slFiles = KFileDialog::getOpenFileNames(pProj ? pProj->getSourceRoot() : + QString::null); + + // Open all selected files. + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) { + if (!(*itr).isEmpty()) + slotShowEditor(*itr, 0); + } +} + +/** + * Handles the "File->Close" menu command. + * Closes the currently active editor page. + */ +void KScope::slotCloseEditor() +{ + m_pEditTabs->removeCurrentPage(); +} + +/** + * Handles the "Window->Close All" menu command. + * Closes all open editor pages. + */ +void KScope::slotCloseAllWindows() +{ + m_bUpdateGUI = false; + m_pEditTabs->removeAllPages(); + m_bUpdateGUI = true; +} + +/** + * Displays error messages from a Cscope process. + * This slot is connected to the progress() signal emitted by the any + * Cscope process. + * @param sMsg The error message + */ +void KScope::slotCscopeError(const QString& sMsg) +{ + m_pMsgDlg->addText(sMsg); +} + +/** + * Reports progress information from the Cscope process responsible for + * rebuilding the cross-reference database. + * This slot is connected to the progress() signal emitted by the builder + * process. + * Progress information is displayed in the status bar. + * @param nFiles The number of files scanned + * @param nTotal The total number of files in the project + */ +void KScope::slotBuildProgress(int nFiles, int nTotal) +{ + QString sMsg; + + // Use the progress dialogue, if it exists (first time builds) + if (m_pProgressDlg) { + m_pProgressDlg->setValue((nFiles * 100) / nTotal); + return; + } + + // Show progress information + sMsg = i18n("Rebuilding the cross reference database...") + " " + + QString::number((nFiles * 100) / nTotal) + "%"; + statusBar()->message(sMsg); +} + +/** + * Reports to the user that Cscope has started building the inverted index. + * This slot is connected to the buildInvIndex() signal emitted by the + * builder process. + */ +void KScope::slotBuildInvIndex() +{ + if (m_pProgressDlg) { + m_pProgressDlg->setLabel(i18n("Please wait while KScope builds the " + "inverted index")); + m_pProgressDlg->setIdle(); + return; + } + + statusBar()->message(i18n("Rebuilding inverted index...")); +} + +/** + * Informs the user the database rebuild process has finished. + * This slot is connected to the finished() signal emitted by the builder + * process. + */ +void KScope::slotBuildFinished(uint) +{ + // Delete the progress dialogue, if it exists (first time builds) + if (m_pProgressDlg) { + delete m_pProgressDlg; + m_pProgressDlg = NULL; + return; + } + + // Show a message in the status bar + statusBar()->message(i18n("Rebuilding the cross reference database..." + "Done!"), 3000); +} + +/** + * Called if the build process failed to complete. + * This slot is connected to the aborted() signal emitted by the builder + * process. + */ +void KScope::slotBuildAborted() +{ + // Delete the progress dialogue, if it exists (first time builds) + if (m_pProgressDlg) { + delete m_pProgressDlg; + m_pProgressDlg = NULL; + + // Display a failure message + KMessageBox::error(0, i18n("The database could not be built.\n" + "Cross-reference information will not be available for this " + "project.\n" + "Please ensure that the Cscope parameters were correctly " + "entered in the \"Settings\" dialogue.")); + return; + } + + // Show a message in the status bar + statusBar()->message(i18n("Rebuilding the cross reference database..." + "Failed"), 3000); +} + +/** + * Applies the selected user preferences once the "Apply" or "OK" buttons in + * the preferences dialog is clicked. + */ +void KScope::slotApplyPref() +{ + m_pQueryWidget->applyPrefs(); + m_pFileList->applyPrefs(); + m_pEditTabs->applyPrefs(); + m_pEditMgr->applyPrefs(); + + // Enable/disable the external editor menu item + m_pActions->enableExtEditor(Config().useExtEditor()); +} + +/** + * Displays the current cursor position, whenever it is moved by the user. + * This slot is connected to the cursorPosChanged() signal emitted by an + * EditorPage object. + * @param nLine The new line number + * @param nCol The new column number + */ +void KScope::slotShowCursorPos(uint nLine, uint nCol) +{ + KStatusBar* pStatus = statusBar(); + QString sText; + + /* Show the line and column numbers. */ + QTextOStream(&sText) << " Line: " << nLine << " Col: " << nCol << " "; + pStatus->changeItem(sText, 0); + + /* Store the current line. */ + m_nCurLine = nLine; +} + +/** + * Stores the path of a newly opened file. + * This slot is connected to the fileOpened() signal emitted by an + * EditorPage object. + * @param sFilePath The full path of the opened file + */ +void KScope::slotFileOpened(EditorPage*, const QString& sFilePath) +{ + m_sCurFilePath = sFilePath; + setCaption(m_pProjMgr->getProjName() + " - " + m_sCurFilePath); +} + +/** + * Sets a timer for rebuilding the database after a file has been saved. + * This slot is connected to the fileSaved() signal emitted by an EditorPage + * object. + * The time period before rebuilding is determined on a per-project basis. + * @param sPath The full path of the modified file that caused this event + * @param bIsNew true if this is a new file, false otherwise + */ +void KScope::slotFileSaved(const QString& sPath, bool bIsNew) +{ + ProjectBase* pProj; + int nTime; + + pProj = m_pProjMgr->curProject(); + if (!pProj) + return; + + // Prompt the user to add this file to the current project + if (bIsNew && !pProj->isTemporary()) { + if (KMessageBox::questionYesNo(0, + i18n("Whould you like to add this file to the active project?")) == + KMessageBox::Yes) { + + // Add the path to the 'cscope.files' file + if (!((Project*)pProj)->addFile(sPath)) { + KMessageBox::error(0, i18n("Failed to write the file list.")); + return; + } + + // Add the path to the file list widget + m_pFileList->addItem(sPath); + + // Rebuild immediately + slotRebuildDB(); + return; + } + } + + // Get the project's auto-rebuild time + nTime = pProj->getAutoRebuildTime(); + + // Do nothing if the time is set to -1 + if (nTime == -1) + return; + + // Check if the file is included in the project (external files should + // not trigger the timer) + if (!m_pFileList->findFile(sPath)) + return; + + // Rebuild immediately for a time set to 0 + if (nTime == 0) { + slotRebuildDB(); + return; + } + + // Reset the rebuild timer + m_timerRebuild.start(nTime * 1000, true); +} + +/** + * Handles file drops inside the editors tab widget. + * Opens all files dropped over the widget. + * @param pEvent Pointer to an object containing the list of dropped files + */ +void KScope::slotDropEvent(QDropEvent* pEvent) +{ + KURL::List list; + KURL::List::Iterator itr; + + // Create a list of file URLs + if (!KURLDrag::decode(pEvent, list)) + return; + + // Open all files in the list + for (itr = list.begin(); itr != list.end(); ++itr) + addEditor((*itr).path()); +} + +#include "kscope.moc" diff --git a/src/kscope.desktop b/src/kscope.desktop new file mode 100644 index 0000000..453a4fc --- /dev/null +++ b/src/kscope.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=KScope +Exec=kscope +Icon=kscope +Type=Application +Comment=Source-editing environment for large C projects +Comment[fr]=Editeur de codes sources pour de gros projets en C +GenericName=Source editing environment +GenericName[fr]=Editeur de code source +Categories=Qt;KDE;Development + diff --git a/src/kscope.h b/src/kscope.h new file mode 100644 index 0000000..f1b646e --- /dev/null +++ b/src/kscope.h @@ -0,0 +1,235 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef KSCOPE_H +#define KSCOPE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qtimer.h> +#include <kcmdlineargs.h> +#include <kapp.h> +#include <kparts/dockmainwindow.h> +#include <kparts/part.h> + +class ProjectManager; +class EditorTabs; +class FileView; +class FileList; +class QueryWidget; +class EditorManager; +class CscopeFrontend; +class EditorPage; +class ProgressDlg; +class CscopeMsgDlg; +class MakeDlg; +class CallTreeManager; +class KScopeActions; + +/** + * Defines the main window of KScope. + * The main window has both UI and functional tasks. As a window, it is + * composed of three parts: + * 1. The editing area (EditorTabs - a tab widget with editor pages) + * 2. The project pane (FileList - listing the files in the project) + * 3. The query pane (QueryWidget - a tab widget with pages displaying query + * results in lists) + * The main window also maintains the main menu, the toolbar and the status- + * bar, and is responsible for handling all the actions connected to these + * bars. + * As the application's main class, it is responsible for managing projects + * (using a ProjectManager object) and for running instances of Cscope + * (through a CscopeFrontend object). + * @author Elad Lahav + */ +class KScope : public KParts::DockMainWindow +{ + Q_OBJECT + +public: + KScope(QWidget* pParent = 0, const char* szName = 0); + ~KScope(); + + void openProject(const QString&); + void openLastProject(); + bool openCscopeOut(const QString&); + void parseCmdLine(KCmdLineArgs *pArgs); + void verifyCscope(); + +public slots: + void slotClose(); + +protected: + virtual bool queryClose(); + +private: + /** A project manager used to load projects and read their properties. */ + ProjectManager* m_pProjMgr; + + /** The editors tabbed window. */ + EditorTabs* m_pEditTabs; + + /** The file selection widget (project file list and OS file system + tree.) */ + FileView* m_pFileView; + + /** Pointer to the file list part of the FileView widget. */ + FileList* m_pFileList; + + /** The query results tabbed window. */ + QueryWidget* m_pQueryWidget; + + /** A KDE editor part manager, responsible for creating KTextEditor + parts. */ + EditorManager* m_pEditMgr; + + /** A Cscope process for building the database. */ + CscopeFrontend* m_pCscopeBuild; + + /** A timer for rebuilding the database after a file has been saved. */ + QTimer m_timerRebuild; + + /** Whether the query window should be hidden after the user selects an + item. */ + bool m_bHideQueryOnSelection; + + /** The file view docking area. */ + KDockWidget* m_pFileViewDock; + + /** The query window docking area. */ + KDockWidget* m_pQueryDock; + + /** A persistent dialog used to display error messages from Cscope. */ + CscopeMsgDlg* m_pMsgDlg; + + /** The path of the file currently being edited. */ + QString m_sCurFilePath; + + /** The line number of the current cursor position. */ + int m_nCurLine; + + /** Creates and maintains call tree dialogues. */ + CallTreeManager* m_pCallTreeMgr; + + /** A progress dialogue that is displayed when building the database for + the first time. */ + ProgressDlg* m_pProgressDlg; + + /** A flag indicating whether the GUI of the embedded editor should be + merged with that of KScope's. Can be turned off to save time when + loading/closing a number of editor parts. */ + bool m_bUpdateGUI; + + /** Set to true after a shell script has verified that Cscope is installed + and correctly configured on this system. + No Cscope operations should be run if this flag is set to false. */ + bool m_bCscopeVerified; + + /** + * Used to postpone rebuilding of the database, until Cscope is ready. + */ + bool m_bRebuildDB; + + /** + * A widget for running make. + */ + MakeDlg* m_pMakeDlg; + + /** + * Manages menu and tool-bar commands. + */ + KScopeActions* m_pActions; + + void initMainWindow(); + void initCscope(); + bool getSymbol(uint&, QString&, bool&, bool bPrompt = true); + EditorPage* addEditor(const QString&s); + EditorPage* createEditorPage(); + inline bool isAutoRebuildEnabled(); + void restoreSession(); + void toggleQueryWindow(bool); + + friend class KScopeActions; + +private slots: + // Menu actions + void slotNewFile(); + void slotOpenFile(); + void slotCloseEditor(); + void slotCreateProject(); + void slotOpenProject(); + void slotProjectFiles(); + void slotProjectProps(); + void slotProjectCscopeOut(); + bool slotCloseProject(); + void slotQueryReference(); + void slotQueryDefinition(); + void slotQueryCalled(); + void slotQueryCalling(); + void slotQueryText(); + void slotQueryPattern(); + void slotQueryFile(); + void slotQueryIncluding(); + void slotQueryQuickDef(); + void slotCallTree(); + void slotRebuildDB(); + void slotHistoryShow(); + void slotShortcuts(); + void slotConfigure(); + void slotCloseAllWindows(); + void slotExtEdit(); + void slotCompleteSymbol(); + void slotShowWelcome(); + void slotGotoTag(); + void slotProjectMake(); + void slotProjectRemake(); + void slotShowBookmarks(); + + // Other slots + void slotProjectFilesChanged(); + void slotFilesAdded(const QStringList&); + void slotQuery(uint, bool); + void slotDeleteEditor(EditorPage*); + void slotChangeEditor(EditorPage*, EditorPage*); + void slotShowEditor(const QString&, uint); + void slotFileOpened(EditorPage*, const QString&); + void slotFileSaved(const QString&, bool); + void slotCscopeError(const QString&); + void slotBuildProgress(int, int); + void slotBuildInvIndex(); + void slotBuildFinished(uint); + void slotBuildAborted(); + void slotApplyPref(); + void slotShowCursorPos(uint, uint); + void slotQueryShowEditor(const QString&, uint); + void slotDropEvent(QDropEvent*); + void slotCscopeVerified(bool, uint); +}; + +#endif diff --git a/src/kscope.lsm b/src/kscope.lsm new file mode 100644 index 0000000..1062526 --- /dev/null +++ b/src/kscope.lsm @@ -0,0 +1,16 @@ +Begin4 +Title: KScope +Version: 1.4.0 +Entered-date: ? +Description: A source-editing environment for KDE bsaed on Cscope +Keywords: KDE Cscope Source Browser Editor IDE C +Author: elad_lahav@users.sourceforge.net (Elad Lahav) +Maintained-by: elad_lahav@users.sourceforge.net (Elad Lahav) +Home-page: http://kscope.sourceforge.net +Alternate-site: +Primary-site: http://download.sourceforge.net/kscope/ + ?M kscope-1.4.0.tar.gz + ? kscope-1.4.0.lsm +Platform: Linux/Unix. Requires KDE. +Copying-policy: BSD +End diff --git a/src/kscope_config b/src/kscope_config new file mode 100644 index 0000000..25fad0f --- /dev/null +++ b/src/kscope_config @@ -0,0 +1,165 @@ +# Configures KScope parameters + +# Checks that the given executable is indeed a Cscope-compatible application +# and determines which options it supports. +verifyCscope() +{ + CSCOPE_EXE=`basename $CSCOPE_PATH` + + if [ $DEBUG ] + then + echo -n Checking $CSCOPE_EXE version... + fi + + # Get the executable's version + CSCOPE_VER_MAJOR=`$CSCOPE_PATH -V 2>&1 | grep -i $CSCOPE_EXE | sed -e "s/.*version \([1-9][0-9]*\)\.\([0-9]\).*/\1/"` + CSCOPE_VER_MINOR=`$CSCOPE_PATH -V 2>&1 | grep -i $CSCOPE_EXE | sed -e "s/.*version \([1-9][0-9]*\)\.\([0-9]\).*/\2/"` + + if [ -n "$CSCOPE_VER_MAJOR" -a "$CSCOPE_VER_MINOR" ] + then + echo $CSCOPE_VER_MAJOR.$CSCOPE_VER_MINOR + + if [ $DEBUG ] + then + echo -n Cscope support for line mode verbose output... + fi + + # Check for verbose output + if [ "`$CSCOPE_PATH -h 2>&1 | grep "\-v"`" ] + then + CSCOPE_VERBOSE=Yes + else + CSCOPE_VERBOSE=No + fi + echo $CSCOPE_VERBOSE + + if [ $DEBUG ] + then + echo -n Cscope support slow path definitions... + fi + + # Check for slow-path definitions + if [ "`$CSCOPE_PATH -h 2>&1 | grep "\-D"`" ] + then + CSCOPE_SLOWPATH=Yes + else + CSCOPE_SLOWPATH=No + fi + echo $CSCOPE_SLOWPATH + else + echo ERROR + if [ $DEBUG ] + then + echo -e "\n *** ERROR *** The \"cscope\" executable does not appear to be a Cscope compatible programme" + fi + fi +} + +DEBUG=0 +CSCOPE_OPTIONS_ONLY= + +# Parse command-line parameters +# Supported options: +# -d: Debug mode +# -co: Check Cscope options only +for opt in $@ +do + case "$opt" in + "-d") DEBUG=1 + ;; + "-co") CSCOPE_OPTIONS_ONLY=1 + ;; + esac +done + +if [ $DEBUG ] +then + echo -n Looking for cscope... +fi + +if [ -z "$CSCOPE_PATH" ] +then + CSCOPE_PATH=`which cscope` +fi + +if [ -n "$CSCOPE_PATH" -a -x "$CSCOPE_PATH" ] +then + echo $CSCOPE_PATH + verifyCscope +else + echo ERROR + if [ $DEBUG ] + then + echo -e "\n *** ERROR *** No Cscope executable found" + fi +fi + +if [ -n "$CSCOPE_OPTIONS_ONLY" ] +then + exit +fi + +if [ $DEBUG ] +then + echo -n Looking for Ctags... +fi + +if [ -z "$CTAGS_PATH" ] +then + for CTAGS_NAME in exctags ctags-exuberant exuberant-ctags ctags + do + CTAGS_PATH=`which $CTAGS_NAME` + if [ -n "$CTAGS_PATH" -a -x "$CTAGS_PATH" ] + then + break + fi + done +fi + +if [ -n "$CTAGS_PATH" ] +then + echo $CTAGS_PATH + + # echo -n Checking for Exuberant-Ctags compatibility... + + CTAGS_EXUB=`$CTAGS_PATH --help | grep -c "\-\-excmd=number"` + if [ $CTAGS_EXUB -gt 0 ] + then + CTAGS_EXUB_PATH=$CTAGS_PATH + echo Yes + else + echo ERROR + # echo -e "\n *** ERROR *** The \"ctags\" executable does not appear to be compatible with Exuberant Ctags" + fi + +else + echo ERROR + # echo -e "\n *** ERROR *** No Ctags executable found" +fi + +# echo -n Looking for Dot... + +if [ -z "$DOT_PATH" ] +then + DOT_PATH=`which dot` +fi + +if [ -n "$DOT_PATH" -a -x "$DOT_PATH" ] +then + echo $DOT_PATH + + # echo -n Checking if dot handles the -Tplain option... + + echo "digraph G {Hello->World}" | $DOT_PATH -Tplain 2>&1 /dev/null + if [ $? -eq 0 ] + then + echo Yes + else + echo ERROR + # echo -e "\n *** ERROR *** The \"dot\" executable does not support -Tplain" + fi + +else + echo ERROR + # echo -e "\n *** ERROR *** No Dot executable found" +fi diff --git a/src/kscopeactions.cpp b/src/kscopeactions.cpp new file mode 100644 index 0000000..d5c64fc --- /dev/null +++ b/src/kscopeactions.cpp @@ -0,0 +1,533 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, m_pWindow list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, m_pWindow list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <klocale.h> +#include "kscope.h" +#include "kscopeactions.h" +#include "kscopeconfig.h" +#include "filelist.h" +#include "editortabs.h" +#include "querywidget.h" + +KScopeActions::KScopeActions(KScope* pWindow) : QObject(), + m_pWindow(pWindow), + m_pCollection(pWindow->actionCollection()) +{ +} + +KScopeActions::~KScopeActions() +{ +} + +/** + * Connects menu bar and toolbar commands with class members. These members + * handle the actions associated with each command. + */ +void KScopeActions::init() +{ + // File menu + KStdAction::openNew(m_pWindow, SLOT(slotNewFile()), m_pCollection); + KStdAction::open(m_pWindow, SLOT(slotOpenFile()), m_pCollection); + KStdAction::close(m_pWindow, SLOT(slotCloseEditor()), m_pCollection); + KStdAction::quit(m_pWindow, SLOT(slotClose()), m_pCollection); + + addAction(i18n("Go to File List"), + NULL, + "Ctrl+Shift+O", + m_pWindow->m_pFileList, + SLOT(slotSetFocus()), + "file_open_file_from_list", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Save Al&l"), + "save_all", + "Ctrl+L", + m_pWindow->m_pEditTabs, + SLOT(slotSaveAll()), + "file_save_all", + NULL); + + // Edit menu + m_pExtEditAction = addAction(i18n("Edit in E&xternal Editor"), + NULL, + "Ctrl+E", + m_pWindow, + SLOT(slotExtEdit()), + "edit_external_editor", + SIGNAL(toggleFile(bool))); + + addAction(i18n("Go To Tag"), + NULL, + "Ctrl+Shift+T", + m_pWindow, + SLOT(slotGotoTag()), + "edit_goto_tag", + SIGNAL(toggleFile(bool))); + + addAction(i18n("Complete Symbol"), + NULL, + "Ctrl+Space", + m_pWindow, + SLOT(slotCompleteSymbol()), + "edit_comp_symbol", + SIGNAL(toggleFile(bool))); + + // Project menu + addAction(i18n("&New Project..."), + NULL, + NULL, + m_pWindow, + SLOT(slotCreateProject()), + "project_new", + NULL); + + addAction(i18n("&Open Project..."), + "project_open", + NULL, + m_pWindow, + SLOT(slotOpenProject()), + "project_open", + NULL); + + addAction(i18n("Open &Cscope.out..."), + NULL, + NULL, + m_pWindow, + SLOT(slotProjectCscopeOut()), + "project_cscope_out", + NULL); + + addAction(i18n("Add/Remove &Files..."), + NULL, + NULL, + m_pWindow, + SLOT(slotProjectFiles()), + "project_add_rem_files", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Properties..."), + NULL, + NULL, + m_pWindow, + SLOT(slotProjectProps()), + "project_properties", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Make Project"), + "make_kdevelop", + "Ctrl+M", + m_pWindow, + SLOT(slotProjectMake()), + "project_make", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Remake Project"), + "rebuild", + "Ctrl+Shift+M", + m_pWindow, + SLOT(slotProjectRemake()), + "project_remake", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Close Project"), + "fileclose", + NULL, + m_pWindow, + SLOT(slotCloseProject()), + "project_close", + SIGNAL(toggleProject(bool))); + + // Cscope menu + addAction(i18n("&References..."), + NULL, + "Ctrl+0", + m_pWindow, + SLOT(slotQueryReference()), + "cscope_references", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Definition..."), + NULL, + "Ctrl+1", + m_pWindow, + SLOT(slotQueryDefinition()), + "cscope_definition", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Called Functions..."), + NULL, + "Ctrl+2", + m_pWindow, + SLOT(slotQueryCalled()), + "cscope_called", + SIGNAL(toggleProject(bool))); + + addAction(i18n("C&alling Functions..."), + NULL, + "Ctrl+3", + m_pWindow, + SLOT(slotQueryCalling()), + "cscope_calling", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Find &Text..."), + NULL, + "Ctrl+4", + m_pWindow, + SLOT(slotQueryText()), + "cscope_text", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Find &EGrep Pattern..."), + NULL, + "Ctrl+5", + m_pWindow, + SLOT(slotQueryPattern()), + "cscope_pattern", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Find &File..."), + NULL, + "Ctrl+7", + m_pWindow, + SLOT(slotQueryFile()), + "cscope_file", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Including Files..."), + NULL, + "Ctrl+8", + m_pWindow, + SLOT(slotQueryIncluding()), + "cscope_including", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Quick Definition"), + NULL, + "Ctrl+]", + m_pWindow, + SLOT(slotQueryQuickDef()), + "cscope_quick_def", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Call &Graph..."), + NULL, + "Ctrl+\\", + m_pWindow, + SLOT(slotCallTree()), + "cscope_call_tree", + SIGNAL(toggleProject(bool))); + + addAction(i18n("Re&build database"), + "vcs_update", + NULL, + m_pWindow, + SLOT(slotRebuildDB()), + "cscope_rebuild", + SIGNAL(toggleProject(bool))); + + // Go menu + addAction(i18n("P&revious Result"), + "up", + "Alt+Up", + m_pWindow->m_pQueryWidget, + SLOT(slotPrevResult()), + "go_prev_result", + SIGNAL(toggleProject(bool))); + + addAction(i18n("N&ext Result"), + "down", + "Alt+Down", + m_pWindow->m_pQueryWidget, + SLOT(slotNextResult()), + "go_next_result", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Previous Position"), + "back", + "Alt+Left", + m_pWindow->m_pQueryWidget, + SLOT(slotHistoryPrev()), + "go_prev_pos", + NULL); + + addAction(i18n("&Next Position"), + "forward", + "Alt+Right", + m_pWindow->m_pQueryWidget, + SLOT(slotHistoryNext()), + "go_next_pos", + NULL); + + addAction(i18n("Position &History"), + "history", + "Ctrl+h", + m_pWindow, + SLOT(slotHistoryShow()), + "go_history", + NULL); + + addAction(i18n("Global &Bookmarks"), + "bookmark", + "Ctrl+Shift+G", + m_pWindow, + SLOT(slotShowBookmarks()), + "go_bookmarks", + NULL); + + // View menu + m_pToggleFileViewAction = addToggle(i18n("Toggle File List"), + "view_sidetree", + "Ctrl+/", + m_pWindow->m_pFileViewDock, + SLOT(changeHideShowState()), + "view_toggle_filelist_dock", + NULL); + + m_pToggleQueryWindowAction = addToggle(i18n("Toggle Query Window"), + "view_top_bottom", + "Ctrl+.", + m_pWindow->m_pQueryDock, + SLOT(changeHideShowState()), + "view_toggle_query_dock", + NULL); + + m_pToggleTagListAction = addToggle(i18n("Toggle Tag List"), + "view_detailed", + "Ctrl+'", + m_pWindow->m_pEditTabs, + SLOT(slotToggleTagList()), + "view_toggle_tag_list", + NULL); + + // Window menu + addAction(i18n("Close &All"), + "fileclose", + NULL, + m_pWindow, + SLOT(slotCloseAllWindows()), + "window_close_all", + NULL); + + addAction(i18n("Go &Left"), + "back", + "Alt+Shift+Left", + m_pWindow->m_pEditTabs, + SLOT(slotGoLeft()), + "window_go_left", + NULL); + + addAction(i18n("Go &Right"), + "forward", + "Alt+Shift+Right", + m_pWindow->m_pEditTabs, + SLOT(slotGoRight()), + "window_go_right", + NULL); + + // Settings menu + KStdAction::preferences(m_pWindow, SLOT(slotConfigure()), m_pCollection); + KStdAction::keyBindings(m_pWindow, SLOT(slotShortcuts()), m_pCollection); + + // Help menu + addAction(i18n("Show &Welcome Message..."), + NULL, + NULL, + m_pWindow, + SLOT(slotShowWelcome()), + "help_welcome", + NULL); + + // Query widget popup menu + addAction(i18n("&New"), + "filenew", + NULL, + m_pWindow->m_pQueryWidget, + SLOT(slotNewQueryPage()), + "query_new", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Refresh"), + "reload", + NULL, + m_pWindow->m_pQueryWidget, + SLOT(slotRefreshCurrent()), + "query_refresh", + SIGNAL(toggleProject(bool))); + + m_pLockAction = addToggle(i18n("&Lock/Unlock"), + "encrypted", + NULL, + m_pWindow->m_pQueryWidget, + SLOT(slotLockCurrent()), + "query_toggle_locked", + SIGNAL(toggleProject(bool))); + + addAction(i18n("&Close"), + "fileclose", + NULL, + m_pWindow->m_pQueryWidget, + SLOT(slotCloseCurrent()), + "query_close", + SIGNAL(toggleProject(bool))); + + m_pExtEditAction->setEnabled(Config().useExtEditor()); +} + +void KScopeActions::initLayoutActions() +{ + m_pToggleFileViewAction->setChecked(m_pWindow->m_pFileViewDock->isShown()); + m_pToggleQueryWindowAction->setChecked(m_pWindow->m_pQueryDock->isShown()); + m_pToggleTagListAction->setChecked(Config().getShowTagList()); +} + +/** + * Enables/disables the "Edit in External Editor" command. + * @param bEnable true to enable the command, false to disable it + */ +void KScopeActions::enableExtEditor(bool bEnable) +{ + m_pExtEditAction->setEnabled(bEnable); +} + +void KScopeActions::slotQueryDockToggled(bool bVisible) +{ + m_pToggleQueryWindowAction->setChecked(bVisible); +} + +/** + * Ensures the "Show/Hide Query Window" action is unchecked when the dock + * is closed through its close button. + * This slot is conncted to the headerCloseButtonClicked() signal of the + * query window dock widget. + */ +void KScopeActions::slotQueryDockClosed() +{ + m_pToggleQueryWindowAction->setChecked(false); +} + +/** + * Ensures the "Show/Hide File View" action is unchecked when the dock + * is closed through its close button. + * This slot is conncted to the headerCloseButtonClicked() signal of the + * file view dock widget. + */ +void KScopeActions::slotFileViewDockClosed() +{ + m_pToggleFileViewAction->setChecked(false); +} + +/** + * Enables/disables all actions related to open projects. + * This slot should be called whenever a project is opened or closed. + * @param bEnable true to enable actions, false to disable + */ +void KScopeActions::slotEnableProjectActions(bool bEnable) +{ + emit toggleProject(bEnable); +} + +/** + * Enables/disables all actions related to open files. + * This slot should be called the first file is opened, or when the last one + * is closed. + * @param bEnable true to enable actions, false to disable + */ +void KScopeActions::slotEnableFileActions(bool bEnable) +{ + emit toggleFile(bEnable); +} + +/** + * Creates a new action. + * @param sCaption The text to display in the menu item + * @param szIcon Optional icon associated with the action + * @param szShortcut Optional key-combination string + * @param pReceiver The widget to receive the action's signal + * @param szSlot The widget's slot that connect to the signal + * @param szName The XML entry corresponding to the action + * @param szSignal Optional signal to connect to the setEnabled() slot of + * the action + * @return The newly created action object + */ +KAction* KScopeActions::addAction(const QString& sCaption, const char* szIcon, + const char* szShortcut, QWidget* pReceiver, const char* szSlot, + const char* szName, const char* szSignal) +{ + KAction* pAction; + + // Create the action + pAction = new KAction(sCaption, + szIcon, + szShortcut == NULL ? KShortcut() : KShortcut(szShortcut), + pReceiver, + szSlot, + m_pCollection, + szName); + + // Add to the given action list, if any + if (szSignal) + connect(this, szSignal, pAction, SLOT(setEnabled(bool))); + + return pAction; +} + +/** + * Creates a new toggle action. + * @param sCaption The text to display in the menu item + * @param szIcon Optional icon associated with the action + * @param szShortcut Optional key-combination string + * @param pReceiver The widget to receive the action's signal + * @param szSlot The widget's slot that connect to the signal + * @param szName The XML entry corresponding to the action + * @param szSignal Optional signal to connect to the setEnabled() slot of + * the action + * @return The newly created action object + */ +KToggleAction* KScopeActions::addToggle(const QString& sCaption, + const char* szIcon, const char* szShortcut, QWidget* pReceiver, + const char* szSlot, const char* szName, const char* szSignal) +{ + KToggleAction* pAction; + + // Create the action + pAction = new KToggleAction(sCaption, + szIcon, + szShortcut == NULL ? KShortcut() : KShortcut(szShortcut), + pReceiver, + szSlot, + m_pCollection, + szName); + + // Add to the given action list, if any + if (szSignal) + connect(this, szSignal, pAction, SLOT(setEnabled(bool))); + + return pAction; +} + +#include "kscopeactions.moc" diff --git a/src/kscopeactions.h b/src/kscopeactions.h new file mode 100644 index 0000000..4836310 --- /dev/null +++ b/src/kscopeactions.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef KSCOPEACTIONS_H +#define KSCOPEACTIONS_H + +#include <kaction.h> + +class KScope; + +typedef QPtrList<KAction> ActionList; + +/** + * A helper class for managing KScope's menu commands. + * @author Elad Lahav + */ +class KScopeActions : public QObject +{ + Q_OBJECT + +public: + KScopeActions(KScope*); + ~KScopeActions(); + + void init(); + void initPopups(); + void initLayoutActions(); + void enableExtEditor(bool); + + KToggleAction* getLockAction() { return m_pLockAction; } + +public slots: + void slotQueryDockToggled(bool); + void slotQueryDockClosed(); + void slotFileViewDockClosed(); + void slotEnableProjectActions(bool); + void slotEnableFileActions(bool); + +signals: + void toggleProject(bool bEnable); + void toggleFile(bool bEnable); + +private: + KScope* m_pWindow; + KActionCollection* m_pCollection; + + /** A list of actions that require an active project. */ + ActionList m_lstProjActions; + + /** A list of actions that require an active file. */ + ActionList m_lstFileActions; + + /** A toggle menu item for locking/unlocking query pages. */ + KToggleAction* m_pLockAction; + + /** The "Edit in External Editor" menu command. */ + KAction* m_pExtEditAction; + + /** The "Show/Hide File View" menu command. */ + KToggleAction* m_pToggleFileViewAction; + + /** The "Show/Hide Query Window" menu command. */ + KToggleAction* m_pToggleQueryWindowAction; + + /** The "Show/Hide Tag List" menu command. */ + KToggleAction* m_pToggleTagListAction; + + KAction* addAction(const QString&, const char*, const char*, QWidget*, + const char*, const char*, const char*); + KToggleAction* addToggle(const QString&, const char*, const char*, + QWidget*, const char*, const char*, const char*); +}; + +#endif diff --git a/src/kscopeconfig.cpp b/src/kscopeconfig.cpp new file mode 100644 index 0000000..3cc5094 --- /dev/null +++ b/src/kscopeconfig.cpp @@ -0,0 +1,768 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <kconfig.h> +#include <kapplication.h> +#include <kglobalsettings.h> +#include "kscopeconfig.h" + +// NOTE: +// This configuration file entry controls whether the welcome dialogue is +// displayed. Normally it only needs to be shown once, but the entry's name +// can be changed across versions to force the display of new information. +#define SHOW_WELCOME_ENTRY "ShowWelcomeDlg" + +/** + * Stores the display name and the configuration file entry for a configurable + * GUI element. + * @author Elad Lahav + */ +struct ElementInfo +{ + /** The display name of the element. */ + const char* szName; + + /** The configuration file entry. */ + const char* szEntry; +}; + +/** + * A list of GUI elements for which the colour can be configured. + */ +const ElementInfo eiColors[] = { + { "File List (Foreground)", "FileListFore" }, + { "File List (Background)", "FileListBack" }, + { "Tag List (Foreground)", "TagListFore" }, + { "Tag List (Background)", "TagListBack" }, + { "Query Window (Foreground)", "QueryListFore" }, + { "Query Window (Background)", "QueryListBack" }, + { "Call Graph (Background)", "GraphBack" }, + { "Call Graph (Nodes)", "GraphNode" }, + { "Call Graph (Text)", "GraphText" }, + { "Call Graph (Multi-Call Nodes)", "GraphMultiCall" } +}; + +/** + * A list of GUI elements for which the font can be configured. + */ +const ElementInfo eiFonts[] = { + { "File List", "FileList" }, + { "Tag List", "TagList" }, + { "Query Page", "QueryList" }, + { "Call Graph", "Graph" } +}; + +#define COLOR_NAME(_i) eiColors[_i].szName +#define COLOR_ENTRY(_i) eiColors[_i].szEntry +#define FONT_NAME(_i) eiFonts[_i].szName +#define FONT_ENTRY(_i) eiFonts[_i].szEntry + +KScopeConfig::ConfParams KScopeConfig::s_cpDef = { + "/usr/bin/cscope", // Cscope path + "/usr/bin/ctags", // Ctags path + "/usr/bin/dot", // Dot path + true, // Show the tag list + SPLIT_SIZES(), // Tag list width + { + QColor(black), // File list foreground + QColor(white), // File list background + QColor(black), // Tag list foreground + QColor(white), // Tag list background + QColor(black), // Query page foreground + QColor(white), // Query page background + QColor("#c0c0c0"), // Call graph background + QColor("#c0ff80"), // Call graph nodes + QColor(black), // Call graph text + QColor("#ff8000") + }, + { + QFont(), // Font definitions are overriden in load() + QFont(), + QFont(), + QFont() + }, + NameAsc, // Ctags sort order + false, // Read-only mode + true, // Load last project + true, // Automatic tag highlighting + false, // Brief query captions + true, // Warn when file is modified on the disk + true, // Sort files when a project is loaded + "kate --line %L %F", // External editor example + Fast, // System profile + Embedded, // Editor context menu + "TB", // Call graph orientation + 10, // Maximum calls per graph node + 0 // Default graph view +}; + +/** + * Class constructor. + */ +KScopeConfig::KScopeConfig() : m_bFontsChanged(false) +{ +} + +/** + * Class destructor. + */ +KScopeConfig::~KScopeConfig() +{ +} + +/** + * Reads KScope's parameters from the standard configuration file. + */ +void KScopeConfig::load() +{ + uint i; + + KConfig* pConf = kapp->config(); + + // Need a working instance to get the system's default font (cannot be + // initialised statically) + s_cpDef.fonts[FileList] = KGlobalSettings::generalFont(); + s_cpDef.fonts[TagList] = KGlobalSettings::generalFont(); + s_cpDef.fonts[QueryWindow] = KGlobalSettings::generalFont(); + s_cpDef.fonts[Graph] = KGlobalSettings::generalFont(); + + // Read the paths to required executables + pConf->setGroup("Programs"); + m_cp.sCscopePath = pConf->readEntry("CScope"); + m_cp.sCtagsPath = pConf->readEntry("CTags"); + m_cp.sDotPath = pConf->readEntry("Dot"); + + // Read size and position parameters + pConf->setGroup("Geometry"); + m_cp.bShowTagList = pConf->readBoolEntry("ShowTagList", + s_cpDef.bShowTagList); + m_cp.siEditor = pConf->readIntListEntry("Editor"); + if (m_cp.siEditor.empty()) + m_cp.siEditor << 200 << 800; + + // Read the recent projects list + pConf->setGroup("Projects"); + m_slProjects = pConf->readListEntry("Recent"); + + // Read colour settings + pConf->setGroup("Colors"); + for (i = 0; i <= LAST_COLOR; i++) { + m_cp.clrs[i] = pConf->readColorEntry(COLOR_ENTRY(i), + &s_cpDef.clrs[i]); + } + + // Read font settings + pConf->setGroup("Fonts"); + for (i = 0; i <= LAST_FONT; i++) { + m_cp.fonts[i] = pConf->readFontEntry(FONT_ENTRY(i), + &s_cpDef.fonts[i]); + } + + // Other options + pConf->setGroup("Options"); + m_cp.ctagSortOrder = + (CtagSort)pConf->readUnsignedNumEntry("CtagSortOrder", + s_cpDef.ctagSortOrder); + m_cp.bReadOnlyMode = pConf->readBoolEntry("ReadOnlyMode", + s_cpDef.bReadOnlyMode); + m_cp.bLoadLastProj = pConf->readBoolEntry("LoadLastProj", + s_cpDef.bLoadLastProj); + m_cp.bAutoTagHl = pConf->readBoolEntry("AutoTagHl", + s_cpDef.bAutoTagHl); + m_cp.bBriefQueryCaptions = pConf->readBoolEntry("BriefQueryCaptions", + s_cpDef.bBriefQueryCaptions); + m_cp.bWarnModifiedOnDisk = pConf->readBoolEntry("WarnModifiedOnDisk", + s_cpDef.bWarnModifiedOnDisk); + m_cp.bAutoSortFiles = pConf->readBoolEntry("AutoSortFiles", + s_cpDef.bAutoSortFiles); + m_cp.sExtEditor = pConf->readEntry("ExternalEditor", s_cpDef.sExtEditor); + m_cp.profile = (SysProfile)pConf->readUnsignedNumEntry("SystemProfile", + s_cpDef.profile); + m_cp.popup = (EditorPopup)pConf->readUnsignedNumEntry("EditorPopup", + s_cpDef.popup); + m_cp.sGraphOrient = pConf->readEntry("GraphOrientation", + s_cpDef.sGraphOrient); + m_cp.nGraphMaxNodeDegree = pConf->readNumEntry("GraphMaxNodeDegree", + s_cpDef.nGraphMaxNodeDegree); + m_cp.nDefGraphView = pConf->readNumEntry("DefGraphView", + s_cpDef.nDefGraphView); +} + +/** + * Sets default values to he configuration parameters (except for those where + * a default value has no meaning, such as the recent projects list). + */ +void KScopeConfig::loadDefault() +{ + m_cp = s_cpDef; +} + +/** + * Loads the layout of the main window. + * @param pMainWindow Pointer to the main docking window + */ +void KScopeConfig::loadWorkspace(KDockMainWindow* pMainWindow) +{ + pMainWindow->readDockConfig(kapp->config(), "Workspace"); +} + +/** + * Writes KScope's parameters from the standard configuration file. + */ +void KScopeConfig::store() +{ + uint i; + + KConfig* pConf = kapp->config(); + + // Write the paths to required executables + pConf->setGroup("Programs"); + pConf->writeEntry("CScope", m_cp.sCscopePath); + pConf->writeEntry("CTags", m_cp.sCtagsPath); + pConf->writeEntry("Dot", m_cp.sDotPath); + + // Write size and position parameters + pConf->setGroup("Geometry"); + pConf->writeEntry("ShowTagList", m_cp.bShowTagList); + pConf->writeEntry("Editor", m_cp.siEditor); + + // Write the recent projects list + pConf->setGroup("Projects"); + pConf->writeEntry("Recent", m_slProjects); + + // Write colour settings + pConf->setGroup("Colors"); + for (i = 0; i <= LAST_COLOR; i++) + pConf->writeEntry(COLOR_ENTRY(i), m_cp.clrs[i]); + + // Write font settings + if (m_bFontsChanged) { + pConf->setGroup("Fonts"); + for (i = 0; i <= LAST_FONT; i++) + pConf->writeEntry(FONT_ENTRY(i), m_cp.fonts[i]); + + m_bFontsChanged = false; + } + + // Other options + pConf->setGroup("Options"); + pConf->writeEntry("CtagSortOrder", (uint)m_cp.ctagSortOrder); + pConf->writeEntry("ReadOnlyMode", m_cp.bReadOnlyMode); + pConf->writeEntry("LoadLastProj", m_cp.bLoadLastProj); + pConf->writeEntry("AutoTagHl", m_cp.bAutoTagHl); + pConf->writeEntry("BriefQueryCaptions", m_cp.bBriefQueryCaptions); + pConf->writeEntry("WarnModifiedOnDisk", m_cp.bWarnModifiedOnDisk); + pConf->writeEntry("AutoSortFiles", m_cp.bAutoSortFiles); + pConf->writeEntry("ExternalEditor", m_cp.sExtEditor); + pConf->writeEntry("SystemProfile", (uint)m_cp.profile); + pConf->writeEntry("EditorPopup", (uint)m_cp.popup); + pConf->writeEntry("GraphOrientation", m_cp.sGraphOrient); + pConf->writeEntry("GraphMaxNodeDegree", m_cp.nGraphMaxNodeDegree); + pConf->writeEntry("DefGraphView", m_cp.nDefGraphView); + + // Do not report it's the first time on the next run + pConf->setGroup("General"); + pConf->writeEntry("FirstTime", false); + pConf->writeEntry(SHOW_WELCOME_ENTRY, false); +} + +/** + * Stores the layout of the main window. + * @param pMainWindow Pointer to the main docking window + */ +void KScopeConfig::storeWorkspace(KDockMainWindow* pMainWindow) +{ + pMainWindow->writeDockConfig(kapp->config(), "Workspace"); +} + +/** + * Determines if this is the first time KScope was launched by the current + * user. + * @return true if this is the first time, false otherwise + */ +bool KScopeConfig::isFirstTime() +{ + KConfig* pConf = kapp->config(); + + pConf->setGroup("General"); + return pConf->readBoolEntry("FirstTime", true); +} + +/** + * Determines if the welcome dialogue should be displayed. + * Note that while the dialogue is displayed on the first invocation of KScope, + * it may be required on other occasions (e.g., to display important information + * on a per-version basis) and thus it is separated from isFirstTime(). + * @return true if the dialogue should be shown, false otherwise + */ +bool KScopeConfig::showWelcomeDlg() +{ + KConfig* pConf = kapp->config(); + + pConf->setGroup("General"); + return pConf->readBoolEntry(SHOW_WELCOME_ENTRY, true); +} + +/** + * @return The full path of the Cscope executable + */ +const QString& KScopeConfig::getCscopePath() const +{ + return m_cp.sCscopePath; +} + +/** + * @param sPath The full path of the Cscope executable + */ +void KScopeConfig::setCscopePath(const QString& sPath) +{ + m_cp.sCscopePath = sPath; +} + +/** + * @return The full path of the Ctags executable + */ +const QString& KScopeConfig::getCtagsPath() const +{ + return m_cp.sCtagsPath; +} + +/** + * @param sPath The full path of the Ctags executable + */ +void KScopeConfig::setCtagsPath(const QString& sPath) +{ + m_cp.sCtagsPath = sPath; +} + +/** + * @return The full path of the Dot executable + */ +const QString& KScopeConfig::getDotPath() const +{ + return m_cp.sDotPath; +} + +/** + * @param sPath The full path of the Dot executable + */ +void KScopeConfig::setDotPath(const QString& sPath) +{ + m_cp.sDotPath = sPath; +} + +/** + * @return A sorted list of recently used project paths. + */ +const QStringList& KScopeConfig::getRecentProjects() const +{ + return m_slProjects; +} + +/** + * Adds the given project path to the beginning of the recently used projects + * list. + * @param sProjPath The path of the project to add + */ +void KScopeConfig::addRecentProject(const QString& sProjPath) +{ + QStringList::Iterator itr; + + itr = m_slProjects.find(sProjPath); + if (itr != m_slProjects.end()) + m_slProjects.remove(itr); + + m_slProjects.prepend(sProjPath); +} + +/** + * Removes the given project path from recently used projects list. + * @param sProjPath The path of the project to remove + */ +void KScopeConfig::removeRecentProject(const QString& sProjPath) +{ + m_slProjects.remove(sProjPath); +} + +/** + * @return true if the tag list should be visible, false otherwise + */ +bool KScopeConfig::getShowTagList() const +{ + return m_cp.bShowTagList; +} + +/** + * @param bShowTagList true to make the tag list visible, false otherwise + */ +void KScopeConfig::setShowTagList(bool bShowTagList) +{ + m_cp.bShowTagList = bShowTagList; +} + +/** + * @return A list containing the widths of the Ctags list part and the + * editor part in an editor page. + */ +const SPLIT_SIZES& KScopeConfig::getEditorSizes() const +{ + return m_cp.siEditor; +} + +/** + * @param siEditor A list containing the widths of the Ctags list part + * and the editor part in an editor page. + */ +void KScopeConfig::setEditorSizes(const SPLIT_SIZES& siEditor) +{ + m_cp.siEditor = siEditor; +} + +/** + * Finds a colour to use for a GUI element. + * @param ce Identifies the GUI element + * @return A reference to the colour object to use + */ +const QColor& KScopeConfig::getColor(ColorElement ce) const +{ + return m_cp.clrs[ce]; +} + +/** + * Returns the display name of a GUI element whose colour can be configured. + * @param ce The GUI element + * @return A name used in the colour configuration page + */ +QString KScopeConfig::getColorName(ColorElement ce) const +{ + return COLOR_NAME(ce); +} + +/** + * Sets a new colour to a GUI element. + * @param ce Identifies the GUI element + * @param clr The colour to use + */ +void KScopeConfig::setColor(ColorElement ce, const QColor& clr) +{ + m_cp.clrs[ce] = clr; +} + +/** + * Finds a font to use for a GUI element. + * @param fe Identifies the GUI element + * @return A reference to the font object to use + */ +const QFont& KScopeConfig::getFont(FontElement fe) const +{ + return m_cp.fonts[fe]; +} + +/** + * Returns the display name of a GUI element whose font can be configured. + * @param ce The GUI element + * @return A name used in the font configuration page + */ +QString KScopeConfig::getFontName(FontElement ce) const +{ + return FONT_NAME(ce); +} + +/** + * Sets a new font to a GUI element. + * @param fe Identifies the GUI element + * @param font The font to use + */ +void KScopeConfig::setFont(FontElement fe, const QFont& font) +{ + m_bFontsChanged = true; + m_cp.fonts[fe] = font; +} + +/** + * @return The column and direction by which the tags should be sorted + */ +KScopeConfig::CtagSort KScopeConfig::getCtagSortOrder() +{ + return m_cp.ctagSortOrder; +} + +/** + * @param ctagSortOrder The column and direction by which the tags should + * be sorted + */ +void KScopeConfig::setCtagSortOrder(CtagSort ctagSortOrder) +{ + m_cp.ctagSortOrder = ctagSortOrder; +} + +/** + * @return true to work in Read-Only mode, false otherwise + */ +bool KScopeConfig::getReadOnlyMode() +{ + return m_cp.bReadOnlyMode; +} + +/** + * @param bReadOnlyMode true to work in Read-Only mode, false otherwise + */ +void KScopeConfig::setReadOnlyMode(bool bReadOnlyMode) +{ + m_cp.bReadOnlyMode = bReadOnlyMode; +} + +/** + * @return true to load the last project on start-up, false otherwise + */ +bool KScopeConfig::getLoadLastProj() +{ + return m_cp.bLoadLastProj; +} + +/** + * @param bLoadLastProj true to load the last project on start-up, false + * otherwise + */ +void KScopeConfig::setLoadLastProj(bool bLoadLastProj) +{ + m_cp.bLoadLastProj = bLoadLastProj; +} + +/** + * @return true to enable tag highlighting based on cursor position, false + * to disable this feature + */ +bool KScopeConfig::getAutoTagHl() +{ + return m_cp.bAutoTagHl; +} + +/** + * @param bAutoTagHl true to enable tag highlighting based on cursor + * position, false to disable this feature + */ +void KScopeConfig::setAutoTagHl(bool bAutoTagHl) +{ + m_cp.bAutoTagHl = bAutoTagHl; +} + +/** + * @return true to use the short version of the query captions, false to use + * the long version + */ +bool KScopeConfig::getUseBriefQueryCaptions() +{ + return m_cp.bBriefQueryCaptions; +} + +/** + * @param bBrief true to use the short version of the query captions, false + * to use the long version + */ +void KScopeConfig::setUseBriefQueryCaptions(bool bBrief) +{ + m_cp.bBriefQueryCaptions = bBrief; +} + +/** + * @return true to warn user when file is modified on disk, false + * otherwise + */ +bool KScopeConfig::getWarnModifiedOnDisk() +{ + return m_cp.bWarnModifiedOnDisk; +} + +/** + * @param bWarn true to warn user when file is modified on disk, + * false otherwise + */ +void KScopeConfig::setWarnModifiedOnDisk(bool bWarn) +{ + m_cp.bWarnModifiedOnDisk = bWarn; +} + +/** + * @return true to sort files when a project is loaded, false otherwise + */ +bool KScopeConfig::getAutoSortFiles() +{ + return m_cp.bAutoSortFiles; +} + +/** + * @param bSort true to sort files when a project is loaded, false + * otherwise + */ +void KScopeConfig::setAutoSortFiles(bool bSort) +{ + m_cp.bAutoSortFiles = bSort; +} + +/** + * @return A command line for launching an external editor + */ +const QString& KScopeConfig::getExtEditor() +{ + return m_cp.sExtEditor; +} + +/** + * @param sExtEditor A command line for launching an external editor + */ +void KScopeConfig::setExtEditor(const QString& sExtEditor) +{ + m_cp.sExtEditor = sExtEditor; +} + +/** + * Determines if an external editor should be used. + * An external editor is used if KScope is in Read-Only mode, and a command- + * line for the editor was specified. + * @return true to use an external editor, false otherwise + */ +bool KScopeConfig::useExtEditor() +{ + return !m_cp.sExtEditor.isEmpty(); +} + +/** + * @return The chosen profile for this system (@see SysProfile) + */ +KScopeConfig::SysProfile KScopeConfig::getSysProfile() const +{ + return m_cp.profile; +} + +/** + * @param profile The system profile to use (@see SysProfile) + */ +void KScopeConfig::setSysProfile(KScopeConfig::SysProfile profile) +{ + m_cp.profile = profile; +} + +/** + * @return The chosen popup menu type for the embedded editor (@see + * EditorPopup) + */ +KScopeConfig::EditorPopup KScopeConfig::getEditorPopup() const +{ + return m_cp.popup; +} + +/** + * @return The name of the popup menu to use in the embedded editor + */ +QString KScopeConfig::getEditorPopupName() const +{ + switch (m_cp.popup) { + case Embedded: + return "ktexteditor_popup"; + + case KScopeOnly: + return "kscope_popup"; + } + + // Will not happen, but the compiler complains if no return statement is + // given here + return ""; +} + +/** + * @param popup The popup menu to use for the embedded editor (@see + * EditorPopup) + */ +void KScopeConfig::setEditorPopup(KScopeConfig::EditorPopup popup) +{ + m_cp.popup = popup; +} + +/** + * @return The default orientation for call graphs + */ +QString KScopeConfig::getGraphOrientation() const +{ + return m_cp.sGraphOrient; +} + +/** + * @param sOrient The default orientation for call graphs + */ +void KScopeConfig::setGraphOrientation(const QString& sOrient) +{ + m_cp.sGraphOrient = sOrient; +} + +/** + * @return The maximal number of calls per graph node + */ +int KScopeConfig::getGraphMaxNodeDegree() const +{ + return m_cp.nGraphMaxNodeDegree; +} + +/** + * @param nMaxNodeDegree The maximal number of calls per graph node + */ +void KScopeConfig::setGraphMaxNodeDegree(int nMaxNodeDegree) +{ + m_cp.nGraphMaxNodeDegree = nMaxNodeDegree; +} + +/** + * @return The default view in the call graph dialogue + */ +int KScopeConfig::getDefGraphView() const +{ + return m_cp.nDefGraphView; +} + +/** + * @param nDefGraphView The default view in the call graph dialogue + */ +void KScopeConfig::setDefGraphView(int nDefGraphView) +{ + m_cp.nDefGraphView = nDefGraphView; +} + +/** + * Returns a reference to a global configuration object. + * The static object defined is this function should be the only KSCopeConfig + * object in this programme. Any code that wishes to get or set global + * configuration parameters, should call Config(), instead of defining its + * own object. + * @return Reference to a statically allocated configuration object + */ +KScopeConfig& Config() +{ + static KScopeConfig conf; + return conf; +} + +#include "kscopeconfig.moc" diff --git a/src/kscopeconfig.h b/src/kscopeconfig.h new file mode 100644 index 0000000..8a047cf --- /dev/null +++ b/src/kscopeconfig.h @@ -0,0 +1,218 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef KSCOPECONFIG_H +#define KSCOPECONFIG_H + +#include <qobject.h> +#include <qstringlist.h> +#include <qcolor.h> +#include <kdockwidget.h> + +typedef QValueList<int> SPLIT_SIZES; + +/** + * Loads and stores global configuration parameters. + * @author Elad Lahav + */ + +class KScopeConfig : public QObject +{ + Q_OBJECT + +public: + KScopeConfig(); + ~KScopeConfig(); + + /** GUI elements whose colours can be set. */ + enum ColorElement { FileListFore = 0, FileListBack, TagListFore, + TagListBack, QueryWindowFore, QueryWindowBack, GraphBack, + GraphNode, GraphText, GraphMultiCall, LAST_COLOR = GraphMultiCall }; + + /** GUI elements whose fonts can be set. */ + enum FontElement { FileList = 0, TagList, QueryWindow, Graph, + LAST_FONT = Graph }; + + /** Sort order values for the tags list. */ + enum CtagSort { NameAsc = 0, NameDes, LineAsc, LineDes, TypeAsc, + TypeDes }; + + /** Types of systems that determine certain aspects in KScope's + behaviour. + For fast systems, certain time-consuming operations, such as + rebuilding the database, may be performed automatically. Such + behaviour, however, is not desired on slow systems, in which the user + should handle such operations manually. */ + enum SysProfile { Fast, Slow }; + + /** The different options for a popup menu to be installed in the editor + parts. */ + enum EditorPopup { Embedded, KScopeOnly }; + + void load(); + void loadDefault(); + void loadWorkspace(KDockMainWindow*); + void store(); + void storeWorkspace(KDockMainWindow*); + bool isFirstTime(); + bool showWelcomeDlg(); + + const QString& getCscopePath() const; + void setCscopePath(const QString&); + const QString& getCtagsPath() const; + void setCtagsPath(const QString&); + const QString& getDotPath() const; + void setDotPath(const QString&); + const QStringList& getRecentProjects() const; + void addRecentProject(const QString&); + void removeRecentProject(const QString&); + bool getShowTagList() const; + void setShowTagList(bool); + const SPLIT_SIZES& getEditorSizes() const; + void setEditorSizes(const SPLIT_SIZES&); + const QColor& getColor(ColorElement) const; + QString getColorName(ColorElement) const; + void setColor(ColorElement, const QColor&); + const QFont& getFont(FontElement) const; + QString getFontName(FontElement) const; + void setFont(FontElement, const QFont&); + CtagSort getCtagSortOrder(); + void setCtagSortOrder(CtagSort); + bool getReadOnlyMode(); + void setReadOnlyMode(bool); + bool getLoadLastProj(); + void setLoadLastProj(bool); + bool getAutoTagHl(); + void setAutoTagHl(bool); + bool getUseBriefQueryCaptions(); + void setUseBriefQueryCaptions(bool); + bool getWarnModifiedOnDisk(); + void setWarnModifiedOnDisk(bool); + bool getAutoSortFiles(); + void setAutoSortFiles(bool); + const QString& getExtEditor(); + void setExtEditor(const QString&); + bool useExtEditor(); + SysProfile getSysProfile() const; + void setSysProfile(SysProfile); + EditorPopup getEditorPopup() const; + QString getEditorPopupName() const; + void setEditorPopup(EditorPopup); + QString getGraphOrientation() const; + void setGraphOrientation(const QString&); + int getGraphMaxNodeDegree() const; + void setGraphMaxNodeDegree(int); + int getDefGraphView() const; + void setDefGraphView(int); + +private: + /** A list of previously loaded projects. */ + QStringList m_slProjects; + + /** Defines the list of all configurable parameters in KScope. + The use of a structure helps define default values (@see s_cpDef) */ + struct ConfParams { + /** The full path of the Cscope executable. */ + QString sCscopePath; + + /** The full path of the Ctags executable. */ + QString sCtagsPath; + + /** The full path of the Dot executable. */ + QString sDotPath; + + /** Whether the tag list should be visible. */ + bool bShowTagList; + + /** The widths of the tag list and editor panes inside an editor + page. */ + SPLIT_SIZES siEditor; + + /** Colours for GUI elements. */ + QColor clrs[LAST_COLOR + 1]; + + /** Fonts for GUI elements. */ + QFont fonts[LAST_FONT + 1]; + + /** Sort order of the tag lists. */ + CtagSort ctagSortOrder; + + /** Whether KScope should operate in code read-only mode. */ + bool bReadOnlyMode; + + /** Whether the last open project should be reloaded on start-up. */ + bool bLoadLastProj; + + /** Whether tags should be highlighted based on the current cursor + position. */ + bool bAutoTagHl; + + /** Whether query page captions should use mnemonics for query types, + instead of the full description. */ + bool bBriefQueryCaptions; + + /** Whether the warning should be displayed when file is modified on + disk by external process. */ + bool bWarnModifiedOnDisk; + + /** Should files be sorted automatically when a project is loaded. */ + bool bAutoSortFiles; + + /** A command line pattern for an external editor (in read-only + mode.)*/ + QString sExtEditor; + + /** How KScope should treat time-consuming operations. */ + SysProfile profile; + + /** The type of popup menu to use in the embedded editor. */ + EditorPopup popup; + + /** The default orientation of call graphs. */ + QString sGraphOrient; + + /** Maximal number of called/calling functions per call graph node. */ + int nGraphMaxNodeDegree; + + /** Default view for the call graph dialogue. */ + int nDefGraphView; + }; + + /** The current configuration parameters */ + ConfParams m_cp; + + /** Holds default values for the configuration parameters */ + static ConfParams s_cpDef; + + /** Write font preferences only if modified by the user (keep default + setting otherwise) */ + bool m_bFontsChanged; +}; + +extern KScopeConfig& Config(); + +#endif diff --git a/src/kscopepixmaps.cpp b/src/kscopepixmaps.cpp new file mode 100644 index 0000000..495d756 --- /dev/null +++ b/src/kscopepixmaps.cpp @@ -0,0 +1,376 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <kglobal.h> +#include <kiconloader.h> +#include "kscopepixmaps.h" + +static const char* XPM_FUNC[] = { + "12 12 2 1", + ". c #000000", + "# c #58a8ff", + "............", + ".##########.", + ".###....###.", + ".###.######.", + ".###.######.", + ".###.######.", + ".###....###.", + ".###.######.", + ".###.######.", + ".###.######.", + ".##########.", + "............" +}; + +static const char* XPM_VAR[] = { + "12 12 3 1", + ". c #000000", + "a c #c00000", + "# c #ff0000", + "............", + ".##########.", + ".##########.", + ".##.####.##.", + ".##.####.##.", + ".##.a##a.##.", + ".##a.##.a##.", + ".###.aa.###.", + ".###a..a###.", + ".####..####.", + ".##########.", + "............" +}; + +static const char* XPM_STRUCT[] = { + "12 12 2 1", + ". c #000000", + "# c #ffff00", + "............", + ".##########.", + ".####...###.", + ".###.###.##.", + ".###.######.", + ".####.#####.", + ".#####.####.", + ".######.###.", + ".##.###.###.", + ".###...####.", + ".##########.", + "............" +}; + +static const char* XPM_MACRO[] = { + "12 12 2 1", + ". c #000000", + "# c #00c000", + "............", + ".##########.", + ".##.####.##.", + ".##..##..##.", + ".##.#..#.##.", + ".##.####.##.", + ".##.####.##.", + ".##.####.##.", + ".##.####.##.", + ".##.####.##.", + ".##########.", + "............" +}; + +static const char* XPM_MEMBER[] = { + "12 12 3 1", + ". c #000000", + "a c #0000c0", + "# c #c0c0ff", + "............", + ".##########.", + ".##########.", + ".##########.", + ".##a.##.a##.", + ".##.a..a.##.", + ".##.#aa#.##.", + ".##.####.##.", + ".##.####.##.", + ".##########.", + ".##########.", + "............" +}; + +static const char* XPM_ENUM[] = { + "12 12 2 1", + ". c #000000", + "# c #ff00ff", + "............", + ".##########.", + ".##########.", + ".##......##.", + ".##.#######.", + ".##.#######.", + ".##.....###.", + ".##.#######.", + ".##.#######.", + ".##......##.", + ".##########.", + "............" +}; + +static const char* XPM_ENUMERATOR[] = { + "12 12 2 1", + ". c #000000", + "# c #ffc0c0", + "............", + ".##########.", + ".##########.", + ".###...####.", + ".##.###.###.", + ".##.###.###.", + ".##.....###.", + ".##.#######.", + ".##.###.###.", + ".###...####.", + ".##########.", + "............" +}; + +static const char* XPM_TYPEDEF[] = { + "12 12 2 1", + ". c #000000", + "# c #c0ffc0", + "............", + ".##########.", + ".#.......##.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".##########.", + "............" +}; + +static const char* XPM_LABEL[] = { + "12 12 2 1", + ". c #000000", + "# c #c0ff00", + "............", + ".##########.", + ".#.########.", + ".#.########.", + ".#.########.", + ".#.########.", + ".#.########.", + ".#.########.", + ".#.########.", + ".#.......##.", + ".##########.", + "............" +}; + +static const char* XPM_INCLUDE[] = { + "12 12 2 1", + ". c #000000", + "# c #c0c0c0", + "............", + ".##########.", + ".##.....###.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".####.#####.", + ".##.....###.", + ".##########.", + "............" +}; + +static const char* XPM_UNKNOWN[] = { + "12 12 2 1", + ". c #000000", + "# c #ffffff", + "............", + ".##########.", + ".##.....###.", + ".#.#####.##.", + ".########.#.", + ".########.#.", + ".#######.##.", + ".######.###.", + ".####.#####.", + ".##########.", + ".####.#####.", + "............" +}; + +/** + * Class constructor. + */ +KScopePixmaps::KScopePixmaps() : + m_pPixArray(NULL), + m_loader() +{ +} + +/** + * Class destructor. + */ +KScopePixmaps::~KScopePixmaps() +{ + int i; + + for (i = 0; i < PIX_ARRAY_SIZE; i++) + delete m_pPixArray[i]; + + delete [] m_pPixArray; +} + +/** + * Creates the array of embedded pixmaps. + * This function is separated from the constructor since QPixmap objects + * cannot be created at the time the static KScopePixmaps object is + * allocated. + */ +void KScopePixmaps::init() +{ + // Create the pixmap array + m_pPixArray = new QPixmap * [PIX_ARRAY_SIZE]; + + // Create all pixmaps + m_pPixArray[SymFunc] = new QPixmap(XPM_FUNC); + m_pPixArray[SymVar] = new QPixmap(XPM_VAR); + m_pPixArray[SymStruct] = new QPixmap(XPM_STRUCT); + m_pPixArray[SymMacro] = new QPixmap(XPM_MACRO); + m_pPixArray[SymMember] = new QPixmap(XPM_MEMBER); + m_pPixArray[SymEnum] = new QPixmap(XPM_ENUM); + m_pPixArray[SymEnumerator] = new QPixmap(XPM_ENUMERATOR); + m_pPixArray[SymTypedef] = new QPixmap(XPM_TYPEDEF); + m_pPixArray[SymLabel] = new QPixmap(XPM_LABEL); + m_pPixArray[SymInclude] = new QPixmap(XPM_INCLUDE); + m_pPixArray[SymUnknown] = new QPixmap(XPM_UNKNOWN); +} + +/** + * Returns a reference to an embedded pixmap. + * @param name The pixmap's identifier + * @return A reference to the requested pixmap + */ +const QPixmap& KScopePixmaps::getPixmap(PixName name) const +{ + return *m_pPixArray[name]; +} + +/** + * Loads a pixmap with the KIconLoader mechanism. + * @param name The pixmap's identifier + * @return The requested pixmap + */ +QPixmap KScopePixmaps::getPixmap(LoadPixName name) +{ + switch (name) { + case TabUnlocked: + return m_loader.loadIcon("query_unlocked", KIcon::Small, 0, + false); + + case TabLocked: + return m_loader.loadIcon("query_locked", KIcon::Small, 0, + false); + + case TabBookmark: + return m_loader.loadIcon("bookmark", KIcon::Small, 0, + false); + + case TabRW: + return m_loader.loadIcon("file_rw", KIcon::Small, 0, + false); + + case TabRO: + return m_loader.loadIcon("file_ro", KIcon::Small, 0, + false); + + case TabSave: + return m_loader.loadIcon("file_save", KIcon::Small, 0, + false); + + case TabFileList: + return m_loader.loadIcon("view_detailed", KIcon::Small, 0, + false); + + case TabFileTree: + return m_loader.loadIcon("view_tree", KIcon::Small, 0, + false); + + case TabList: + return m_loader.loadIcon("tab_list", KIcon::Small, 0, + false); + + case ButtonSaveAs: + return m_loader.loadIcon("filesaveas", KIcon::Toolbar, + 0, false); + + case ButtonZoomIn: + return m_loader.loadIcon("viewmag+", KIcon::Toolbar, + 0, false); + + case ButtonZoomOut: + return m_loader.loadIcon("viewmag-", KIcon::Toolbar, + 0, false); + + case ButtonRotate: + return m_loader.loadIcon("rotate", KIcon::Toolbar, + 0, false); + + case ButtonPref: + return m_loader.loadIcon("configure", KIcon::Toolbar, + 0, false); + + case CalledTree: + return m_loader.loadIcon("called_tree", KIcon::Toolbar, + 0, false); + + case CallingTree: + return m_loader.loadIcon("calling_tree", KIcon::Toolbar, + 0, false); + + case CallGraph: + return m_loader.loadIcon("call_graph", KIcon::Toolbar, + 0, false); + } + + return QPixmap(); +} + +/** + * @return A reference to a global KScopePixmaps object + */ +KScopePixmaps& Pixmaps() +{ + static KScopePixmaps pix; + return pix; +} diff --git a/src/kscopepixmaps.h b/src/kscopepixmaps.h new file mode 100644 index 0000000..e5f321b --- /dev/null +++ b/src/kscopepixmaps.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef KSCOPEPIXMAPS_H +#define KSCOPEPIXMAPS_H + +#include <qpixmap.h> +#include <kiconloader.h> + +#define GET_PIXMAP(_pix) \ + Pixmaps().getPixmap(KScopePixmaps::_pix) + +/** + * Handles all pixmaps required by KScope. + * There are two types of pixmaps: embedded, i.e., pixmaps whose pixels are + * given by static two-dimensional arrays, and loadable, which are retrieved + * through the KIconLoader mechanism. + * The application uses a single global instance of this class. + * @author Elad Lahav + */ + +class KScopePixmaps +{ +public: + KScopePixmaps(); + ~KScopePixmaps(); + + /** Identifiers for embedded pixmaps. */ + enum PixName { SymFunc, SymVar, SymStruct, SymMacro, SymMember, SymEnum, + SymEnumerator, SymTypedef, SymLabel, SymInclude, SymUnknown, + PIX_ARRAY_SIZE }; + + /** Identifiers for loadable pixmaps. */ + enum LoadPixName { TabUnlocked, TabLocked, TabBookmark, TabRW, TabRO, + TabSave, TabFileList, TabFileTree, TabList, ButtonSaveAs, ButtonZoomIn, + ButtonZoomOut, ButtonRotate, ButtonPref, CalledTree, + CallingTree, CallGraph }; + + void init(); + const QPixmap& getPixmap(PixName name) const; + QPixmap getPixmap(LoadPixName name); + +private: + /** An array of pointers to the embedded pixmaps. */ + QPixmap** m_pPixArray; + + /** An icon loader used to retrieve pixmaps through the KDE mechanism. */ + KIconLoader m_loader; +}; + +extern KScopePixmaps& Pixmaps(); + +#endif diff --git a/src/kscopeui.rc b/src/kscopeui.rc new file mode 100644 index 0000000..81d3646 --- /dev/null +++ b/src/kscopeui.rc @@ -0,0 +1,141 @@ +<!DOCTYPE kpartgui> +<kpartgui name="kscope"> +<MenuBar> + <Menu name="file"><text>&File</text> + <Merge/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="edit_external_editor"/> + <Separator/> + <Merge/> + <Action name="edit_goto_tag"/> + <Action name="edit_comp_symbol"/> + </Menu> + <Menu name="view"><text>&View</text> + <Action name="view_toggle_filelist_dock"/> + <Action name="view_toggle_query_dock"/> + <Action name="view_toggle_tag_list"/> + <Separator/> + <Merge/> + </Menu> + <Menu name="project"><text>&Project</text> + <Action name="project_new"/> + <Action name="project_open"/> + <Action name="project_cscope_out"/> + <Action name="project_add_rem_files"/> + <Action name="project_properties"/> + <Separator/> + <Action name="project_make"/> + <Action name="project_remake"/> + <Separator/> + <Action name="project_close"/> + </Menu> + <Menu name="cscope"><text>&Cscope</text> + <Action name="cscope_rebuild"/> + <Separator/> + <Action name="cscope_references"/> + <Action name="cscope_definition"/> + <Action name="cscope_called"/> + <Action name="cscope_calling"/> + <Action name="cscope_text"/> + <Action name="cscope_pattern"/> + <Action name="cscope_file"/> + <Action name="cscope_including"/> + <Separator/> + <Action name="cscope_quick_def"/> + <Action name="cscope_call_tree"/> + </Menu> + <Menu name="go"><text>&Go</text> + <Action name="go_prev_result"/> + <Action name="go_next_result"/> + <Separator/> + <Action name="go_prev_pos"/> + <Action name="go_next_pos"/> + <Action name="go_history"/> + <Separator/> + <Action name="go_bookmarks"/> + </Menu> + <Merge/> + <Menu name="window"><text>&Window</text> + <Action name="window_close_all"/> + <Action name="window_go_left"/> + <Action name="window_go_right"/> + <Separator/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Merge/> + </Menu> + <Menu name="help"><text>&Help</text> + <Action name="help_welcome"/> + <Merge/> + </Menu> +</MenuBar> +<Menu name="query_popup"><text>&Query</text> + <Action name="query_new"/> + <Action name="query_refresh"/> + <Action name="query_toggle_locked"/> + <Separator/> + <Action name="query_close"/> +</Menu> +<Menu name="ktexteditor_popup"> + <Merge/> + <Menu name="cscope"><text>Cscope</text> + <Action name="cscope_references"/> + <Action name="cscope_definition"/> + <Action name="cscope_called"/> + <Action name="cscope_calling"/> + <Action name="cscope_text"/> + <Action name="cscope_pattern"/> + <Action name="cscope_file"/> + <Action name="cscope_including"/> + <Separator/> + <Action name="cscope_quick_def"/> + <Action name="cscope_call_tree"/> + </Menu> + <Action name="edit_external_editor"/> + <Action name="file_close"/> +</Menu> +<Menu name="kscope_popup"> + <Action name="cscope_references"/> + <Action name="cscope_definition"/> + <Action name="cscope_called"/> + <Action name="cscope_calling"/> + <Action name="cscope_text"/> + <Action name="cscope_pattern"/> + <Action name="cscope_file"/> + <Action name="cscope_including"/> + <Separator/> + <Action name="cscope_quick_def"/> + <Action name="cscope_call_tree"/> + <Action name="edit_external_editor"/> + <Separator/> + <Action name="file_close"/> +</Menu> +<ToolBar fullWidth="true" name="mainToolBar"> + <Action name="file_close"/> +</ToolBar> +<ToolBar fullWidth="true" name="projectToolBar"><text>Project</text> + <Action name="project_open"/> + <Action name="cscope_rebuild"/> +</ToolBar> +<ToolBar fullWidth="true" name="navigateToolBar"><text>Navigation</text> + <Action name="go_prev_pos"/> + <Action name="go_next_pos"/> + <Action name="go_history"/> + <Action name="go_bookmarks"/> +</ToolBar> +<ToolBar fullWidth="true" name="queryToolBar"><text>Query</text> + <Action name="query_new"/> + <Action name="query_refresh"/> + <Action name="query_toggle_locked"/> + <Action name="query_close"/> + <Separator/> + <Action name="go_prev_result"/> + <Action name="go_next_result"/> +</ToolBar> +<ToolBar fullWidth="true" name="workspaceToolBar"><text>Workspace</text> + <Action name="view_toggle_tag_list"/> + <Action name="view_toggle_query_dock"/> + <Action name="view_toggle_filelist_dock"/> +</ToolBar> +</kpartgui> diff --git a/src/lo16-app-kscope.png b/src/lo16-app-kscope.png Binary files differnew file mode 100644 index 0000000..fd8ef48 --- /dev/null +++ b/src/lo16-app-kscope.png diff --git a/src/lo32-app-kscope.png b/src/lo32-app-kscope.png Binary files differnew file mode 100644 index 0000000..5bb28f8 --- /dev/null +++ b/src/lo32-app-kscope.png diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ffa7b55 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> + +#include "kscope.h" +#include "kscopeconfig.h" + +static const char *description = + I18N_NOOP("KScope\nA source-editing environment for KDE, based on " + "Cscope"); + +static KCmdLineOptions options[] = +{ + { "+[CSCOPE.OUT path]", + I18N_NOOP("Opens a cscope.out file in a temporary project"), 0 }, + { "+[CSCOPE.PROJ path | KScope project directory path]", + I18N_NOOP("Opens a KScope project"), 0 }, + KCmdLineLastOption +}; + +/** + * Defines the programme's entry point. + * Creates KScope's main window, and starts the event loop. + * @param argc Number of command line arguments + * @param argv Command line arguments + * @return Programme's exit value + */ +int main(int argc, char *argv[]) +{ + // Create the "About" dialogue + KAboutData aboutData( "kscope", I18N_NOOP("KScope"), + VERSION, description, KAboutData::License_BSD, + "(c) 2003-2007, Elad Lahav", 0, "http://kscope.sourceforge.net", + "elad_lahav@users.sf.net"); + aboutData.addAuthor("Elad Lahav", "Developer", + "elad_lahav@users.sf.net"); + aboutData.addCredit("Albert Yosher", + "Code completion, patches and bug fixes", "ayosher@users.sf.net"); + aboutData.addCredit("Gabor Fekete", "Bug fixes and patches", + "feketgai@index.hu"); + + // Initialise command-line argument parsing + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions(options); + + // Parse command line arguments + KCmdLineArgs* pArgs = KCmdLineArgs::parsedArgs(); + + // Create the main window + KApplication a; + KScope* pKScope = new KScope(); + a.setMainWidget(pKScope); + + // Display the main window + pKScope->show(); + + // Handle command-line arguments + if (pArgs->count() > 0) { + pKScope->parseCmdLine(pArgs); + } else if (Config().getLoadLastProj()) { + // No arguments given, load the most recent project + pKScope->openLastProject(); + } + + // Make sure Cscope is properly installed + pKScope->verifyCscope(); + + // Start the event loop + return a.exec(); +} diff --git a/src/makedlg.cpp b/src/makedlg.cpp new file mode 100644 index 0000000..ac60129 --- /dev/null +++ b/src/makedlg.cpp @@ -0,0 +1,267 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtextcodec.h> +#include <ktextbrowser.h> +#include <kcombobox.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <klocale.h> +#include "makedlg.h" +#include "makefrontend.h" +#include "queryview.h" + +/** Window flags for call-tree widgets. */ +#define MAKE_DLG_W_FLAGS \ + WStyle_Customize | \ + WStyle_NormalBorder | \ + WStyle_Title + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +MakeDlg::MakeDlg(QWidget* pParent, const char* szName) : + MakeLayout(pParent, szName, MAKE_DLG_W_FLAGS) +{ + // Don't show the "Function" column + m_pErrorView->setColumnWidthMode(0, QListView::Manual); + m_pErrorView->setColumnWidth(0, 0); + + // Create a new make front-end + m_pMake = new MakeFrontend(); + connect(m_pMake, SIGNAL(dataReady(FrontendToken*)), this, + SLOT(slotShowOutput(FrontendToken*))); + connect(m_pMake, SIGNAL(finished(uint)), this, SLOT(slotFinished(uint))); + connect(m_pMake, + SIGNAL(error(const QString&, const QString&, const QString&)), + this, + SLOT(slotAddError(const QString&, const QString&, const QString&))); + + // The Root URL control should browse directories + m_pRootURL->setMode(KFile::Directory); + + // Handle URL links in the browser + m_pOutputBrowser->setNotifyClick(true); + connect(m_pOutputBrowser, SIGNAL(urlClick(const QString&)), this, + SLOT(slotBrowserClicked(const QString&))); + + // Handle selections in the error view + connect(m_pErrorView, SIGNAL(lineRequested(const QString& , uint)), this, + SIGNAL(fileRequested(const QString&, uint))); + + // Do not allow duplicates in the command history + m_pCommandHistory->setDuplicatesEnabled(false); +} + +/** + * Class destructor. + */ +MakeDlg::~ MakeDlg() +{ + delete m_pMake; +} + +/** + * @return The currently set make command + */ +QString MakeDlg::getCommand() const +{ + return m_pCommandHistory->currentText(); +} + +/** + * @param sCmd The new make command to use + */ +void MakeDlg::setCommand(const QString& sCmd) +{ + m_pCommandHistory->setCurrentText(sCmd); + m_pCommandHistory->addToHistory(sCmd); +} + +/** + * @return The directory in which to run the make command + */ +QString MakeDlg::getDir() const +{ + return m_pRootURL->url(); +} + +/** + * @param sURL The new root directory to use + */ +void MakeDlg::setDir(const QString& sURL) +{ + m_pRootURL->setURL(sURL); +} + +/** + * Overrides the default close behaviour. + * Makes sure that a window is not closed while a make process is running, + * unless the user explicitly requests it. In this case, the make process + * is killed. + * @param pEvent The close event descriptor + */ +void MakeDlg::closeEvent(QCloseEvent* pEvent) +{ + // Check if a process is currently running + if (m_pMake->isRunning()) { + // Prompt the user + switch (KMessageBox::questionYesNoCancel(this, + i18n("A make process is running. Would you like to stop it first?"), + i18n("Close Make Window"))) { + case KMessageBox::Yes: + // Stop the process first + m_pMake->kill(); + break; + + case KMessageBox::No: + // Do nothing + break; + + case KMessageBox::Cancel: + // Abort closing + pEvent->ignore(); + return; + } + } + + QWidget::closeEvent(pEvent); +} + +/** + * Starts a make process using the user-supplied command. + * This slot is connected to the clicked() signal of the "Make" button. + */ +void MakeDlg::slotMake() +{ + QString sCommand; + + // Clear the current contents + m_pOutputBrowser->clear(); + m_pErrorView->clear(); + + // Run the make command + sCommand = m_pCommandHistory->currentText(); + if (!m_pMake->run("make", QStringList::split(" ", sCommand), + m_pRootURL->url())) { + KMessageBox::error(this, m_pMake->getRunError()); + return; + } + + // Add the command to the command history + m_pCommandHistory->addToHistory(sCommand); + + // Disbale the make button + m_pMakeButton->setEnabled(false); + m_pStopButton->setEnabled(true); +} + +/** + * Terminates the current make process. + * This slot is connected to the clicked() signal of the stop button. + */ +void MakeDlg::slotStop() +{ + m_pMake->kill(); +} + +/** + * Displays the parsed output, as generated by the MakeFrontend object. + * This slot is connected to the dataReady() signal of the make front-end. + * @param pToken Holds the parsed data + */ +void MakeDlg::slotShowOutput(FrontendToken* pToken) +{ + QString sData; + + // GCC uses unicode quote characters - this should ensure that they are + // treated correctly by the text browser widget + sData = QTextCodec::codecForLocale()->toUnicode(pToken->getData()); + m_pOutputBrowser->append(sData); +} + +/** + * Displays the results of the make command. + * This slot is connected to the finished() signal of the make front-end. + */ +void MakeDlg::slotFinished(uint) +{ + // Add "Success" or "Error" at the end of the output + if (m_pMake->exitStatus() == 0) { + m_pOutputBrowser->append("<font color=\"#008000\"><b>Success</b>" + "</font>"); + } + else { + m_pOutputBrowser->append("<font color=\"#ff0000\"><b>Error</b></font>"); + } + + // Re-enable the "Make" button + m_pMakeButton->setEnabled(true); + m_pStopButton->setEnabled(false); +} + +/** + * Emits the fileRequested() signal when a browser link is clicked. + * This slot is connected to the urlClick() signal of the browser. + * @param sURL The requested URL + */ +void MakeDlg::slotBrowserClicked(const QString& sURL) +{ + QString sFile; + QString sLine; + + // Exract the file name and the line number from the URL + sFile = sURL.section('&', 0, 0); + sLine = sURL.section('&', 1, 1); + + // Add root path for relative paths + if (!sFile.startsWith("/")) + sFile = m_pRootURL->url() + "/" + sFile; + + // Emit the signal + emit fileRequested(sFile, sLine.toUInt()); +} + +/** + * Show an error/warning on a deidicated list. + * This slot is connected to the error() signal of the make front-end. + * @param sFile The file name containing the error/warning + * @param sLine The line number + * @param sText An explanation of the error + */ +void MakeDlg::slotAddError(const QString& sFile, const QString& sLine, + const QString& sText) +{ + QString sUniText; + + sUniText = QTextCodec::codecForLocale()->toUnicode(sText); + m_pErrorView->addRecord("", sFile, sLine, sUniText); +} + +#include "makedlg.moc" diff --git a/src/makedlg.h b/src/makedlg.h new file mode 100644 index 0000000..3120b95 --- /dev/null +++ b/src/makedlg.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef MAKEDLG_H +#define MAKEDLG_H + +#include "makelayout.h" + +class MakeFrontend; +class FrontendToken; + +/** + * A window that displays the output of make-like commands. + * The window contains a text browser showing errors as links to source + * locations. + * The make process is determined by a user-specified command, and is run in + * a user-specified directory. Controls are provided for modifying these values. + * @author Elad Lahav + */ +class MakeDlg: public MakeLayout +{ + Q_OBJECT + +public: + MakeDlg(QWidget* pParent = 0, const char* szName = 0); + virtual ~MakeDlg(); + + QString getCommand() const; + void setCommand(const QString&); + QString getDir() const; + void setDir(const QString&); + +public slots: + virtual void slotMake(); + +signals: + void fileRequested(const QString&, uint); + +protected: + virtual void closeEvent(QCloseEvent*); + +protected slots: + virtual void slotStop(); + void slotShowOutput(FrontendToken*); + void slotFinished(uint); + void slotBrowserClicked(const QString&); + void slotAddError(const QString&, const QString&, const QString&); + +private: + /** Handles the make process. */ + MakeFrontend* m_pMake; +}; + +#endif diff --git a/src/makefrontend.cpp b/src/makefrontend.cpp new file mode 100644 index 0000000..80ea9b8 --- /dev/null +++ b/src/makefrontend.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qregexp.h> +#include "makefrontend.h" + +// TODO: +// This should probably be configurable on a per-project basis. +#define PATH_ELEM "[a-zA-Z0-9_\\.\\-]+" + +#define RE_FILE_LINE \ + "((?:\\/)?(?:"PATH_ELEM"\\/)*"PATH_ELEM"):([0-9]+)(:[0-9]+)?: (.*)" +#define RE_ENTER_DIR \ + "Entering directory " \ + "\\`((\\/)?("PATH_ELEM"\\/)*"PATH_ELEM")" +#define RE_EXIT_DIR "Leaving directory" + +/** + * Class constructor. + * @param bAutoDelete If true, the object is deleted when the process + * terminates (false by default) + */ +MakeFrontend::MakeFrontend(bool bAutoDelete) : Frontend(1, bAutoDelete) +{ + // Execute inside a shell + setUseShell(true); + + // Each token represent a complete line + m_delim = Newline; +} + +/** + * Class destructor. + */ +MakeFrontend::~MakeFrontend() +{ +} + +/** + * Executes the make command. + * @param sName The name of the process (for error messages) + * @param slArgs A list containing the command-line arguments + * @param sWorkDir Initial build directory + * @param bBlock (Optional) true to block, false otherwise + * @return true if the process was executed successfully, false otherwise + */ +bool MakeFrontend::run(const QString& sName, const QStringList& slArgs, + const QString& sWorkDir, bool bBlock) +{ + QStringList slShellArgs; + + // Store the current build directory + m_slPathStack.push_back(sWorkDir); + + // Join the output streams, so that they can both be parsed by + // parseStdout() + slShellArgs = slArgs; + slShellArgs << "2>&1"; + + // Execute the command + return Frontend::run(sName, slShellArgs, sWorkDir, bBlock); +} + +/** + * Parses lines of output produced by the make command. + * @param sToken A single line of output + */ +Frontend::ParseResult MakeFrontend::parseStdout(QString& sToken, ParserDelim) +{ + static QRegExp reErrWarn(RE_FILE_LINE); + static QRegExp reEntDir(RE_ENTER_DIR); + static QRegExp reExtDir(RE_EXIT_DIR); + QString sRep; + int nPos; + QString sFile, sLine, sText; + + if ((nPos = reErrWarn.search(sToken)) >= 0) { + // An error/warning message + if (sToken.at(nPos) == '/') { + sFile = reErrWarn.capturedTexts()[1]; + } + else { + sFile = m_slPathStack.last() + "/" + + reErrWarn.capturedTexts()[1]; + } + + sLine = reErrWarn.capturedTexts()[2]; + sText = reErrWarn.capturedTexts()[4]; + emit error(sFile, sLine, sText); + + sRep = QString("<a href=\"") + sFile + "&\\2\">\\1:\\2</a>\\3: \\4"; + sToken.replace(reErrWarn, sRep); + } + else if ((nPos = reEntDir.search(sToken)) >= 0) { + // Recursing into a directory + m_slPathStack.push_back(reEntDir.capturedTexts()[1]); + sToken = QString("<b>Entering directory</b> ") + + m_slPathStack.last(); + } + else if ((nPos = reExtDir.search(sToken)) >= 0) { + // Leaving a directory + sToken = QString("<b>Leaving directory</b> ") + + m_slPathStack.last(); + m_slPathStack.pop_back(); + } + + return RecordReady; +} + +#include "makefrontend.moc" diff --git a/src/makefrontend.h b/src/makefrontend.h new file mode 100644 index 0000000..4ed575f --- /dev/null +++ b/src/makefrontend.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * + * Copyright (C) 2006 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef MAKEFRONTEND_H +#define MAKEFRONTEND_H + +#include <frontend.h> + +/** + * A shell-process front-end intended for running make-like tasks. + * Records are single-line tokens delimited by newline characters. The parser + * replaces references to source lines (e.g., filename:123) with hypertext + * links for use in a browser. + * @author Elad Lahav + */ +class MakeFrontend : public Frontend +{ + Q_OBJECT + +public: + MakeFrontend(bool bAutoDelete = false); + ~MakeFrontend(); + + virtual bool run(const QString&, const QStringList&, + const QString&, bool bBlock = false); + virtual ParseResult parseStdout(QString&, ParserDelim); + +signals: + void error(const QString& sFile, const QString& sLine, + const QString& sText); + +private: + /** A stack of paths used to track the current build directory. */ + QStringList m_slPathStack; +}; + +#endif diff --git a/src/makelayout.ui b/src/makelayout.ui new file mode 100644 index 0000000..e47acf8 --- /dev/null +++ b/src/makelayout.ui @@ -0,0 +1,245 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>MakeLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>MakeLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>768</width> + <height>642</height> + </rect> + </property> + <property name="caption"> + <string>KScope - Make</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Root Directory:</string> + </property> + </widget> + <widget class="KHistoryCombo" row="1" column="1"> + <property name="name"> + <cstring>m_pCommandHistory</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>m_pRootURL</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Command:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Output</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KTextBrowser"> + <property name="name"> + <cstring>m_pOutputBrowser</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Errors a&nd Warnings</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QueryView"> + <property name="name"> + <cstring>m_pErrorView</cstring> + </property> + </widget> + </vbox> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>520</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pMakeButton</cstring> + </property> + <property name="text"> + <string>&Make</string> + </property> + <property name="accel"> + <string>Alt+M</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pStopButton</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Stop</string> + </property> + <property name="accel"> + <string>Alt+S</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCloseButton</cstring> + </property> + <property name="text"> + <string>&Close</string> + </property> + <property name="accel"> + <string>Alt+C</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>QueryView</class> + <header location="local">queryview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data> + </image> +</images> +<connections> + <connection> + <sender>m_pCloseButton</sender> + <signal>clicked()</signal> + <receiver>MakeLayout</receiver> + <slot>close()</slot> + </connection> + <connection> + <sender>m_pMakeButton</sender> + <signal>clicked()</signal> + <receiver>MakeLayout</receiver> + <slot>slotMake()</slot> + </connection> + <connection> + <sender>m_pStopButton</sender> + <signal>clicked()</signal> + <receiver>MakeLayout</receiver> + <slot>slotStop()</slot> + </connection> + <connection> + <sender>m_pCommandHistory</sender> + <signal>returnPressed()</signal> + <receiver>MakeLayout</receiver> + <slot>slotMake()</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_pRootURL</tabstop> + <tabstop>m_pCommandHistory</tabstop> + <tabstop>m_pMakeButton</tabstop> + <tabstop>m_pStopButton</tabstop> + <tabstop>m_pCloseButton</tabstop> +</tabstops> +<slots> + <slot access="protected">slotStop()</slot> + <slot access="protected">slotMake()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>ktextbrowser.h</includehint> + <includehint>queryview.h</includehint> +</includehints> +</UI> diff --git a/src/newprojectdlg.cpp b/src/newprojectdlg.cpp new file mode 100644 index 0000000..ec8fbca --- /dev/null +++ b/src/newprojectdlg.cpp @@ -0,0 +1,354 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qregexp.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qtextedit.h> +#include <kurlrequester.h> +#include <klineedit.h> +#include <kmessagebox.h> +#include <klocale.h> +#include "newprojectdlg.h" + +/** + * Class constructor. + * @param bNewProj true to create a new project dialog, false to display + * the properties of an existing project + * @param pParent The parent widget + * @param szName The widget's name + */ +NewProjectDlg::NewProjectDlg(bool bNewProj, QWidget* pParent, + const char* szName) : + NewProjectLayout(pParent, szName), + m_bNewProj(bNewProj) +{ + ProjectBase::Options opt; + + // Create the auto-completion sub-dialogue + m_pAutoCompDlg = new AutoCompletionDlg(this); + + // Restrict the path requester to existing directories. + m_pPathRequester->setMode(KFile::Directory | KFile::ExistingOnly | + KFile::LocalOnly); + m_pSrcRootRequester->setMode(KFile::Directory | KFile::ExistingOnly | + KFile::LocalOnly); + + // Set up the Create/Cancel buttons + connect(m_pCreateButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + // Show the auto-completion properties dialogue + connect(m_pACButton, SIGNAL(clicked()), m_pAutoCompDlg, SLOT(exec())); + + // Perform actions specific to the type of dialog (new project or + // project properties) + if (bNewProj) { + // Set default project properties + ProjectBase::getDefOptions(opt); + setProperties("", "", opt); + } + else { + // Give appropriate titles to the dialog and the accept button + setCaption(i18n("Project Properties")); + m_pCreateButton->setText(i18n("OK")); + + // Disable the non-relevant widgets + m_pNameEdit->setEnabled(false); + m_pPathRequester->setEnabled(false); + } +} + +/** + * Class destructor. + */ +NewProjectDlg::~NewProjectDlg() +{ +} + +/** + * Configures the dialog's widget to display the properties of the current + * project. + * @param sName The project's name + * @param sPath The project's path + * @param opt Project parameters configurable in this dialogue + */ +void NewProjectDlg::setProperties(const QString& sName, const QString& sPath, + const ProjectBase::Options& opt) +{ + QStringList::ConstIterator itr; + + // Set values for current project + m_pNameEdit->setText(sName); + m_pPathRequester->setURL(sPath); + m_pSrcRootRequester->setURL(opt.sSrcRootPath); + m_pKernelCheck->setChecked(opt.bKernel); + m_pInvCheck->setChecked(opt.bInvIndex); + m_pNoCompCheck->setChecked(opt.bNoCompress); + m_pSlowPathCheck->setChecked(opt.bSlowPathDef); + + if (opt.nAutoRebuildTime >= 0) { + m_pAutoRebuildCheck->setChecked(true); + m_pAutoRebuildSpin->setValue(opt.nAutoRebuildTime); + } + + if (opt.bACEnabled) { + m_pACCheck->setChecked(true); + } + + if (opt.nTabWidth > 0) { + m_pTabWidthCheck->setChecked(true); + m_pTabWidthSpin->setValue(opt.nTabWidth); + } + + // Initialise the auto-completion sub-dialogue + m_pAutoCompDlg->m_nMinChars = opt.nACMinChars; + m_pAutoCompDlg->m_nDelay = opt.nACDelay; + m_pAutoCompDlg->m_nMaxEntries = opt.nACMaxEntries; + + // Add type strings to the types list box + for (itr = opt.slFileTypes.begin(); itr != opt.slFileTypes.end(); ++itr) + m_pTypesList->insertItem(*itr); + + m_pCtagsCmdEdit->setText(opt.sCtagsCmd); +} + +/** + * Retrieves the text entered by the user in the dialog's "Project Name" edit + * box. + * @return The name of the new project + */ +QString NewProjectDlg::getName() +{ + return m_pNameEdit->text(); +} + +/** + * Retrieves the text entered by the user in the dialog's "Project Path" edit + * box. + * Note that the chosen path will be the parent of the new project's + * directory, created under it using the project's name. + * @return The full path of the parent directory for the new project + */ +QString NewProjectDlg::getPath() +{ + if (m_pHiddenDirCheck->isChecked()) + return QString(m_pSrcRootRequester->url()) + "/.cscope"; + + return m_pPathRequester->url(); +} + +/** + * Fills a structure with all user-configured project options. + * @param opt The structure to fill + */ +void NewProjectDlg::getOptions(ProjectBase::Options& opt) +{ + opt.sSrcRootPath = m_pSrcRootRequester->url(); + opt.slFileTypes = m_slTypes; + opt.bKernel = m_pKernelCheck->isChecked(); + opt.bInvIndex = m_pInvCheck->isChecked(); + opt.bNoCompress = m_pNoCompCheck->isChecked(); + opt.bSlowPathDef = m_pSlowPathCheck->isChecked(); + + if (m_pAutoRebuildCheck->isChecked()) + opt.nAutoRebuildTime = m_pAutoRebuildSpin->value(); + else + opt.nAutoRebuildTime = -1; + + if (m_pTabWidthCheck->isChecked()) + opt.nTabWidth = m_pTabWidthSpin->value(); + else + opt.nTabWidth = 0; + + opt.bACEnabled = m_pACCheck->isChecked(); + opt.nACMinChars = m_pAutoCompDlg->m_nMinChars; + opt.nACDelay = m_pAutoCompDlg->m_nDelay; + opt.nACMaxEntries = m_pAutoCompDlg->m_nMaxEntries; + + opt.sCtagsCmd = m_pCtagsCmdEdit->text(); +} + +/** + * Ends the dialog after the user has clicked the "OK" button. + */ +void NewProjectDlg::accept() +{ + int i, nCount; + + // Validate the name of a new project + if (m_bNewProj) { + QRegExp re("[^ \\t\\n]+"); + if (!re.exactMatch(m_pNameEdit->text())) { + KMessageBox::error(0, i18n("Project names must not contain " + "whitespace.")); + return; + } + } + + // Fill the string list with all file types + nCount = (int)m_pTypesList->count(); + for (i = 0; i < nCount; i++) + m_slTypes.append(m_pTypesList->text(i)); + + // Clean-up the source root + QDir dir(m_pSrcRootRequester->url()); + if (dir.exists()) + m_pSrcRootRequester->setURL(dir.absPath()); + else + m_pSrcRootRequester->setURL("/"); + + // Close the dialog + QDialog::accept(); +} + +/** + * Adds the the file type string in the edit-box to the list of project types. + * This slot is called when the "Add.." button is clicked. + */ +void NewProjectDlg::slotAddType() +{ + QString sType; + + // Try the custom type edit-box first. + sType = m_pTypesEdit->text(); + sType.stripWhiteSpace(); + if (sType.isEmpty()) + return; + + // Validate the type string + QRegExp reg("[ \\t\\n\\|\\\\\\/]"); + if (sType.contains(reg)) { + KMessageBox::error(0, i18n("This is not a valid file type!")); + return; + } + + // Do not add an existing type. + if (m_pTypesList->findItem(sType, Qt::CaseSensitive | Qt::ExactMatch) != + NULL) { + return; + } + + // Add the file type to the list + m_pTypesList->insertItem(sType); + m_pTypesEdit->clear(); +} + +/** + * Removes the selected item from the list of file types. + * This slot is called when the "Remove" button is clicked. + */ +void NewProjectDlg::slotRemoveType() +{ + int nItem; + QString sType; + + // Verify an item is selected + nItem = m_pTypesList->currentItem(); + if (nItem == -1) + return; + + // Remove the selected item + sType = m_pTypesList->currentText(); + m_pTypesList->removeItem(nItem); + + // Add to the list of available types. + if (m_pAvailTypesList->findItem(sType, Qt::CaseSensitive | Qt::ExactMatch) + == NULL) { + m_pAvailTypesList->insertItem(sType); + } + +} + +/** + * Changes the text in the types edit-box to reflect the current selection in + * the list of available types. + * This slot is called whenever a new item is highlighted in the list of + * available types. + * @param sType The newly selected type + */ +void NewProjectDlg::slotAvailTypesChanged(const QString& sType) +{ + m_pTypesEdit->setText(sType); +} + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +AutoCompletionDlg::AutoCompletionDlg(QWidget* pParent, + const char* szName ) : + AutoCompletionLayout(pParent, szName) +{ + connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); +} + +/** + * Class destructor. + */ +AutoCompletionDlg::~AutoCompletionDlg() +{ +} + +/** + * Displays the dialogue, and waits for either the "OK" or "Cancel" button to + * be clicked. + * Before the dialogue is displayed, the stored values are set to the widgets. + * @return The dialogue's termination code + */ +int AutoCompletionDlg::exec() +{ + // Set current values + m_pMinCharsSpin->setValue(m_nMinChars); + m_pDelaySpin->setValue(m_nDelay); + m_pMaxEntriesSpin->setValue(m_nMaxEntries); + + // Show the dialogue + return QDialog::exec(); +} + +/** + * Stores the values set by the user in the dialogue widgets, and terminates + * the dialogue. + * This slot is connected to the clicked() signal of the "OK" button. + */ +void AutoCompletionDlg::accept() +{ + // Store widget values + m_nMinChars = m_pMinCharsSpin->value(); + m_nDelay = m_pDelaySpin->value(); + m_nMaxEntries = m_pMaxEntriesSpin->value(); + + // Close the dialogue, indicating acceptance + QDialog::accept(); +} + + +#include "newprojectdlg.moc" diff --git a/src/newprojectdlg.h b/src/newprojectdlg.h new file mode 100644 index 0000000..5d8e556 --- /dev/null +++ b/src/newprojectdlg.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef NEWPROJECTDLG_H +#define NEWPROJECTDLG_H + +#include <qlineedit.h> +#include <qcheckbox.h> +#include <newprojectlayout.h> +#include <autocompletionlayout.h> +#include "projectbase.h" + +/** + * A sub-dialogue of the New Project dialogue. + * Allows the user to configure auto-completion parameters. + * @author Elad Lahav + */ +class AutoCompletionDlg : public AutoCompletionLayout +{ + Q_OBJECT + +public: + AutoCompletionDlg(QWidget* pParent, const char* szName = NULL); + ~AutoCompletionDlg(); + +public slots: + int exec(); + +protected slots: + virtual void accept(); + +private: + /** The minimum number of characters in a symbol required for automatic + completion. */ + uint m_nMinChars; + + /** The time, in seconds, to wait before automatic completion is + attempted. */ + uint m_nDelay; + + /** The maximal number of results. */ + uint m_nMaxEntries; + + friend class NewProjectDlg; +}; + +/** + * A dialog for creating new projects. + * Prompts the user for the project's name, the directory for Cscope's files, + * the types of files included in the project and several options. + * Can also be used to change some of the properties of a project after it + * has been created. + * @author Elad Lahav + */ + +class NewProjectDlg : public NewProjectLayout +{ + Q_OBJECT + +public: + NewProjectDlg(bool, QWidget* pParent = NULL, const char* szName = NULL); + ~NewProjectDlg(); + + void setProperties(const QString&, const QString&, + const ProjectBase::Options&); + + QString getName(); + QString getPath(); + void getOptions(ProjectBase::Options&); + +protected slots: + virtual void accept(); + virtual void slotAddType(); + virtual void slotRemoveType(); + virtual void slotAvailTypesChanged(const QString&); + +private: + /** The file MIME-types associated with the new project. */ + QStringList m_slTypes; + + /** A sub-dialogue for configuring symbol auto-completion parameters. */ + AutoCompletionDlg* m_pAutoCompDlg; + + /** Whether the dialogue represents a new or existing project. */ + bool m_bNewProj; +}; + +#endif diff --git a/src/newprojectlayout.ui b/src/newprojectlayout.ui new file mode 100644 index 0000000..841b059 --- /dev/null +++ b/src/newprojectlayout.ui @@ -0,0 +1,778 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>NewProjectLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>NewProjectLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>539</width> + <height>383</height> + </rect> + </property> + <property name="caption"> + <string>Create Project</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Detai&ls</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout18</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Path</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>m_pNameEdit</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter a name for this project. +The name must conform to the file system's naming conventions for directories (e.g., no spaces, exclamaion marks, etc.).</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Name</string> + </property> + </widget> + <widget class="KURLRequester" row="1" column="1"> + <property name="name"> + <cstring>m_pPathRequester</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>The path to hold this project. +KScope will create a directory with the given name under this project, and populate it with the project configuration and database files. +This does not need to be the path in which the source files reside.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pHiddenDirCheck</cstring> + </property> + <property name="text"> + <string>&Use a hidden folder under the source root directory</string> + </property> + <property name="accel"> + <string>Alt+U</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Source Root (Optional)</string> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_pSrcRootRequester</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string><blockquote>A project consists of several files located in a directory + with the given name and path. The project's name needs to be a valid directory +name and must not contain any whitespace.</blockquote> +<br> +<blockquote>The Source Root is a convinient way to specify a common +path for all source files, but is not required.</blockquote></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer29</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>50</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>File T&ypes</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>This Project</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListBox"> + <property name="name"> + <cstring>m_pTypesList</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>KScope uses these filters to locate source files to include in this project.</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>61</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pAddButton</cstring> + </property> + <property name="text"> + <string><< &Add</string> + </property> + <property name="accel"> + <string>Alt+A</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Adds the selected file type to the current project.</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pRemoveButton</cstring> + </property> + <property name="text"> + <string>>> &Remove</string> + </property> + <property name="accel"> + <string>Alt+R</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Remove the selected file type from the project.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>50</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Available Types</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_pTypesEdit</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>You can enter custom file types here.</string> + </property> + </widget> + <widget class="QListBox"> + <item> + <property name="text"> + <string>*.c</string> + </property> + </item> + <item> + <property name="text"> + <string>*.h</string> + </property> + </item> + <item> + <property name="text"> + <string>*.l</string> + </property> + </item> + <item> + <property name="text"> + <string>*.y</string> + </property> + </item> + <item> + <property name="text"> + <string>*.S</string> + </property> + </item> + <item> + <property name="text"> + <string>*.cc</string> + </property> + </item> + <item> + <property name="text"> + <string>*.cpp</string> + </property> + </item> + <item> + <property name="text"> + <string>*.cxx</string> + </property> + </item> + <item> + <property name="text"> + <string>*.C</string> + </property> + </item> + <item> + <property name="text"> + <string>*.hh</string> + </property> + </item> + <item> + <property name="text"> + <string>*.hpp</string> + </property> + </item> + <item> + <property name="text"> + <string>*.hxx</string> + </property> + </item> + <item> + <property name="text"> + <string>*.H</string> + </property> + </item> + <property name="name"> + <cstring>m_pAvailTypesList</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>A list of standard file types.</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer8_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>61</width> + <height>21</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>&Options</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pKernelCheck</cstring> + </property> + <property name="text"> + <string>Kernel project (-k)</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string>For kernel projects, symbols are not looked up in the standard include path.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pInvCheck</cstring> + </property> + <property name="text"> + <string>Build inverted inde&x (-q)</string> + </property> + <property name="accel"> + <string>Alt+X</string> + </property> + <property name="whatsThis" stdset="0"> + <string>An inverted index may greatly speed up searches in a large project. The project's building process is longer, though.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pNoCompCheck</cstring> + </property> + <property name="text"> + <string>Do not compress the database (-c)</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pSlowPathCheck</cstring> + </property> + <property name="text"> + <string>Slower, but more accurate, function definition detection (-D)</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout31</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pAutoRebuildCheck</cstring> + </property> + <property name="text"> + <string>Refresh data&base automatically</string> + </property> + <property name="accel"> + <string>Alt+B</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Rebuild the database after changed files are saved to disk.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer32</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>125</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>m_pAutoRebuildLabel</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>(Seconds)</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pAutoRebuildSpin</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="whatsThis" stdset="0"> + <string>Wait this number of seconds after the last save before rebuilding the database.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout30</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pACCheck</cstring> + </property> + <property name="text"> + <string>&Use symbol auto-completion</string> + </property> + <property name="accel"> + <string>Alt+U</string> + </property> + <property name="whatsThis" stdset="0"> + <string>As-you-type symbol completion.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer33</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>61</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pACButton</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Options...</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pTabWidthCheck</cstring> + </property> + <property name="text"> + <string>Override default tab width (Kate only)</string> + </property> + <property name="toolTip" stdset="0"> + <string>Overrides the editor's configured tab width</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>211</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_pTabWidthSpin</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer31</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>40</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>&Advanced</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_4</cstring> + </property> + <property name="text"> + <string>Ctags command line (Do not change unless you know what you are doing!)</string> + </property> + </widget> + <widget class="QTextEdit"> + <property name="name"> + <cstring>m_pCtagsCmdEdit</cstring> + </property> + <property name="textFormat"> + <enum>PlainText</enum> + </property> + <property name="autoFormatting"> + <set>AutoAll</set> + </property> + </widget> + </vbox> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>141</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCreateButton</cstring> + </property> + <property name="text"> + <string>&Create</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Ca&ncel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_pAddButton</sender> + <signal>clicked()</signal> + <receiver>NewProjectLayout</receiver> + <slot>slotAddType()</slot> + </connection> + <connection> + <sender>m_pRemoveButton</sender> + <signal>clicked()</signal> + <receiver>NewProjectLayout</receiver> + <slot>slotRemoveType()</slot> + </connection> + <connection> + <sender>m_pAutoRebuildCheck</sender> + <signal>toggled(bool)</signal> + <receiver>m_pAutoRebuildSpin</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_pACCheck</sender> + <signal>toggled(bool)</signal> + <receiver>m_pACButton</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_pAvailTypesList</sender> + <signal>highlighted(const QString&)</signal> + <receiver>NewProjectLayout</receiver> + <slot>slotAvailTypesChanged(const QString&)</slot> + </connection> + <connection> + <sender>m_pTabWidthCheck</sender> + <signal>toggled(bool)</signal> + <receiver>m_pTabWidthSpin</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_pAutoRebuildCheck</sender> + <signal>toggled(bool)</signal> + <receiver>m_pAutoRebuildLabel</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_pHiddenDirCheck</sender> + <signal>toggled(bool)</signal> + <receiver>m_pPathRequester</receiver> + <slot>setDisabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>m_pNameEdit</tabstop> + <tabstop>m_pPathRequester</tabstop> + <tabstop>m_pHiddenDirCheck</tabstop> + <tabstop>m_pSrcRootRequester</tabstop> + <tabstop>m_pAddButton</tabstop> + <tabstop>m_pRemoveButton</tabstop> + <tabstop>m_pKernelCheck</tabstop> + <tabstop>m_pInvCheck</tabstop> + <tabstop>m_pNoCompCheck</tabstop> + <tabstop>m_pSlowPathCheck</tabstop> + <tabstop>m_pAutoRebuildCheck</tabstop> + <tabstop>m_pAutoRebuildSpin</tabstop> + <tabstop>m_pACCheck</tabstop> + <tabstop>m_pACButton</tabstop> + <tabstop>m_pTabWidthCheck</tabstop> + <tabstop>m_pTabWidthSpin</tabstop> + <tabstop>m_pCreateButton</tabstop> + <tabstop>m_pCancelButton</tabstop> + <tabstop>tabWidget2</tabstop> + <tabstop>m_pTypesList</tabstop> + <tabstop>m_pTypesEdit</tabstop> + <tabstop>m_pAvailTypesList</tabstop> + <tabstop>m_pCtagsCmdEdit</tabstop> +</tabstops> +<slots> + <slot access="protected">slotAddType()</slot> + <slot access="protected">slotRemoveType()</slot> + <slot access="protected">slotAutoRebuildChanged(bool)</slot> + <slot access="protected">slotAutoCompletionChanged(bool)</slot> + <slot access="protected">slotAvailTypesChanged(const QString&)</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/src/openprojectdlg.cpp b/src/openprojectdlg.cpp new file mode 100644 index 0000000..722fde6 --- /dev/null +++ b/src/openprojectdlg.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <kurlrequester.h> +#include "openprojectdlg.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +OpenProjectDlg::OpenProjectDlg(QWidget* pParent, const char* szName) : + OpenProjectLayout(pParent, szName) +{ + loadRecent(); + m_pProjPathRequester->setFilter("cscope.proj"); +} + +/** + * Class destructor. + */ +OpenProjectDlg::~OpenProjectDlg() +{ +} + +/** + * @return The selected project path + */ +QString OpenProjectDlg::getPath() const +{ + return m_pProjPathRequester->url(); +} + +/** + * Sets the requester to reflect the selected project's directory, instead of + * the cscope.proj file. + * @param sProjPath The full path of the selected cscope.proj file + */ +void OpenProjectDlg::slotProjectSelected(const QString& sProjPath) +{ + QFileInfo fi(sProjPath); + m_pProjPathRequester->setURL(fi.dirPath(true)); +} + +/** + * Removes a project from the recent projects list. + * This slot is connected to the clicked() signal of the "Remove" button. + */ +void OpenProjectDlg::slotRemoveRecent() +{ + QListBoxItem* pItem; + + // Remove the selected item, if any + pItem = m_pRecentList->selectedItem(); + if (pItem != NULL) { + Config().removeRecentProject(pItem->text()); + m_pRecentList->removeItem(m_pRecentList->currentItem()); + } +} + +/** + * Selects a project for opening when an item is highlighted in the recent + * projects list. + * This slot is connected to the highlighted() signal of the recent projects + * list box. + * @param pItem The selected project item + */ +void OpenProjectDlg::slotSelectRecent(QListBoxItem* pItem) +{ + if (pItem != NULL) + m_pProjPathRequester->setURL(pItem->text()); +} + +/** + * Selects a project for opening and closes the dialogue when an item in the + * recent projects list is double-clicked. + * This slot is connected to the doubleClicked() signal of the recent + * projects list box. + * @param pItem The selected project item + */ +void OpenProjectDlg::slotOpenRecent(QListBoxItem* pItem) +{ + if (pItem != NULL) { + m_pProjPathRequester->setURL(pItem->text()); + accept(); + } +} + +/** + * Fills the recent projects list box with the project paths read from the + * configuration file. + */ +void OpenProjectDlg::loadRecent() +{ + const QStringList& slProjects = Config().getRecentProjects(); + QStringList::const_iterator itr; + + // Create a list item for each project in the list + for (itr = slProjects.begin(); itr != slProjects.end(); ++itr) + m_pRecentList->insertItem(*itr); +} + +#include "openprojectdlg.moc" diff --git a/src/openprojectdlg.h b/src/openprojectdlg.h new file mode 100644 index 0000000..cf492ad --- /dev/null +++ b/src/openprojectdlg.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef OPENPROJECTDLG_H +#define OPENPROJECTDLG_H + +#include <qwidget.h> +#include <openprojectlayout.h> + +/** + * A dialogue for selecting a project to open. + * Allows projects to be searched, and displays a list of previosuly loaded + * projects. + * @author Elad Lahav + */ + +class OpenProjectDlg : public OpenProjectLayout +{ + Q_OBJECT + +public: + OpenProjectDlg(QWidget* pParent = 0, const char* szName = 0); + ~OpenProjectDlg(); + + QString getPath() const; + +protected slots: + virtual void slotProjectSelected(const QString&); + virtual void slotRemoveRecent(); + virtual void slotSelectRecent(QListBoxItem*); + virtual void slotOpenRecent(QListBoxItem*); + +private: + void loadRecent(); +}; + +#endif diff --git a/src/openprojectlayout.ui b/src/openprojectlayout.ui new file mode 100644 index 0000000..88d52be --- /dev/null +++ b/src/openprojectlayout.ui @@ -0,0 +1,202 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>OpenProjectLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>OpenProjectLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>417</width> + <height>384</height> + </rect> + </property> + <property name="caption"> + <string>Open Project</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup5</cstring> + </property> + <property name="title"> + <string>Project Path</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_pProjPathRequester</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup6</cstring> + </property> + <property name="title"> + <string>Recent Projects</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListBox"> + <property name="name"> + <cstring>m_pRecentList</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>281</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pRemoveButton</cstring> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>201</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pOpenButton</cstring> + </property> + <property name="text"> + <string>&Open</string> + </property> + <property name="accel"> + <string>Alt+O</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>C&ancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_pOpenButton</sender> + <signal>clicked()</signal> + <receiver>OpenProjectLayout</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>m_pCancelButton</sender> + <signal>clicked()</signal> + <receiver>OpenProjectLayout</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>m_pRemoveButton</sender> + <signal>clicked()</signal> + <receiver>OpenProjectLayout</receiver> + <slot>slotRemoveRecent()</slot> + </connection> + <connection> + <sender>m_pRecentList</sender> + <signal>highlighted(QListBoxItem*)</signal> + <receiver>OpenProjectLayout</receiver> + <slot>slotSelectRecent(QListBoxItem*)</slot> + </connection> + <connection> + <sender>m_pRecentList</sender> + <signal>doubleClicked(QListBoxItem*)</signal> + <receiver>OpenProjectLayout</receiver> + <slot>slotOpenRecent(QListBoxItem*)</slot> + </connection> + <connection> + <sender>m_pProjPathRequester</sender> + <signal>urlSelected(const QString&)</signal> + <receiver>OpenProjectLayout</receiver> + <slot>slotProjectSelected(const QString&)</slot> + </connection> + <connection> + <sender>m_pRecentList</sender> + <signal>returnPressed(QListBoxItem*)</signal> + <receiver>OpenProjectLayout</receiver> + <slot>slotOpenRecent(QListBoxItem*)</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotRemoveRecent()</slot> + <slot access="protected">slotSelectRecent(QListBoxItem*)</slot> + <slot access="protected">slotOpenRecent(QListBoxItem*)</slot> + <slot access="protected">slotProjectSelected(const QString&)</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/src/prefcolor.cpp b/src/prefcolor.cpp new file mode 100644 index 0000000..85beb4b --- /dev/null +++ b/src/prefcolor.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlistview.h> +#include <qpainter.h> +#include <kcolordialog.h> +#include "prefcolor.h" +#include "kscopeconfig.h" + +/** + * A list view item that shows the name of a GUI element and the colour + * associated with it. + * The colour is presented in the form of a rectangle filled with that + * colour. + * @author Elad Lahav + */ +class ColorListItem : public QListViewItem +{ +public: + /** + * Class constructor. + * @param pList The owner list view + * @param ce The GUI element shown by this item + */ + ColorListItem(QListView* pList, KScopeConfig::ColorElement ce) : + QListViewItem(pList, Config().getColorName(ce), ""), + m_ce(ce) { + setColor(Config().getColor(ce)); + } + + /** + * @return The GUI element shown by this item + */ + KScopeConfig::ColorElement getElement() { return m_ce; } + + /** + * Changes the colour associated with this item. + * The function assigns a pixmap to the item which shows a rectangle + * filled with the requested colour. + * The colour set by this function is returned by getColor(). + * @param clr The colour to set + */ + void setColor(QColor clr) { + QPixmap pix; + QPainter painter; + int nWidth, nHeight; + + // Remember the colour + m_clr = clr; + + // Set the pixmap's size to fit into the list field + nWidth = listView()->columnWidth(1) - 1; + nHeight = height(); + pix.resize(nWidth, nHeight); + + // Draw on the pixmap + painter.begin(&pix); + painter.setBrush(clr); + painter.drawRect(0, 0, nWidth, nHeight); + painter.end(); + + // Set the pixmap to the item + setPixmap(1, pix); + } + + /** + * @return The colour associated with this item + */ + QColor getColor() { return m_clr; } + +private: + /** The GUI element shown by this item. */ + KScopeConfig::ColorElement m_ce; + + /** The colour associated with this item. */ + QColor m_clr; +}; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +PrefColor::PrefColor(QWidget* pParent, const char* szName) : + PrefColorLayout(pParent, szName) +{ + m_pList->setColumnWidthMode(1, QListView::Manual); + + // Set initial values + load(); +} + +/** + * Class destructor. + */ +PrefColor::~PrefColor() +{ +} + +/** + * Reads the current settings from the configuration object, and applies them + * the the page's widget. + */ +void PrefColor::load() +{ + uint i; + ColorListItem* pItem; + + // Create a list item for every GUI element + for (i = 0; i <= KScopeConfig::LAST_COLOR; i++) + pItem = new ColorListItem(m_pList, (KScopeConfig::ColorElement)i); +} + +/** + * Commits settings changes to the configuration object. + */ +void PrefColor::apply() +{ + ColorListItem* pItem; + + // Create a list item for every GUI element + for (pItem = (ColorListItem*)m_pList->firstChild(); pItem != NULL; + pItem = (ColorListItem*)pItem->nextSibling()) { + Config().setColor(pItem->getElement(), pItem->getColor()); + } +} + +/** + * Displays a colour selection dialogue when an item is selected. + * If the user chooses a new colour, it is set to the selected item. + * This slot is connected to both the doubleClicked() and the returnPressed() + * signals of the list view. + * @param pItem The selected item + */ +void PrefColor::slotItemSelected(QListViewItem* pItem) +{ + ColorListItem* pClrItem; + QColor clr; + + pClrItem = (ColorListItem*)pItem; + if (KColorDialog::getColor(clr, pClrItem->getColor()) == + QDialog::Accepted) { + pClrItem->setColor(clr); + emit modified(); + } +} + +#include "prefcolor.moc" diff --git a/src/prefcolor.h b/src/prefcolor.h new file mode 100644 index 0000000..b26bed2 --- /dev/null +++ b/src/prefcolor.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PREFCOLORDLG_H +#define PREFCOLORDLG_H + +#include <prefcolorlayout.h> + +/** + * A widget for selecting colours for KScope's main child-windows. + * @author Elad Lahav + */ +class PrefColor : public PrefColorLayout +{ + Q_OBJECT + +public: + PrefColor(QWidget* pParent = 0, const char* szName = 0); + ~PrefColor(); + + void load(); + void apply(); + +signals: + /** + * Emitted whenever the user makes a change to the dialogue's input + * widgets. + */ + void modified(); + +protected slots: + void slotItemSelected(QListViewItem*); +}; + +#endif diff --git a/src/prefcolorlayout.ui b/src/prefcolorlayout.ui new file mode 100644 index 0000000..8e15bda --- /dev/null +++ b/src/prefcolorlayout.ui @@ -0,0 +1,69 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PrefColorLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PrefColorLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>350</width> + <height>210</height> + </rect> + </property> + <property name="caption"> + <string>Form4</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>GUI Element</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Colour</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <property name="name"> + <cstring>m_pList</cstring> + </property> + </widget> + </hbox> +</widget> +<connections> + <connection> + <sender>m_pList</sender> + <signal>doubleClicked(QListViewItem*)</signal> + <receiver>PrefColorLayout</receiver> + <slot>slotItemSelected(QListViewItem*)</slot> + </connection> + <connection> + <sender>m_pList</sender> + <signal>returnPressed(QListViewItem*)</signal> + <receiver>PrefColorLayout</receiver> + <slot>slotItemSelected(QListViewItem*)</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotItemSelected(QListViewItem*)</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/preferencesdlg.cpp b/src/preferencesdlg.cpp new file mode 100644 index 0000000..ab13c33 --- /dev/null +++ b/src/preferencesdlg.cpp @@ -0,0 +1,206 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlayout.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kurlrequester.h> +#include <klineedit.h> +#include <qcheckbox.h> +#include <kcolorbutton.h> +#include <kmessagebox.h> +#include <kfontrequester.h> +#include "preferencesdlg.h" +#include "preffrontend.h" +#include "prefcolor.h" +#include "preffont.h" +#include "prefopt.h" +#include "kscopeconfig.h" +#include "cscopefrontend.h" +#include "ctagsfrontend.h" +#include "dotfrontend.h" + + +/** + * Class constructor. + * @param nPage The initial page to show + * @param pParent The parent widget + * @param szName The widget's name + */ +PreferencesDlg::PreferencesDlg(uint nPage, QWidget* pParent, + const char* szName) : + KDialogBase(IconList, i18n("Preferences"), Default | Ok | Apply | Cancel, + Ok, pParent, szName, 0) +{ + QFrame* pFrame; + QVBoxLayout* pLayout; + + // Create and add the "Frontend" page + pFrame = addPage(i18n("Programmes"), + i18n("Paths to back-end programmes"), + KGlobal::iconLoader()->loadIcon("run", KIcon::Panel, 0, false)); + pLayout = new QVBoxLayout(pFrame, 0, 0); + m_pPrefFrontend = new PrefFrontend(pFrame); + pLayout->addWidget(m_pPrefFrontend); + + // Create and add the "Colours" page + pFrame = addPage(i18n("Colours"), i18n("Window colours"), + KGlobal::iconLoader()->loadIcon("colors", KIcon::Panel, 0, false)); + pLayout = new QVBoxLayout(pFrame, 0, 0); + m_pPrefColor = new PrefColor(pFrame); + pLayout->addWidget(m_pPrefColor); + + // Create and add the "Fonts" page + pFrame = addPage(i18n("Fonts"), i18n("Window fonts"), + KGlobal::iconLoader()->loadIcon("fonts", KIcon::Panel, 0, false)); + pLayout = new QVBoxLayout(pFrame, 0, 0); + m_pPrefFont = new PrefFont(pFrame); + pLayout->addWidget(m_pPrefFont); + + // Create and add the "Options" page + pFrame = addPage(i18n("Options"), i18n("Misc. Options"), + KGlobal::iconLoader()->loadIcon("package_settings", + KIcon::Panel, 0, false)); + pLayout = new QVBoxLayout(pFrame, 0, 0); + m_pPrefOpt = new PrefOpt(pFrame); + pLayout->addWidget(m_pPrefOpt); + + // Make sure the "Apply" button is initially disabled + enableButtonApply(false); + + // Enable the "Apply" button when a parameter changes its value + connect(m_pPrefFrontend, SIGNAL(modified()), this, + SLOT(slotModified())); + connect(m_pPrefColor, SIGNAL(modified()), this, SLOT(slotModified())); + connect(m_pPrefFont, SIGNAL(modified()), this, SLOT(slotModified())); + connect(m_pPrefOpt, SIGNAL(modified()), this, SLOT(slotModified())); + + // Set the active page + showPage(nPage); +} + +/** + * Class destructor. + */ +PreferencesDlg::~PreferencesDlg() +{ +} + +/** + * Updates the dialog's widgets with the current configuration parameters. + */ +void PreferencesDlg::loadConfig() +{ + m_pPrefFrontend->load(); + m_pPrefColor->load(); + m_pPrefFont->load(); + m_pPrefOpt->load(); +} + +/** + * Sets the configured parameters to the global configuration object. + * This method is called when either the "OK" or the "Apply" button are + * clicked. Before the new settings are applied, their values are verified. + * @return true if the new parameters were applied successfully, false + * otherwise + */ +bool PreferencesDlg::updateConfig() +{ + // Verify configured paths lead to the executables + if (!verifyPaths()) + return false; + + // Apply the changes + m_pPrefFrontend->apply(); + m_pPrefColor->apply(); + m_pPrefFont->apply(); + m_pPrefOpt->apply(); + + emit applyPref(); + return true; +} + +/** + * Tests whether the paths set for Cscope and Ctags lead to executables. + * Cscope is verified by a different process. + */ +bool PreferencesDlg::verifyPaths() +{ + return (CtagsFrontend::verify(m_pPrefFrontend->m_pCtagsURL->url()) && + DotFrontend::verify(m_pPrefFrontend->m_pDotURL->url())); +} + +/** + * Updates the global configuration based on the values given in the + * preferences dialogue, and then closes the dialogue. + * This function is called after the user clicks the dialogue's "OK" button. + */ +void PreferencesDlg::accept() +{ + if (updateConfig()) + KDialogBase::accept(); +} + +/** + * Updates the global configuration based on the values given in the + * preferences dialogue, leaving the dialogue open. + * This function is called after the user clicks the dialogue's "Apply" + * button. + */ +void PreferencesDlg::slotApply() +{ + if (updateConfig()) + enableButtonApply(false); +} + +/** + * Resets all configuration parameters to their default values. + * This slot is called when the user clicks the "Default" button. + */ +void PreferencesDlg::slotDefault() +{ + // Prompt the user before applying default values + if (KMessageBox::questionYesNo(0, i18n("This would reset all your " + "configuration settings! Continue?")) == KMessageBox::Yes) { + // Load the default values + Config().loadDefault(); + loadConfig(); + + // Apply the default values + slotApply(); + } +} + +/** + * Enables the "Apply" button. + */ +void PreferencesDlg::slotModified() +{ + enableButtonApply(true); +} + +#include "preferencesdlg.moc" diff --git a/src/preferencesdlg.h b/src/preferencesdlg.h new file mode 100644 index 0000000..51fa2cb --- /dev/null +++ b/src/preferencesdlg.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PREFERENCESDLG_H +#define PREFERENCESDLG_H + +#include <qwidget.h> +#include <kdialogbase.h> + +class PrefFrontend; +class PrefColor; +class PrefFont; +class PrefOpt; + +/** + * The main configuration dialog for KScope. + * This dialog displays a set of configuration pages, each dedicated to a + * different subject (frontend programme paths, colours, etc.) + * This code is based on a tutorial by Andreas Nicolai which can be found at + * http://www.kdevelop.org/doc/tutorial_settings + * @author Elad Lahav + */ + +class PreferencesDlg : public KDialogBase +{ + Q_OBJECT + +public: + PreferencesDlg(uint nPage = Frontend, QWidget* pParent = 0, const char* + szName = 0); + ~PreferencesDlg(); + + /** Available pages. */ + enum { Frontend = 0, Colors, Fonts, Options }; + +signals: + /** + * Emitted when the global configuration changes as a result of using + * this dialogue. + */ + void applyPref(); + +protected slots: + virtual void accept(); + virtual void slotApply(); + virtual void slotDefault(); + +private: + /** The front-end programmes page. */ + PrefFrontend* m_pPrefFrontend; + + /** The colours preference page. */ + PrefColor* m_pPrefColor; + + /** The fonts preference page. */ + PrefFont* m_pPrefFont; + + /** The additional options page. */ + PrefOpt* m_pPrefOpt; + + void loadConfig(); + bool updateConfig(); + bool verifyPaths(); + +private slots: + void slotModified(); +}; + +#endif diff --git a/src/preffont.cpp b/src/preffont.cpp new file mode 100644 index 0000000..288c699 --- /dev/null +++ b/src/preffont.cpp @@ -0,0 +1,174 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlistview.h> +#include <qpainter.h> +#include <kfontdialog.h> +#include <klocale.h> +#include "preffont.h" +#include "kscopeconfig.h" + +/** + * A list view item that shows the name of a GUI element and the font + * associated with it. + * The font is presented in the form of a sample text drawn using this font. + * @author Elad Lahav + */ +class FontListItem : public QListViewItem +{ +public: + /** + * Class constructor. + * @param pList The owner list view + * @param fe The GUI element shown by this item + */ + FontListItem(QListView* pList, KScopeConfig::FontElement fe) : + QListViewItem(pList, Config().getFontName(fe), ""), + m_fe(fe) { + setFont(Config().getFont(fe)); + } + + /** + * @return The GUI element shown by this item + */ + KScopeConfig::FontElement getElement() { return m_fe; } + + /** + * Changes the font associated with this item. + * The function a sample text on a pixmap using this font, and then + * assigns the pixmap to the list item. + * The font set by this function is returned by getFont(). + * @param font The font to set + */ + void setFont(QFont font) { + QPixmap pix; + QFontMetrics fm(font); + QPainter painter; + QRect rc; + + // Remember the font + m_font = font; + + // Set the pixmap's size so it can contain the sample text + rc = fm.boundingRect(i18n("Sample")); + rc.moveTopLeft(QPoint(0, 0)); + pix.resize(rc.width(), rc.height()); + + // Draw on the pixmap + pix.fill(); + painter.begin(&pix); + painter.setFont(font); + painter.setPen(black); + painter.drawText(rc, Qt::AlignHCenter | Qt::AlignVCenter, + i18n("Sample")); + painter.end(); + + // Set the pixmap to the item + setPixmap(1, pix); + } + + /** + * @return The font associated with this item + */ + QFont getFont() { return m_font; } + +private: + /** The GUI element shown by this item. */ + KScopeConfig::FontElement m_fe; + + /** The font associated with this item. */ + QFont m_font; +}; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +PrefFont::PrefFont(QWidget* pParent, const char* szName) : + PrefFontLayout(pParent, szName) +{ + // Set initial values + load(); +} + +/** + * Class destructor. + */ +PrefFont::~PrefFont() +{ +} + +/** + * Reads the current settings from the configuration object, and applies them + * the the page's widget. + */ +void PrefFont::load() +{ + uint i; + FontListItem* pItem; + + // Create a list item for every GUI element + for (i = 0; i <= KScopeConfig::LAST_FONT; i++) + pItem = new FontListItem(m_pList, (KScopeConfig::FontElement)i); +} + +/** + * Commits settings changes to the configuration object. + */ +void PrefFont::apply() +{ + FontListItem* pItem; + + // Create a list item for every GUI element + for (pItem = (FontListItem*)m_pList->firstChild(); pItem != NULL; + pItem = (FontListItem*)pItem->nextSibling()) { + Config().setFont(pItem->getElement(), pItem->getFont()); + } +} + +/** + * Displays a font selection dialogue when an item is selected. + * If the user chooses a new font, it is set to the selected item. + * This slot is connected to both the doubleClicked() and the returnPressed() + * signals of the list view. + * @param pItem The selected item + */ +void PrefFont::slotItemSelected(QListViewItem* pItem) +{ + FontListItem* pFontItem; + QFont font; + + pFontItem = (FontListItem*)pItem; + font = pFontItem->getFont(); + if (KFontDialog::getFont(font) == QDialog::Accepted) { + pFontItem->setFont(font); + emit modified(); + } +} + +#include "preffont.moc" diff --git a/src/preffont.h b/src/preffont.h new file mode 100644 index 0000000..66fdebc --- /dev/null +++ b/src/preffont.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PREFFONT_H +#define PREFFONT_H + +#include "preffontlayout.h" + +/** + * A widget for selecting fonts for KScope's main child-windows. + * @author Elad Lahav + */ + +class PrefFont : public PrefFontLayout +{ + Q_OBJECT + +public: + PrefFont(QWidget* pParent = 0, const char* szName = 0); + ~PrefFont(); + + void load(); + void apply(); + +signals: + /** + * Emitted whenever the user makes a change to the dialogue's input + * widgets. + */ + void modified(); + +protected slots: + void slotItemSelected(QListViewItem*); +}; + +#endif diff --git a/src/preffontlayout.ui b/src/preffontlayout.ui new file mode 100644 index 0000000..983da52 --- /dev/null +++ b/src/preffontlayout.ui @@ -0,0 +1,69 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PrefFontLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PrefFontLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>363</width> + <height>210</height> + </rect> + </property> + <property name="caption"> + <string>Form4</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView"> + <column> + <property name="text"> + <string>GUI Element</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Font</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>false</bool> + </property> + </column> + <property name="name"> + <cstring>m_pList</cstring> + </property> + </widget> + </hbox> +</widget> +<connections> + <connection> + <sender>m_pList</sender> + <signal>doubleClicked(QListViewItem*)</signal> + <receiver>PrefFontLayout</receiver> + <slot>slotItemSelected(QListViewItem*)</slot> + </connection> + <connection> + <sender>m_pList</sender> + <signal>returnPressed(QListViewItem*)</signal> + <receiver>PrefFontLayout</receiver> + <slot>slotItemSelected(QListViewItem*)</slot> + </connection> +</connections> +<slots> + <slot access="protected">slotItemSelected(QListViewItem*)</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/preffrontend.cpp b/src/preffrontend.cpp new file mode 100644 index 0000000..3bedda7 --- /dev/null +++ b/src/preffrontend.cpp @@ -0,0 +1,238 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qcheckbox.h> +#include <qtextedit.h> +#include <kurlrequester.h> +#include <klineedit.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include "preffrontend.h" +#include "kscopeconfig.h" +#include "configfrontend.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +PrefFrontend::PrefFrontend(QWidget* pParent, const char* szName) : + PrefFrontendLayout(pParent, szName) +{ + // Set initial values + load(); + + // Attempt to guess paths based on the user's PATH environment variable + connect(m_pGuessButton, SIGNAL(clicked()), this, + SLOT(slotGuessPaths())); + + // Emit the modified() signal when a new path is set + connect(m_pCscopeURL, SIGNAL(textChanged(const QString&)), this, + SIGNAL(modified())); + connect(m_pCtagsURL, SIGNAL(textChanged(const QString&)), this, + SIGNAL(modified())); + connect(m_pDotURL, SIGNAL(textChanged(const QString&)), this, + SIGNAL(modified())); +} + +/** + * Class destructor. + */ +PrefFrontend::~PrefFrontend() +{ +} + +/** + * Reads the current settings from the configuration object, and applies them + * the the page's widget. + */ +void PrefFrontend::load() +{ + m_pCscopeURL->lineEdit()->setText(Config().getCscopePath()); + m_pCtagsURL->lineEdit()->setText(Config().getCtagsPath()); + m_pDotURL->lineEdit()->setText(Config().getDotPath()); +} + +/** + * Commits settings changes to the configuration object. + */ +void PrefFrontend::apply() +{ + Config().setCscopePath(m_pCscopeURL->url()); + Config().setCtagsPath(m_pCtagsURL->url()); + Config().setDotPath(m_pDotURL->url()); +} + +/** + * Emits the modified() signal whenever any of the paths edit widgets changes + * its contents. + * This slot is connected to the textChanged() signal of each of the path + * edit widgets. By emitting the modified() signal, the widget notifies the + * parent dialog it should enable the "Apply" button. + */ +void PrefFrontend::slotChanged(const QString&) +{ + emit modified(); +} + +/** + * Checks the user's PATH environment variable for a Cscope and Ctags + * executables. + * This is done by running the kscope_config script. + */ +void PrefFrontend::slotGuessPaths() +{ + ConfigFrontend* pConf; + + // Start with an empty results text widget + m_pScriptText->clear(); + + // Create a frontend object for the script + pConf = new ConfigFrontend(true); + + // Show tests and results in the text widget + connect(pConf, SIGNAL(test(uint)), this, + SLOT(slotAutoConfigTest(uint))); + connect(pConf, SIGNAL(result(uint, const QString&)), this, + SLOT(slotAutoConfigResult(uint, const QString&))); + + // Run the script + pConf->run(m_pCscopeURL->url(), m_pCtagsURL->url(), + m_pDotURL->url()); +} + +/** + * Shows the test being executed by the script in the text widget. + * This slot is connected to the test() signal of the ConfigFrontend object. + * @param nType The type of test being executed + */ +void PrefFrontend::slotAutoConfigTest(uint nType) +{ + switch (nType) { + case ConfigFrontend::CscopePath: + m_pScriptText->insert(i18n("Looking for Cscope...")); + break; + + case ConfigFrontend::CscopeVersion: + m_pScriptText->insert(i18n("Checking Cscope version...")); + break; + + case ConfigFrontend::CscopeVerbose: + m_pScriptText->insert(i18n("Cscope support for line mode verbose " + "output...")); + break; + + case ConfigFrontend::CscopeSlowPath: + m_pScriptText->insert(i18n("Cscope support slow path definitions... ")); + break; + + case ConfigFrontend::CtagsPath: + m_pScriptText->insert(i18n("Looking for Ctags...")); + break; + + case ConfigFrontend::CtagsExub: + m_pScriptText->insert(i18n("Ctags compatibilty with ctags-exuberant" + "...")); + break; + + case ConfigFrontend::DotPath: + m_pScriptText->insert(i18n("Looking for Dot...")); + break; + + case ConfigFrontend::DotPlain: + m_pScriptText->insert(i18n("Checking -Tplain...")); + break; + } +} + +/** + * Shows the result of a test executed by the configuration script, and + * adjusts the configuration widgets accordingly. + * @param nType The type of test that was executed + * @param sResult The test's result + */ +void PrefFrontend::slotAutoConfigResult(uint nType, const QString& sResult) +{ + QString sLine; + + sLine = sResult + "\n"; + + switch (nType) { + case ConfigFrontend::CscopePath: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pCscopeURL->lineEdit()->setText(""); + else + m_pCscopeURL->lineEdit()->setText(sResult); + + break; + + case ConfigFrontend::CscopeVersion: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pCscopeURL->lineEdit()->setText(""); + break; + + case ConfigFrontend::CscopeVerbose: + m_pScriptText->insert(sLine); + break; + + case ConfigFrontend::CscopeSlowPath: + m_pScriptText->insert(sLine); + break; + + case ConfigFrontend::CtagsPath: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pCtagsURL->lineEdit()->setText(""); + else + m_pCtagsURL->lineEdit()->setText(sResult); + break; + + case ConfigFrontend::CtagsExub: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pCtagsURL->lineEdit()->setText(""); + break; + + case ConfigFrontend::DotPath: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pDotURL->lineEdit()->setText(""); + else + m_pDotURL->lineEdit()->setText(sResult); + break; + + case ConfigFrontend::DotPlain: + m_pScriptText->insert(sLine); + if (sResult == "ERROR") + m_pDotURL->lineEdit()->setText(""); + break; + } +} + +#include "preffrontend.moc" diff --git a/src/preffrontend.h b/src/preffrontend.h new file mode 100644 index 0000000..fb46242 --- /dev/null +++ b/src/preffrontend.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PREFFRONTENDDLG_H +#define PREFFRONTENDDLG_H + +#include <qwidget.h> +#include <preffrontendlayout.h> + +/** + * A widget for setting the paths to various programmes to which KScope + * provides a front-end. + * @author Elad Lahav + */ + +class PrefFrontend : public PrefFrontendLayout +{ + Q_OBJECT + +public: + PrefFrontend(QWidget* pParent = 0, const char* szName = 0); + ~PrefFrontend(); + + void load(); + void apply(); + +signals: + /** + * Emitted whenever the user makes a change to the dialogue's input + * widgets. + */ + void modified(); + +private slots: + void slotChanged(const QString&); + void slotGuessPaths(); + void slotAutoConfigTest(uint); + void slotAutoConfigResult(uint, const QString&); +}; + +#endif diff --git a/src/preffrontendlayout.ui b/src/preffrontendlayout.ui new file mode 100644 index 0000000..e6b00c9 --- /dev/null +++ b/src/preffrontendlayout.ui @@ -0,0 +1,193 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PrefFrontendLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PrefFrontendLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>415</width> + <height>368</height> + </rect> + </property> + <property name="caption"> + <string>Form3</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout20</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Cscope path:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Ctags path:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Dot path:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout18</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_pCscopeURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_pCtagsURL</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_pDotURL</cstring> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>261</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pGuessButton</cstring> + </property> + <property name="text"> + <string>G&uess</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QTextEdit"> + <property name="name"> + <cstring>m_pScriptText</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<tabstops> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/src/prefopt.cpp b/src/prefopt.cpp new file mode 100644 index 0000000..7b52d8f --- /dev/null +++ b/src/prefopt.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qlineedit.h> +#include <qlabel.h> +#include "prefopt.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +PrefOpt::PrefOpt(QWidget* pParent, const char* szName) + : PrefOptLayout(pParent, szName) +{ + // Set initial values + load(); + + // Emit the "modified" signal whenever any of the widgets changes its + // its. This will notify the parent dialogue to enable its "Apply" + // button + connect(m_pReadOnlyCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pLastProjCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pTagHlCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pBriefQueryCaptCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pWarnModifiedOnDiskCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pAutoSortCheck, SIGNAL(toggled(bool)), this, + SIGNAL(modified())); + connect(m_pExtEditorEdit, SIGNAL(textChanged(const QString&)), this, + SIGNAL(modified())); + connect(m_pSysProfileCB, SIGNAL(activated(int)), this, + SIGNAL(modified())); + connect(m_pEditorPopupCB, SIGNAL(activated(int)), this, + SIGNAL(modified())); +} + +/** + * Class destructor. + */ +PrefOpt::~PrefOpt() +{ +} + +/** + * Reads the current settings from the configuration object, and applies them + * the the page's widget. + */ +void PrefOpt::load() +{ + m_pReadOnlyCheck->setChecked(Config().getReadOnlyMode()); + m_pLastProjCheck->setChecked(Config().getLoadLastProj()); + m_pTagHlCheck->setChecked(Config().getAutoTagHl()); + m_pBriefQueryCaptCheck->setChecked(Config().getUseBriefQueryCaptions()); + m_pWarnModifiedOnDiskCheck->setChecked(Config().getWarnModifiedOnDisk()); + m_pAutoSortCheck->setChecked(Config().getAutoSortFiles()); + m_pExtEditorEdit->setText(Config().getExtEditor()); + + switch (Config().getSysProfile()) { + case KScopeConfig::Fast: + m_pSysProfileCB->setCurrentItem(0); + break; + + case KScopeConfig::Slow: + m_pSysProfileCB->setCurrentItem(1); + break; + } + + switch (Config().getEditorPopup()) { + case KScopeConfig::Embedded: + m_pEditorPopupCB->setCurrentItem(0); + break; + + case KScopeConfig::KScopeOnly: + m_pEditorPopupCB->setCurrentItem(1); + break; + } +} + +/** + * Commits settings changes to the configuration object. + */ +void PrefOpt::apply() +{ + Config().setReadOnlyMode(m_pReadOnlyCheck->isChecked()); + Config().setLoadLastProj(m_pLastProjCheck->isChecked()); + Config().setAutoTagHl(m_pTagHlCheck->isChecked()); + Config().setUseBriefQueryCaptions(m_pBriefQueryCaptCheck->isChecked()); + Config().setWarnModifiedOnDisk(m_pWarnModifiedOnDiskCheck->isChecked()); + Config().setAutoSortFiles(m_pAutoSortCheck->isChecked()); + Config().setExtEditor(m_pExtEditorEdit->text()); + + switch (m_pSysProfileCB->currentItem()) { + case 0 : + Config().setSysProfile(KScopeConfig::Fast); + break; + + case 1: + Config().setSysProfile(KScopeConfig::Slow); + break; + } + + switch (m_pEditorPopupCB->currentItem()) { + case 0: + Config().setEditorPopup(KScopeConfig::Embedded); + break; + + case 1: + Config().setEditorPopup(KScopeConfig::KScopeOnly); + break; + } +} + +#include "prefopt.moc" diff --git a/src/prefopt.h b/src/prefopt.h new file mode 100644 index 0000000..26e2572 --- /dev/null +++ b/src/prefopt.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PREFOPT_H +#define PREFOPT_H + +#include "prefoptlayout.h" + +/** + * A widget for setting different global options. + * @author Elad Lahav + */ + +class PrefOpt : public PrefOptLayout +{ + Q_OBJECT + +public: + PrefOpt(QWidget* pParent = 0, const char* szName = 0); + ~PrefOpt(); + + void load(); + void apply(); + +signals: + /** + * Emitted whenever the user makes a change to the dialogue's input + * widgets. + */ + void modified(); +}; + +#endif + diff --git a/src/prefoptlayout.ui b/src/prefoptlayout.ui new file mode 100644 index 0000000..cbc8d07 --- /dev/null +++ b/src/prefoptlayout.ui @@ -0,0 +1,217 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>PrefOptLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PrefOptLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>354</width> + <height>312</height> + </rect> + </property> + <property name="caption"> + <string>Form4</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Determines whether KScope should automatically load the last project when started.</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_pExtEditorLabel</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>External Editor</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_pExtEditorEdit</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pReadOnlyCheck</cstring> + </property> + <property name="text"> + <string>Read-Onl&y Mode</string> + </property> + <property name="accel"> + <string>Alt+Y</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Forces all editor windows to work in a read-only mode, so that the user cannot modify the displayed files.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pLastProjCheck</cstring> + </property> + <property name="text"> + <string>Open Last Project on Start-Up</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pTagHlCheck</cstring> + </property> + <property name="text"> + <string>Automatic Tag Highlighting</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Determines whether the tag list should highlight the relevant tag based on the cursor's position.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pBriefQueryCaptCheck</cstring> + </property> + <property name="text"> + <string>Brief Tab Captions for &Query Pages</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If set, the tab captions for query pages will be shortened, by using aliases for the query types.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pWarnModifiedOnDiskCheck</cstring> + </property> + <property name="text"> + <string>Warn When a File is Modified Outside KScope</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If set, the user is prompted whenever the currently edited file is changed by an external programme.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pAutoSortCheck</cstring> + </property> + <property name="text"> + <string>Automatically Sort Files in the File List</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="whatsThis" stdset="0"> + <string>Sorts files in the project's file list when a project is loaded. This may be too slow for large projects on older machines.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>System Profile</string> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Fast</string> + </property> + </item> + <item> + <property name="text"> + <string>Slow</string> + </property> + </item> + <property name="name"> + <cstring>m_pSysProfileCB</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Editor Popup Menu</string> + </property> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Embedded</string> + </property> + </item> + <item> + <property name="text"> + <string>KScope Only</string> + </property> + </item> + <property name="name"> + <cstring>m_pEditorPopupCB</cstring> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer11</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/progressdlg.cpp b/src/progressdlg.cpp new file mode 100644 index 0000000..418a3c9 --- /dev/null +++ b/src/progressdlg.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "progressdlg.h" + +/** + * Class constructor. + * @param sCaption The dialogue's title + * @param sText The text to display + * @param pParent The parent widget + * @param szName The widget's name + */ +ProgressDlg::ProgressDlg(const QString& sCaption, const QString& sText, + QWidget* pParent, const char* szName) : + KProgressDialog(pParent, szName, sCaption, sText, true), + m_nIdleValue(-1) +{ + setAutoClose(false); + setAllowCancel(false); + + // Create the idle-progress timer + m_pIdleTimer = new QTimer(this); + + // Display a busy indicator by increasing the value of the idle counter + connect (m_pIdleTimer, SIGNAL(timeout()), this, SLOT(slotShowBusy())); +} + +/** + * Class destructor. + */ +ProgressDlg::~ProgressDlg() +{ +} + +/** + * Sets a new value to the progress bar. + * If the new value is non-zero, the progress bar is advanced. Otherwise, the + * idle timer is initiated to display a busy indicator. + * @param nValue The new value to set. + */ +void ProgressDlg::setValue(int nValue) +{ + KProgress* pProgress; + + pProgress = progressBar(); + + if (nValue != 0) { + // Do nothing if the value hasn't changed + if (nValue == pProgress->progress()) + return; + + // Handle first non-zero value + if (m_nIdleValue >= 0) { + m_pIdleTimer->stop(); + m_nIdleValue = -1; + pProgress->setPercentageVisible(true); + } + + // Set the new value + pProgress->setValue(nValue); + } + else if (m_nIdleValue == -1) { + // Handle first 0 value + pProgress->setValue(0); + pProgress->setPercentageVisible(false); + m_nIdleValue = 0; + m_pIdleTimer->start(200); + } +} + +void ProgressDlg::setIdle() +{ + m_nIdleValue = -1; + setValue(0); +} + +/** + * Increaes the value of the dummy counter by 1. + * This slot is called by the timeout() event of the idle timer. + */ +void ProgressDlg::slotShowBusy() +{ + // Increase the counter + m_nIdleValue += 5; + if (m_nIdleValue == 100) + m_nIdleValue = 0; + + // Set the value of the progress-bar + progressBar()->setValue(m_nIdleValue); +} + +#include "progressdlg.moc" diff --git a/src/progressdlg.h b/src/progressdlg.h new file mode 100644 index 0000000..d5f0e6b --- /dev/null +++ b/src/progressdlg.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PROGRESSDLG_H +#define PROGRESSDLG_H + +#include <qwidget.h> +#include <qtimer.h> +#include <kprogress.h> + +/** + * An improved progress dialog. + * This variation of the standard KDE progress dialog displays a busy + * indicator while waiting for the first value greater than 0. + * @author Elad Lahav + */ + +class ProgressDlg : public KProgressDialog +{ + Q_OBJECT + +public: + ProgressDlg(const QString&, const QString&, QWidget* pParent = 0, const + char* szName = 0); + ~ProgressDlg(); + + void setValue(int); + void setIdle(); + +private: + /** When the value is 0, this timer initiates value changes that cause + the progress-bar to move. */ + QTimer* m_pIdleTimer; + + /** A dummy value used to move the progress-bar while the value is 0. */ + int m_nIdleValue; + +private slots: + void slotShowBusy(); +}; + +#endif diff --git a/src/project.cpp b/src/project.cpp new file mode 100644 index 0000000..06e1332 --- /dev/null +++ b/src/project.cpp @@ -0,0 +1,442 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <kmessagebox.h> +#include <klocale.h> +#include "project.h" +#include "kscopeconfig.h" +#include "cscopefrontend.h" + +#define PROJECT_CONFIG_VER 2 + +inline void flListFromStringList(FileLocationList& fll, const QStringList& sl) +{ + QStringList::ConstIterator itr; + QString sPath; + uint nLine, nCol; + + // Transform the string into a list of file locations + for (itr = sl.begin(); itr != sl.end(); ++itr) { + sPath = (*itr).section(':', 0, 0); + nLine = (*itr).section(':', 1, 1).toUInt(); + nCol = (*itr).section(':', 2, 2).toUInt(); + fll.append(new FileLocation(sPath, nLine, nCol)); + } +} + +inline void stringListFromFlList(QStringList& sl, const FileLocationList& fll) +{ + FileLocationList* pList; + FileLocation* pLoc; + QString sLoc; + + // Nasty... + pList = (FileLocationList*)&fll; + sl.clear(); + + // Turn the object list into a string list, so that it can be written in + // the configuration file + for (pLoc = pList->first(); pLoc != NULL; pLoc = pList->next()) { + sLoc = ""; + QTextOStream(&sLoc) << pLoc->m_sPath << ":" << pLoc->m_nLine << ":" + << pLoc->m_nCol; + sl.append(sLoc); + } +} + +/** + */ +Project::Project() : ProjectBase(), + m_pConf(NULL) +{ +} + +/** + */ +Project::~Project() +{ + close(); +} + +/** + */ +bool Project::open(const QString& sPath) +{ + QString sConfFile; + Options opt; + + // Associate the object with the project directory + m_dir.setPath(sPath); + if (!m_dir.exists()) { + KMessageBox::error(0, i18n("Project directory does not exist")); + return false; + } + + // Initialise the file-list file object + m_fiFileList.setName(sPath + "/cscope.files"); + + // Open the configuration files + m_pConf = new KConfig(sPath + "/cscope.proj"); + + // Verify the configuration file's version is compatible + m_pConf->setGroup(""); + if (m_pConf->readUnsignedNumEntry("Version", 0) != PROJECT_CONFIG_VER) { + KMessageBox::error(0, i18n("Your project is not compatible with this " + "version of KScope.\nPlease re-create the project.")); + return false; + } + + // Get the project name + m_pConf->setGroup("Project"); + m_sName = m_pConf->readEntry("Name"); + if (m_sName == QString::null) { + KMessageBox::error(0, i18n("Cannot read project name")); + return false; + } + + // Get stored options + initOptions(); + + // Set default make values for new projects (overriden in loadSession(), + // which is not called for new projects) + m_sMakeRoot = getSourceRoot(); + m_sMakeCmd = "make"; + + return true; +} + +/** + */ +void Project::close() +{ + if (m_pConf) + delete m_pConf; + + m_fiFileList.close(); +} + +/** + * Returns a semi-colon separated list of the file types included in the + * current project. + */ +QString Project::getFileTypes() const +{ + QString sTypes; + + m_pConf->setGroup("Project"); + return m_pConf->readEntry("FileTypes"); +} + +/** + * Reads the project's options from the configuration file. + * @param opt A structure to fill with the read options + */ +void Project::getOptions(Options& opt) const +{ + // Get project properties + m_pConf->setGroup("Project"); + opt.sSrcRootPath = m_pConf->readEntry("RootPath", "/"); + opt.slFileTypes = m_pConf->readListEntry("FileTypes", ' '); + opt.bKernel = m_pConf->readBoolEntry("Kernel", DEF_IS_KERNEL); + opt.bInvIndex = m_pConf->readBoolEntry("InvIndex", DEF_INV_INDEX); + opt.bNoCompress = m_pConf->readBoolEntry("NoCompress", DEF_NO_COMPRESS); + opt.bSlowPathDef = m_pConf->readBoolEntry("SlowPathDef", DEF_SLOW_PATH); + opt.nAutoRebuildTime = m_pConf->readNumEntry("AutoRebuildTime"); + opt.nTabWidth = m_pConf->readUnsignedNumEntry("TabWidth"); + opt.sCtagsCmd = m_pConf->readEntry("CtagsCommand", DEF_CTAGS_COMMAND); + + // Get auto-completion options + m_pConf->setGroup("AutoCompletion"); + opt.bACEnabled = m_pConf->readBoolEntry("Enabled"); + opt.nACMinChars = m_pConf->readUnsignedNumEntry("MinChars", + DEF_AC_MIN_CHARS); + opt.nACDelay = m_pConf->readUnsignedNumEntry("Delay", DEF_AC_DELAY); + opt.nACMaxEntries = m_pConf->readUnsignedNumEntry("MaxEntries", + DEF_AC_MAX_ENTRIES); +} + +/** + * Sets project options. + * @param opt A structure containing the new parameters to set + */ +void Project::setOptions(const Options& opt) +{ + // Write the options to the configuration nfile + writeOptions(m_pConf, opt); + + // Update project parameters + initOptions(); +} + +/** + */ +void Project::loadSession(Session& sess) +{ + QStringList slEntry; + + m_pConf->setGroup("Session"); + + // Read the list of open file locations + slEntry = m_pConf->readListEntry("OpenFiles"); + flListFromStringList(sess.fllOpenFiles, slEntry); + + // Get the path of the last viewed file + sess.sLastFile = m_pConf->readEntry("LastOpenFile"); + + // Read the lists of locked query files and call-tree/graph files + sess.slQueryFiles = m_pConf->readListEntry("QueryFiles"); + sess.slCallTreeFiles = m_pConf->readListEntry("CallTreeFiles"); + + // Read the list of bookmarks + slEntry = m_pConf->readListEntry("Bookmarks"); + flListFromStringList(sess.fllBookmarks, slEntry); + + // Read make-related information + sess.sMakeCmd = m_pConf->readEntry("MakeCommand", "make"); + sess.sMakeRoot = m_pConf->readEntry("MakeRoot", getSourceRoot()); + + // Cache make values + m_sMakeCmd = sess.sMakeCmd; + m_sMakeRoot = sess.sMakeRoot; +} + +/** + * Saves session-related information in the project's configuration file. + * @param sess Session parameters + */ +void Project::storeSession(const Session& sess) +{ + QStringList slEntry; + + m_pConf->setGroup("Session"); + + // Write the list of open file locations + stringListFromFlList(slEntry, sess.fllOpenFiles); + m_pConf->writeEntry("OpenFiles", slEntry); + + // Write the path of the last viewed file + m_pConf->writeEntry("LastOpenFile", sess.sLastFile); + + // Write the lists of locked query files and call-tree/graph files + m_pConf->writeEntry("QueryFiles", sess.slQueryFiles); + m_pConf->writeEntry("CallTreeFiles", sess.slCallTreeFiles); + + // Write the list of bookmarks + stringListFromFlList(slEntry, sess.fllBookmarks); + m_pConf->writeEntry("Bookmarks", slEntry); + + // Write make-related information + // Be careful not to write empty strings, as they may occur if the make + // dialogue was not invoked during this session + if (!sess.sMakeCmd.isEmpty()) + m_pConf->writeEntry("MakeCommand", sess.sMakeCmd); + if (!sess.sMakeRoot.isEmpty()) + m_pConf->writeEntry("MakeRoot", sess.sMakeRoot); +} + +/** + * Fills a list object with all files in the project. + * List items are created by reading and parsing all file name entries from + * the project's 'cscope.files' file. + * Note that the file may contain option lines, beginning with a dash. These + * should be ignored. + * @param pList Pointer to the object to fill + */ +bool Project::loadFileList(FileListTarget* pList) +{ + QString sFilePath; + + // Open the 'cscope.files' file + if (!m_fiFileList.open(IO_ReadOnly)) + return false; + + // Read all file names from the file + QTextStream str(&m_fiFileList); + while ((sFilePath = str.readLine()) != QString::null) { + // Skip option lines + if (sFilePath.at(0) == '-') + continue; + + // Set the new list item + pList->addItem(sFilePath); + } + + m_fiFileList.close(); + return true; +} + +/** + * Writes all file entries in a list view widget to the project's + * 'cscope.files' file (replacing current file contents.) + * @param pList Pointer to the object from which to take the new entries + */ +bool Project::storeFileList(FileListSource* pList) +{ + QString sFilePath; + + // Open the 'cscope.files' file + if (!m_fiFileList.open(IO_WriteOnly | IO_Truncate)) + return false; + + QTextStream str(&m_fiFileList); + + // Write all file names + if (pList->firstItem(sFilePath)) { + do { + str << sFilePath << "\n"; + } while (pList->nextItem(sFilePath)); + } + + m_fiFileList.close(); + return true; +} + +/** + * Adds a single file to the file list. + * @param sPath The path of the file to add + * @return true if successful, false otherwise + */ +bool Project::addFile(const QString& sPath) +{ + // Open the 'cscope.files' file + if (!m_fiFileList.open(IO_WriteOnly | IO_Append)) + return false; + + // Write the file path + QTextStream str(&m_fiFileList); + str << sPath << "\n"; + + m_fiFileList.close(); + return true; +} + +/** + * Determines whether the project includes any files. + * Reads the 'cscope.files' file and looks for any file names in it. If none + * is present, then the project is considered empty. + * Note that the file may contain option lines, beginning with a dash. These + * should be ignored. + * @return true if no files are included in the project, false otherwise + */ +bool Project::isEmpty() +{ + QString sPath, sFileName; + bool bResult = true; + + // Open the 'cscope.files' file + if (!m_fiFileList.open(IO_ReadOnly)) + return true; + + // Find at least one file name entry in the file + QTextStream str(&m_fiFileList); + while ((sPath = str.readLine()) != QString::null) { + if (sPath.at(0) != '-') { + bResult = false; + break; + } + } + + m_fiFileList.close(); + return bResult; +} + +/** + * Copies the list of previously queried symbols to the target object. + * @param slSymHistory The list object to copy into + */ +void Project::getSymHistory(QStringList& slSymHistory) const +{ + slSymHistory = m_slSymHistory; +} + +/** + * Copies the list of previously queried symbols from the target object. + * @param slSymHistory The list object to copy from + */ +void Project::setSymHistory(QStringList& slSymHistory) +{ + m_slSymHistory = slSymHistory; +} + +void Project::getMakeParams(QString& sCmd, QString& sDir) const +{ + sCmd = m_sMakeCmd; + sDir = m_sMakeRoot; +} + +/** + * Creates a project by writing a configuration file inside the given + * directory. + * @param sName The project's name + * @param sPath The full path of the project's directory + * @param opt Project options + */ +bool Project::create(const QString& sName, const QString& sPath, + const Options& opt) +{ + // Prepare the project's files + KConfig conf(sPath + "/cscope.proj"); + + // Write the configuration file version + conf.setGroup(""); + conf.writeEntry("Version", PROJECT_CONFIG_VER); + + // Write project properties in the configuration file + conf.setGroup("Project"); + conf.writeEntry("Name", sName); + writeOptions(&conf, opt); + + // Flush the config file data, so the project is created even if KScope + // crashes... + conf.sync(); + + return true; +} + +void Project::writeOptions(KConfig* pConf, const Options& opt) +{ + pConf->setGroup("Project"); + pConf->writeEntry("RootPath", opt.sSrcRootPath); + pConf->writeEntry("FileTypes", opt.slFileTypes.join(" ")); + pConf->writeEntry("Kernel", opt.bKernel); + pConf->writeEntry("InvIndex", opt.bInvIndex); + pConf->writeEntry("NoCompress", opt.bNoCompress); + pConf->writeEntry("SlowPathDef", opt.bSlowPathDef); + pConf->writeEntry("AutoRebuildTime", opt.nAutoRebuildTime); + pConf->writeEntry("TabWidth", opt.nTabWidth); + pConf->writeEntry("CtagsCommand", opt.sCtagsCmd); + + // Set auto-completion options + pConf->setGroup("AutoCompletion"); + pConf->writeEntry("Enabled", opt.bACEnabled); + pConf->writeEntry("MinChars", opt.nACMinChars); + pConf->writeEntry("Delay", opt.nACDelay); + pConf->writeEntry("MaxEntries", opt.nACMaxEntries); +} diff --git a/src/project.h b/src/project.h new file mode 100644 index 0000000..a2679b2 --- /dev/null +++ b/src/project.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PROJECT_H +#define PROJECT_H + +#include <projectbase.h> + +/** + * @author Elad Lahav + */ +class Project : public ProjectBase +{ +public: + Project(); + virtual ~Project(); + + struct Session { + FileLocationList fllOpenFiles; + QString sLastFile; + QStringList slQueryFiles; + QStringList slCallTreeFiles; + FileLocationList fllBookmarks; + QString sMakeCmd; + QString sMakeRoot; + }; + + virtual bool open(const QString&); + virtual bool loadFileList(FileListTarget*); + virtual bool storeFileList(FileListSource*); + virtual bool addFile(const QString&); + virtual bool isEmpty(); + virtual void close(); + + virtual QString getFileTypes() const; + virtual void getOptions(Options&) const; + virtual void setOptions(const Options&); + virtual void loadSession(Session&); + virtual void storeSession(const Session&); + virtual void getSymHistory(QStringList&) const; + virtual void setSymHistory(QStringList&); + virtual void getMakeParams(QString&, QString&) const; + + /** + * Determines whether a project is based on a Cscope.out file, and is + * therefore considered as a temporary project. + * @return true if this is a temporary project, false otherwise + */ + virtual bool isTemporary() { return false; } + + static bool create(const QString&, const QString&, const Options&); + +private: + /** The configuration file ("cscope.proj") */ + KConfig* m_pConf; + + /** The file that holds the paths of all source files in this project + ("cscope.files") */ + QFile m_fiFileList; + + QString m_sMakeCmd; + + QString m_sMakeRoot; + + static void writeOptions(KConfig*, const Options&); +}; + +#endif diff --git a/src/projectbase.cpp b/src/projectbase.cpp new file mode 100644 index 0000000..f99c045 --- /dev/null +++ b/src/projectbase.cpp @@ -0,0 +1,190 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "projectbase.h" +#include "kscopeconfig.h" +#include "cscopefrontend.h" + +ProjectBase::ProjectBase() +{ +} + +ProjectBase::~ProjectBase() +{ +} + +bool ProjectBase::open(const QString& sPath) +{ + QFileInfo fi(sPath); + + // Make sure the file exists, and that is is a cross-reference file + if (!fi.exists() || !isCscopeOut(fi.absFilePath())) + return false; + + // Set the project's directory + m_dir = fi.dirPath(true); + + // Set the name of the project to be the full path of the file + m_sName = fi.absFilePath(); + + // Initialise project options (assume source root is the folder holding the + // cscope.out file) + getDefOptions(m_opt); + m_opt.sSrcRootPath = m_dir.absPath(); + + return true; +} + +/** + * Determines if the cscope.out file for this project exists. + * @return true if the database exists, false otherwise + */ +bool ProjectBase::dbExists() +{ + return m_dir.exists("cscope.out"); +} + +void ProjectBase::getOptions(Options& opt) const +{ + getDefOptions(opt); +} + +void ProjectBase::getMakeParams(QString& sCmd, QString& sDir) const +{ + sCmd = "make"; + sDir = getSourceRoot(); +} + +/** + * Fills a structure with default properties for a new project. + * Default properties are partly based on the system profile. + * @param opt The structure to fill + */ +void ProjectBase::getDefOptions(Options& opt) +{ + // Set default source path to file-system root + opt.sSrcRootPath = "/"; + + // Initialise MIME-type list + opt.slFileTypes.append("*.c"); + opt.slFileTypes.append("*.h"); + + // Set other options + opt.bKernel = DEF_IS_KERNEL; + opt.bInvIndex = DEF_INV_INDEX; + opt.bNoCompress = DEF_NO_COMPRESS; + opt.bSlowPathDef = DEF_SLOW_PATH; + opt.nACMinChars = DEF_AC_MIN_CHARS; + opt.nACDelay = DEF_AC_DELAY; + opt.nACMaxEntries = DEF_AC_MAX_ENTRIES; + opt.nTabWidth = DEF_TAB_WIDTH; + + // Set profile-dependant options + if (Config().getSysProfile() == KScopeConfig::Fast) { + opt.nAutoRebuildTime = 10; + opt.bACEnabled = true; + } + else { + opt.nAutoRebuildTime = -1; + opt.bACEnabled = false; + } +} + +void ProjectBase::initOptions() +{ + // Load the options + getOptions(m_opt); + + // Create the argument list for invoking Cscope + m_nArgs = 0; + if (m_opt.bKernel) + m_nArgs |= CscopeFrontend::Kernel; + if (m_opt.bInvIndex) + m_nArgs |= CscopeFrontend::InvIndex; + if (m_opt.bNoCompress) + m_nArgs |= CscopeFrontend::NoCompression; + if (m_opt.bSlowPathDef) + m_nArgs |= CscopeFrontend::SlowPathDef; +} + +/** + * Determines if the given file is a Cscope cross-reference database. + * @param sPath The full path of the file to check + * @return true if the given file is a cscope.out file, false otherwise + */ +bool ProjectBase::isCscopeOut(const QString& sPath) +{ + QFile file(sPath); + QString sLine; + int nVer; + char szDir[PATH_MAX]; + + // Try to open the file + if (!file.open(IO_ReadOnly)) + return false; + + // Check if the first line matches the expected format + sLine = QTextStream(&file).readLine(); + return sscanf(sLine.latin1(), "cscope %d %s", &nVer, szDir) == 2; +} + +/** + * Fills a list object with all files in the project. + * List items are created by reading and parsing all file name entries from + * the project's 'cscope.files' file. + * Note that the file may contain option lines, beginning with a dash. These + * should be ignored. + * @param pList Pointer to the object to fill + */ +bool ProjectBase::loadFileList(FileListTarget* pList) +{ + QString sFilePath; + QFile file; + + // Make sure the file exists + if (!m_dir.exists("cscope.files")) + return false; + + // Open the file + file.setName(m_dir.absPath() + "/cscope.files"); + if (!file.open(IO_ReadOnly)) + return false; + + // Read all file names from the file + QTextStream str(&file); + while ((sFilePath = str.readLine()) != QString::null) { + // Skip option lines + if (sFilePath.at(0) == '-') + continue; + + // Set the new list item + pList->addItem(sFilePath); + } + + file.close(); + return true; +} diff --git a/src/projectbase.h b/src/projectbase.h new file mode 100644 index 0000000..4170652 --- /dev/null +++ b/src/projectbase.h @@ -0,0 +1,281 @@ +/*************************************************************************** + * + * Copyright (C) 2007 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PROJECTBASE_H +#define PROJECTBASE_H + +#include <qstringlist.h> +#include <qdir.h> +#include <qfile.h> +#include <kconfig.h> + +#define DEF_IS_KERNEL false +#define DEF_INV_INDEX true +#define DEF_NO_COMPRESS false +#define DEF_SLOW_PATH false +#define DEF_AC_MIN_CHARS 3 +#define DEF_AC_DELAY 500 +#define DEF_AC_MAX_ENTRIES 100 +#define DEF_TAB_WIDTH 0 /* Use editor's default */ +#define DEF_CTAGS_COMMAND \ + "--regex-c=\"/^[ \\t]*([_a-zA-Z][_a-zA-Z0-9]*):/\\1/l,label/\" " \ + "--regex-c=\"/^[ \\t]*#[ \\t]*include[ \\t]*[\\\"<]" \ + "([_a-zA-Z0-9\\.\\/]*)[\\\">]/\\1/i,include/\" " \ + "--regex-c++=\"/^[ \\t]*#[ \\t]*include[ \\t]*[\\\"<]" \ + "([_a-zA-Z0-9\\.\\/]*)[\\\">]/\\1/i,include/\"" + +/** + * Abstract base class for classes that need the list of project files. + * Objects of classes derived from this one are used as a parameter to + * ProjectManager::fillList(), which reads all file entries in the project, + * and calls addItem() for each. + * Any class that wishes to retrieve the project's file list, should inherit + * from this class, and implement addItem(). + * @author Elad Lahav + */ + +class FileListTarget +{ +public: + /** + * Class constructor. + */ + FileListTarget() {} + + /** + * Class destructor. + */ + virtual ~FileListTarget() {} + + /** + * Appends a file to the list. + * @param sFilePath The full path of the file to add + */ + virtual void addItem(const QString& sFilePath) = 0; +}; + +/** + * Abstract base class for classes that need the list of project files. + * Objects of classes derived from this one are used as a parameter to + * ProjectManager::writeList(), which calls getFirstItem() and getNextItem(), + * and writes the returned values to the project's 'cscope.files' file. + * Any class that wishes to retrieve the project's file list, should inherit + * from this class, and implement firstItem() and nextItem(). + * @author Elad Lahav + */ + +class FileListSource +{ +public: + /** + * Class constructor. + */ + FileListSource() {} + + /** + * Class destructor. + */ + virtual ~FileListSource() {} + + /** + * Returns the first file in the list, and initiates a new iteration. + * @param sFilePath Holds the path of the first file, upon return + * @return true if there are more files, false otherwise + */ + virtual bool firstItem(QString& sFilePath) = 0; + + /** + * Returns the next file in the list. + * @param sFilePath Holds the path of the file, upon return + * @return true if there are more files, false otherwise + */ + virtual bool nextItem(QString& sFilePath) = 0; +}; + +/** + * Defines a cursor location inside a file. + * This structure is used to store project session information. + * @author Elad Lahav + */ +struct FileLocation +{ + /** + * Struct constructor. + * @param sPath The full path of the file + * @param nLine The line position of the cursor + * @param nCol The column position of the cursor + */ + FileLocation(QString sPath, uint nLine, uint nCol) : m_sPath(sPath), + m_nLine(nLine), m_nCol(nCol) {} + + /** The full path of the file. */ + QString m_sPath; + + /** The line position of the cursor. */ + uint m_nLine; + + /** The column position of the cursor. */ + uint m_nCol; +}; + +/** + * A list of file locations used for restoring a session. + */ +typedef QPtrList<FileLocation> FileLocationList; + +class FileSemaphore; + +/** + * @author Elad Lahav + */ +class ProjectBase +{ +public: + ProjectBase(); + virtual ~ProjectBase(); + + /** + * Configurable project options. + */ + struct Options { + QString sSrcRootPath; + + /** A list of MIME-types that determines which files are included in + the project. */ + QStringList slFileTypes; + + /** true if the -k option for CScope should be used. */ + bool bKernel; + + /** true if Cscope should build an inverted index. */ + bool bInvIndex; + + /** true if the -c option for CScope should be used. */ + bool bNoCompress; + + /** true if the -D option for CScope should be used. */ + bool bSlowPathDef; + + /** The time, in milliseconds, after which the database should be + automatically rebuilt (-1 if this option is disabled). */ + int nAutoRebuildTime; + + /** true to use auto-completion. */ + bool bACEnabled; + + /** Minimum number of characters in a symbol for auto-completion. */ + uint nACMinChars; + + /** Time interval, in milliseconds, before auto-completion is + started. */ + uint nACDelay; + + /** Maximal number of entries for auto-completion. */ + uint nACMaxEntries; + + /** Per-project tab width (overrides editor settings). */ + uint nTabWidth; + + /** Ctags command line. */ + QString sCtagsCmd; + }; + + virtual bool open(const QString&); + virtual bool loadFileList(FileListTarget*); + virtual bool storeFileList(FileListSource*) { return false; } + virtual bool isEmpty() { return false; } + bool dbExists(); + virtual void close() {} + + virtual QString getFileTypes() const { return QString::null; } + virtual void getOptions(Options&) const; + virtual void setOptions(const Options&) {} + virtual void getSymHistory(QStringList&) const {} + virtual void setSymHistory(QStringList&) {} + virtual void getMakeParams(QString&, QString&) const; + + /** + * Determines whether a project is based on a Cscope.out file, and is + * therefore considered as a temporary project. + * @return true if this is a temporary project, false otherwise + */ + virtual bool isTemporary() { return true; } + + /** + * @return The name of the current project + */ + QString getName() const { return m_sName; } + + /** + * @return The full path of the project's directory + */ + QString getPath() const { return m_dir.absPath(); } + + /** + * @return Command-line arguments to pass to a Cscope object, based on + * project's options + */ + uint getArgs() const { return m_nArgs; } + + const QString& getSourceRoot() const { return m_opt.sSrcRootPath; } + + /** + * @return The time, in seconds, to wait before rebuilding the + * cross-refernce database. + */ + int getAutoRebuildTime() const { return m_opt.nAutoRebuildTime; } + + /** + * @return The tab width to use (0 to use the editor's default) + */ + uint getTabWidth() const { return m_opt.nTabWidth; } + + static void getDefOptions(Options&); + +protected: + /** The name of the project, as written in the configuration file */ + QString m_sName; + + /** The directory associated with the project */ + QDir m_dir; + + /** A cached version of the project's options. */ + Options m_opt; + + /** A list of Cscope command-line arguments based on the project's + options. */ + uint m_nArgs; + + /** A list of symbols previously queried. */ + QStringList m_slSymHistory; + + void initOptions(); + + static bool isCscopeOut(const QString&); +}; + +#endif diff --git a/src/projectfilesdlg.cpp b/src/projectfilesdlg.cpp new file mode 100644 index 0000000..de84417 --- /dev/null +++ b/src/projectfilesdlg.cpp @@ -0,0 +1,439 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qpushbutton.h> +#include <qlistview.h> +#include <qlineedit.h> +#include <qregexp.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include "projectfilesdlg.h" +#include "dirscanner.h" +#include "scanprogressdlg.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pProjMgr Pointer the KScope's project manager object + * @param pParent The parent widget + * @param szName The widget's name + */ +ProjectFilesDlg::ProjectFilesDlg(Project* pProj, QWidget* pParent, + const char* szName) : + ProjectFilesLayout(pParent, szName), + m_pProj(pProj), + m_pScanDlg(NULL), + m_pItrItem(NULL), + m_pLastItem(NULL) +{ + // Create the scanner object + m_pScanner = new DirScanner(this, &m_dicFiles); + + // Initialise the list view + m_pFileList->setSelectionMode(QListView::Extended); + m_pFileList->addColumn("File Path"); + + // Sort only when asked to by the user + if (Config().getAutoSortFiles()) + m_pFileList->setSortColumn(0); + else + m_pFileList->setSortColumn(m_pFileList->columns() + 1); + + // Add file/directory/tree when the appropriate button is clicked + connect(m_pAddFilesButton, SIGNAL(clicked()), this, + SLOT(slotAddFiles())); + connect(m_pAddDirButton, SIGNAL(clicked()), this, SLOT(slotAddDir())); + connect(m_pAddTreeButton, SIGNAL(clicked()), this, SLOT(slotAddTree())); + + // Remove selected files/directory/tree when the appropriate button is + // clicked + connect(m_pRemSelButton, SIGNAL(clicked()), this, SLOT(slotRemSel())); + connect(m_pRemDirButton, SIGNAL(clicked()), this, SLOT(slotRemDir())); + connect(m_pRemTreeButton, SIGNAL(clicked()), this, SLOT(slotRemTree())); + + // Hide/show files according to filter + connect(m_pFilterButton, SIGNAL(clicked()), this, SLOT(slotFilter())); + connect(m_pShowAllButton, SIGNAL(clicked()), this, SLOT(slotShowAll())); + + // Close the dialog when OK/Cancel are clicked + connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + // Fill the list with the project's files + m_pFileList->setUpdatesEnabled(false); + m_pProj->loadFileList(this); + m_pFileList->setUpdatesEnabled(true); + m_pFileList->triggerUpdate(); +} + +/** + * Class destructor. + */ +ProjectFilesDlg::~ProjectFilesDlg() +{ + delete m_pScanner; +} + +/** + * Adds a single entry to the file list. + * Implements the addItem() virtual method of the FileListTarget base + * class. When a ProjectFilesDlg object is given as a parameter to + * ProjectManager::fillList(), this method is called for each file included + * in the project. A new list item is created, containing the file's path, + * and is added to the list. + * @param sFilePath The full path of a source file + */ +void ProjectFilesDlg::addItem(const QString& sFilePath) +{ + QListViewItem* pItem; + + pItem = new QListViewItem(m_pFileList, m_pLastItem); + pItem->setText(0, sFilePath); + m_pLastItem = pItem; + m_dicFiles.insert(sFilePath, pItem); +} + +/** + * Retrieves the first file path in the list. + * Imlpements the firstItem() virtual method of the FileListSource base + * class. + * @param sFilePath Contains the file path, upon successful return + * @return bool true if successful, false if the list is empty + */ +bool ProjectFilesDlg::firstItem(QString& sFilePath) +{ + m_pItrItem = m_pFileList->firstChild(); + return nextItem(sFilePath); +} + +/** + * Retrieves the next file path in the list. + * Imlpements the nextItem() virtual method of the FileListSource base + * class. The function requires that firstItem() will be called to begin an + * iteration through the file paths. + * @param sFilePath Contains the file path, upon successful return + * @return bool true if successful, false if no more items are + * available + */ +bool ProjectFilesDlg::nextItem(QString& sFilePath) +{ + if (m_pItrItem == NULL) + return false; + + sFilePath = m_pItrItem->text(0); + m_pItrItem = m_pItrItem->nextSibling(); + return true; +} + +/** + * Notifies the user on the progress of a directory scan (when adding a new + * directory), and, if finished, allows the user to add these files to the + * project. + * @param pEvent The event object + */ +void ProjectFilesDlg::customEvent(QCustomEvent* pEvent) +{ + DirScanEvent* pDSE; + QString sMsg; + + // Process only directory scan progress events + if (((uint)pEvent->type()) != DirScanEvent::EventId) + return; + + pDSE = (DirScanEvent*)pEvent; + + // Check if the scan has terminated + if (!pDSE->m_bFinished) { + // Create the scan progress dialog, if required + if (m_pScanDlg == NULL) { + m_pScanDlg = new ScanProgressDlg(this); + connect(m_pScanDlg, SIGNAL(cancelled()), this, + SLOT(slotCancelDirScan())); + } + + // Set progress indication + m_pScanDlg->addFiles(pDSE->m_nFiles); + return; + } + + // Destroy the scan progress dialog + delete m_pScanDlg; + m_pScanDlg = NULL; + + // Verify the thread has terminated + m_pScanner->wait(500); + if (!m_pScanner->finished()) + m_pScanner->terminate(); + + // Do nothing if the operation was cancelled + if (m_pScanner->wasCancelled()) + return; + + // Abort if no files were found + if (pDSE->m_nFiles == 0) { + KMessageBox::sorry(0, "No files were found"); + return; + } + + // Prompt the user for the files to add + sMsg.sprintf(i18n("Would you like to add %d files to your project?"), + pDSE->m_nFiles); + if (KMessageBox::questionYesNo(0, sMsg) == KMessageBox::No) + return; + + // Add the files to the list + const QStringList& slFiles = m_pScanner->getFiles(); + QStringList::const_iterator itr; + + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) + addItem(*itr); +} + +/** + * Removes a single item from the file list. + */ +void ProjectFilesDlg::removeItem(QListViewItem* pItem) +{ + m_dicFiles.remove(pItem->text(0)); + delete pItem; +} + +/** + * Adds a list of files to the project. + * Prompts the user for source files, and adds the selected files to the + * current project. + */ +void ProjectFilesDlg::slotAddFiles() +{ + QStringList slFiles; + QStringList::const_iterator itr; + + // Prompt the user + slFiles = KFileDialog::getOpenFileNames(m_pProj->getSourceRoot(), + m_pProj->getFileTypes()); + + // Add the selected files, skipping existing entries + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) { + if (m_dicFiles.find(*itr) == NULL) + addItem(*itr); + } +} + +/** + * Adds all source files in a given directory to the project. + * Prompts the user for a directory, and adds all files matching the + * project's pattern to the current project. + * Note that only source files in the selected directory are added, i.e., the + * search does not descend to sub-directories. + */ +void ProjectFilesDlg::slotAddDir() +{ + QString sDir; + QStringList slFiles; + QStringList::const_iterator itr; + + // Prompt the user for a directory + sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot()); + if (sDir.isEmpty()) + return; + + // Search for source files in this directory + m_pScanner->start(sDir, m_pProj->getFileTypes(), false); +} + +/** + * Adds all source files in a given file system tree to the project. + * Prompts the user for a directory, and adds all files matching the + * project's pattern to the current project. + * Note that source files are searched for in the given directory, as well as + * in any of its sub-directories. + */ +void ProjectFilesDlg::slotAddTree() +{ + QString sDir; + QStringList slFiles; + QStringList::const_iterator itr; + + // Prompt the user for a directory + sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot()); + if (sDir.isEmpty()) + return; + + // Search for source files in this directory + m_pScanner->start(sDir, m_pProj->getFileTypes(), true); +} + +/** + * Removes the selected files from the project. + */ +void ProjectFilesDlg::slotRemSel() +{ + QListViewItem* pItem, * pPrevItem; + + // Prompt the user before removing the files + if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove " + "the selected files from the project?")) == KMessageBox::No) { + return; + } + + // Remove the selected files + pItem = m_pFileList->firstChild(); + while (pItem != NULL) { + pPrevItem = pItem; + pItem = pItem->nextSibling(); + + if (pPrevItem->isSelected()) + removeItem(pPrevItem); + } +} + +/** + * Removes all source files in a directory from the project. + */ +void ProjectFilesDlg::slotRemDir() +{ + QString sDir, sFilePath; + QListViewItem* pItem, * pPrevItem; + + // Prompt the user for a directory + sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot()); + if (sDir.isEmpty()) + return; + + // Confirm the directory removal + if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove " + "the selected directory from the project?")) == KMessageBox::No) { + return; + } + + // Remove the files under the selected directory + pItem = m_pFileList->firstChild(); + while (pItem != NULL) { + pPrevItem = pItem; + pItem = pItem->nextSibling(); + + // Check if the file is under the selected directory + sFilePath = pPrevItem->text(0); + if (sFilePath.left(sFilePath.findRev('/') + 1) == sDir) + removeItem(pPrevItem); + } +} + +/** + * Removes all source files in a directory or any of its sub-directories from + * the project. + */ +void ProjectFilesDlg::slotRemTree() +{ + QString sDir, sFilePath; + QListViewItem* pItem, * pPrevItem; + + // Prompt the user for a directory + sDir = KFileDialog::getExistingDirectory(m_pProj->getSourceRoot()); + if (sDir.isEmpty()) + return; + + // Confirm the directory removal + if (KMessageBox::questionYesNo(0, i18n("Are you sure you want to remove " + "all files in the selected tree from the project?")) == + KMessageBox::No) { + return; + } + + // Remove the files under the selected directory + pItem = m_pFileList->firstChild(); + while (pItem != NULL) { + pPrevItem = pItem; + pItem = pItem->nextSibling(); + + // Check if the file is under the selected directory + sFilePath = pPrevItem->text(0); + if (sFilePath.startsWith(sDir)) + removeItem(pPrevItem); + } +} + +/** + * Filter files according to a pattern. + * Hides all entries in the file list, except for those that match a given + * pattern. + */ +void ProjectFilesDlg::slotFilter() +{ + QString sFilter; + QListViewItem* pItem; + + // Get the user's filter string + sFilter = m_pFilterEdit->text().stripWhiteSpace(); + if (sFilter.isEmpty()) + return; + + // Create the regular expression + QRegExp reFilter(sFilter); + reFilter.setWildcard(true); + + // Iterate over the list entries, and hide all items not matching the + // filter string + pItem = m_pFileList->firstChild(); + while (pItem != NULL) { + if (reFilter.search(pItem->text(0)) == -1) { + pItem->setVisible(false); + pItem->setSelectable(false); + } + + pItem = pItem->nextSibling(); + } +} + +/** + * Shows all entries in the file list, after a filter has been applied. + */ +void ProjectFilesDlg::slotShowAll() +{ + QListViewItem* pItem; + + // Iterate over the list entries, and make all items visible + pItem = m_pFileList->firstChild(); + while (pItem != NULL) { + pItem->setVisible(true); + pItem->setSelectable(true); + pItem = pItem->nextSibling(); + } +} + +/** + * Stops a directory scan process. + * This slot is called when the user clicks on the "Cancel" button in the + * scan progress dialog. + */ +void ProjectFilesDlg::slotCancelDirScan() +{ + m_pScanner->cancel(); +} + +#include "projectfilesdlg.moc" diff --git a/src/projectfilesdlg.h b/src/projectfilesdlg.h new file mode 100644 index 0000000..9c6d791 --- /dev/null +++ b/src/projectfilesdlg.h @@ -0,0 +1,104 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PROJECTFILESDLG_H +#define PROJECTFILESDLG_H + +#include <qwidget.h> +#include <projectfileslayout.h> +#include <qdict.h> +#include "project.h" + +class DirScanner; +class ScanProgressDlg; + +/** + * A dialog to manipulate the project's files. + * The dialog allows the user to add source files to the current project, or + * remove files from it. The main widget of the dialog is a list view, that + * displays all files currently in the project. When files are added or + * removed, this list view is updated. The project, however, is only modified + * if the user closes the dialog using the "OK" button. + * Since searches through a list view are very slow, the class also maintains + * a QDict object, that connects file names with their respective list items. + * This dictionary is used to ensure duplicated items are not added to the + * list. + * @author Elad Lahav + */ + +class ProjectFilesDlg : public ProjectFilesLayout, public FileListTarget, + public FileListSource +{ + Q_OBJECT + +public: + ProjectFilesDlg(Project*, QWidget* pParent = 0, const char* szName = 0); + ~ProjectFilesDlg(); + + virtual void addItem(const QString&); + virtual bool firstItem(QString&); + virtual bool nextItem(QString&); + +protected: + virtual void customEvent(QCustomEvent*); + +private: + /** The project to manipulate. */ + Project* m_pProj; + + /** Holds all file paths in a quickly searchable format (for duplicate + entries lookup). */ + QDict<QListViewItem> m_dicFiles; + + /** A thread object to a-synchronously scan directories for source files + to add to the project. */ + DirScanner* m_pScanner; + + /** Displays the progress of a directory scan operation. */ + ScanProgressDlg* m_pScanDlg; + + /** A file list item that serves as an iterator. */ + QListViewItem* m_pItrItem; + + /** The last item added. */ + QListViewItem* m_pLastItem; + + void removeItem(QListViewItem*); + +private slots: + void slotAddFiles(); + void slotAddDir(); + void slotAddTree(); + void slotRemSel(); + void slotRemDir(); + void slotRemTree(); + void slotFilter(); + void slotShowAll(); + void slotCancelDirScan(); +}; + +#endif diff --git a/src/projectfileslayout.ui b/src/projectfileslayout.ui new file mode 100644 index 0000000..a78af7e --- /dev/null +++ b/src/projectfileslayout.ui @@ -0,0 +1,201 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>ProjectFilesLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ProjectFilesLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>585</width> + <height>480</height> + </rect> + </property> + <property name="caption"> + <string>Project Files</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_pFilterEdit</cstring> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pFilterButton</cstring> + </property> + <property name="text"> + <string>Filter</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pShowAllButton</cstring> + </property> + <property name="text"> + <string>Show All</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QListView"> + <property name="name"> + <cstring>m_pFileList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Add</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pAddFilesButton</cstring> + </property> + <property name="text"> + <string>Files...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pAddDirButton</cstring> + </property> + <property name="text"> + <string>Directory...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pAddTreeButton</cstring> + </property> + <property name="text"> + <string>Tree...</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>Remove</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pRemSelButton</cstring> + </property> + <property name="text"> + <string>Selected</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pRemDirButton</cstring> + </property> + <property name="text"> + <string>Directory...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pRemTreeButton</cstring> + </property> + <property name="text"> + <string>Tree...</string> + </property> + </widget> + </vbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>118</height> + </size> + </property> + </spacer> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pOKButton</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </vbox> + </widget> + </vbox> + </widget> + </hbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/projectmanager.cpp b/src/projectmanager.cpp new file mode 100644 index 0000000..998b4a5 --- /dev/null +++ b/src/projectmanager.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <kmessagebox.h> +#include <klocale.h> +#include "projectmanager.h" +#include "project.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + */ +ProjectManager::ProjectManager() : m_pCurProj(NULL) +{ +} + +/** + * Class destructor. + */ +ProjectManager::~ProjectManager() +{ + close(); +} + +/** + * Creates a project's directory, and associates this directory with the + * current object. This directory is created under the given path, and using + * the project's name (which, thus, has to be a legal file name). + * Note: this function attempts to create a new directory, so the given path + * and name must not lead to an existing one. + * @param sName The project's name + * @param sPath The parent directory under which to create the + * project's directory + * @param opt A structure containing project options + * @return true if successful, false otherwise + */ +bool ProjectManager::create(const QString& sName, const QString& sPath, + const ProjectBase::Options& opt, QString& sProjDir) +{ + QDir dir(sPath); + QString sParentPath; + QString sDirName = sName; + QString sMsg; + + // Handle requests for a hidden .cscope directory + if (dir.dirName() == ".cscope") { + sParentPath = QDir::cleanDirPath(dir.absPath()); + sParentPath = sParentPath.section('/', 0, -2); + dir.cd(sParentPath); + sDirName = ".cscope"; + } + + // The parent directory must exist + if (!dir.exists()) { + sMsg = i18n("The requested parent directory (%1) does not exist"). + arg(sParentPath); + KMessageBox::error(0, sMsg); + return false; + } + + // Make sure the directory doesn't exist + if (dir.exists(sDirName)) { + sMsg = i18n("Cannot create a project inside an existing directory " + "(%1/%2)").arg(dir.canonicalPath()).arg(sDirName); + KMessageBox::error(0, sMsg); + return false; + } + + // Try to create the projcet's directory + if (!dir.mkdir(sDirName, false) || !dir.cd(sDirName, false)) { + sMsg = i18n("Failed to create the project directory (%1/%2)"). + arg(dir.canonicalPath()).arg(sDirName); + KMessageBox::error(0, sMsg); + return false; + } + + if (!Project::create(sName, dir.absPath(), opt)) + return false; + + sProjDir = dir.path(); + return true; +} + +/** + * Opens a project and makes it the current one. + * @param sPath The directory containing the project's files + * @return true if successful, false otherwise + */ +bool ProjectManager::open(const QString& sPath) +{ + Project* pProj; + + // Close the current project + close(); + + // Try to open the new project + pProj = new Project(); + if (!pProj->open(sPath)) { + delete pProj; + return false; + } + + // Add to the list of recently opened projects + Config().addRecentProject(sPath); + + // Project opened successfully + m_pCurProj = pProj; + return true; +} + +/** + * Opens a Cscope.out file as a temporary project. + * @param sFilePath The full path of the Cscope.out file + * @return true if successful, false otherwise + */ +bool ProjectManager::openCscopeOut(const QString& sFilePath) +{ + ProjectBase* pProj; + + // Close the current project + close(); + + // Try to open the new project + pProj = new ProjectBase(); + if (!pProj->open(sFilePath)) { + delete pProj; + return false; + } + + // Add to the list of recently opened projects + Config().addRecentProject(sFilePath); + + // Project opened successfully + m_pCurProj = pProj; + return true; +} + +/** + * Performs clean-up on the project's variables, and detaches the associated + * directory. + */ +void ProjectManager::close() +{ + if (m_pCurProj) { + delete m_pCurProj; + m_pCurProj = NULL; + } +} + +QString ProjectManager::getProjName() const +{ + if (!m_pCurProj) + return i18n("No Project"); + + return m_pCurProj->getName(); +} diff --git a/src/projectmanager.h b/src/projectmanager.h new file mode 100644 index 0000000..c78a2c9 --- /dev/null +++ b/src/projectmanager.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef PROJECTMANAGER_H +#define PROJECTMANAGER_H + +#include "projectbase.h" + +/** + * @author Elad Lahav + */ +class ProjectManager : public QObject +{ +public: + ProjectManager(); + virtual ~ProjectManager(); + + bool create(const QString&, const QString&, const ProjectBase::Options&, + QString&); + bool open(const QString&); + bool openCscopeOut(const QString&); + void close(); + QString getProjName() const; + + ProjectBase* curProject() const { return m_pCurProj; } + +private: + /** The current project (NULL if no project is open). */ + ProjectBase* m_pCurProj; +}; + +#endif diff --git a/src/query_locked.png b/src/query_locked.png Binary files differnew file mode 100644 index 0000000..25db6b2 --- /dev/null +++ b/src/query_locked.png diff --git a/src/query_unlocked.png b/src/query_unlocked.png Binary files differnew file mode 100644 index 0000000..3a1a0d3 --- /dev/null +++ b/src/query_unlocked.png diff --git a/src/querypage.cpp b/src/querypage.cpp new file mode 100644 index 0000000..502747b --- /dev/null +++ b/src/querypage.cpp @@ -0,0 +1,211 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfile.h> +#include <klocale.h> +#include "querypage.h" +#include "queryview.h" +#include "queryviewdriver.h" + +const char* QUERY_TYPES[][2] = { + { "References to ", "REF " }, + { "Definition of ", "DEF " }, + { "Functions called by ", "<-- " }, + { "Functions calling ", "-->" }, + { "Search for ", "TXT " }, + { "", "" }, + { "EGrep Search for ", "GRP " }, + { "Files named ", "FIL " }, + { "Files #including ", "INC " }, + { "Query", "Query" } +}; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +QueryPage::QueryPage(QWidget* pParent, const char * szName) : + QueryPageBase(pParent, szName), + m_nType(CscopeFrontend::None) +{ + m_pView = new QueryView(this); + m_pDriver = new QueryViewDriver(m_pView, this); + + connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this, + SIGNAL(lineRequested(const QString&, uint))); + + // Set colours and font + applyPrefs(); +} + +/** + * Class destructor. + */ +QueryPage::~QueryPage() +{ +} + +/** + * Runs a query, using the current page to display the results. + * @param nType The type of the query + * @param sText The text of the query + * @param bCase true for case-sensitive queries, false otherwise + */ +void QueryPage::query(uint nType, const QString& sText, bool bCase) +{ + m_nType = nType; + m_sText = sText; + m_bCase = bCase; + m_sName = getCaption(); + + m_pDriver->query(nType, sText, bCase); +} + +/** + * Re-runs the last query. + */ +void QueryPage::refresh() +{ + m_pView->clear(); + if (!m_sText.isEmpty()) + m_pDriver->query(m_nType, m_sText, m_bCase); +} + +/** + * Resets the query page by deleting all records. + */ +void QueryPage::clear() +{ + m_pView->clear(); + m_nType = CscopeFrontend::None; + m_sText = QString(); + m_sName = QString(); +} + +/** + * @return true if a query is currently running in this page, false otherwise + */ +bool QueryPage::isRunning() +{ + return m_pDriver->isRunning(); +} + +/** + * Constructs a caption for this page, based on the query's type and text. + * @param bBrief true to use a shortened version of the caption, false + * (default) for the full version + * @return The caption for this page + */ +QString QueryPage::getCaption(bool bBrief) const +{ + return QString(QUERY_TYPES[m_nType][bBrief ? 1 : 0] + m_sText); +} + +/** + * Creates a new query result item. + * @param sFile The file name + * @param sFunc The function defining the scope of the result + * @param sLine The line number + * @param sText The contents of the line + */ +void QueryPage::addRecord(const QString& sFile, const QString& sFunc, + const QString& sLine, const QString& sText) +{ + new QListViewItem(m_pView, sFile, sFunc, sLine, sText); +} + +/** + * Creates a unique file name for saving the contents of the query page. + * @param sProjPath The full path of the project directory + * @return The unique file name to use + */ +QString QueryPage::getFileName(const QString& sProjPath) const +{ + QString sFileName, sFileNameBase; + int i = 0; + + // Do nothing if not initialised + if (m_sName.isEmpty()) + return ""; + + // Create a unique file name + sFileNameBase = m_sName; + sFileNameBase.replace(' ', '_'); + do { + sFileName = sFileNameBase + QString::number(++i); + } while (QFile(sProjPath + "/" + sFileName).exists()); + + return sFileName; +} + +/** + * Reads query parameters from a file. + * This mehtod is used as part of the loading process. + * @param str A text stream set to the correct place in the file + * @return true if successful, false otherwise + */ +bool QueryPage::readHeader(QTextStream& str) +{ + QString sTemp; + + // Read the query name + m_sName = str.readLine(); + if (m_sName == QString::null || m_sName.isEmpty()) + return false; + + // Read the query's type + sTemp = str.readLine(); + if (sTemp == QString::null || sTemp.isEmpty()) + return false; + + // Convert the type string to an integer + m_nType = sTemp.toUInt(); + if (m_nType >= CscopeFrontend::None) { + m_nType = CscopeFrontend::None; + return false; + } + + // Read the query's text + m_sText = str.readLine(); + if (m_sText == QString::null || m_sText.isEmpty()) + return false; + + return true; +} + +/** + * Writes query parameters to a file. + * This mehtod is used as part of the storing process. + * @param str A text stream set to the correct place in the file + */ +void QueryPage::writeHeader(QTextStream& str) +{ + str << m_sName << "\n" << m_nType << "\n" << m_sText << "\n"; +} + +#include "querypage.moc" diff --git a/src/querypage.h b/src/querypage.h new file mode 100644 index 0000000..59d6ea2 --- /dev/null +++ b/src/querypage.h @@ -0,0 +1,86 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYPAGE_H +#define QUERYPAGE_H + +#include <qwidget.h> +#include <qlistview.h> +#include <qregexp.h> +#include "querypagebase.h" +#include "cscopefrontend.h" + +class QueryViewDriver; + +/** + * A QueryWidget page that runs and displays Cscope queries. + * The page uses a QueryViewDriver object to run queries, and an embedded + * QueryView widget for displaying query results. + * @author Elad Lahav + */ +class QueryPage : public QueryPageBase +{ + Q_OBJECT + +public: + QueryPage(QWidget* pParent = 0, const char* szName = 0); + ~QueryPage(); + + void query(uint, const QString&, bool); + void refresh(); + void clear(); + bool isRunning(); + + virtual QString getCaption(bool bBrief = false) const; + +protected: + virtual void addRecord(const QString&, const QString&, const QString&, + const QString&); + virtual QString getFileName(const QString&) const; + virtual bool readHeader(QTextStream&); + virtual void writeHeader(QTextStream&); + +private: + /** The type of query whose results are listed on this page. */ + uint m_nType; + + /** The text given as a parameter to the query. */ + QString m_sText; + + /** Whether the query is case-sensitive. */ + bool m_bCase; + + /** A formatted caption for this query, including the type of query and + its text. */ + QString m_sName; + +private: + /** Runs Cscope queries whose results are displayed in this page. */ + QueryViewDriver* m_pDriver; +}; + +#endif diff --git a/src/querypagebase.cpp b/src/querypagebase.cpp new file mode 100644 index 0000000..08cbe6d --- /dev/null +++ b/src/querypagebase.cpp @@ -0,0 +1,194 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qfile.h> +#include "querypagebase.h" +#include "queryview.h" +#include "kscopeconfig.h" + +#define FILE_VERSION "VERSION=2" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +QueryPageBase::QueryPageBase(QWidget* pParent, const char* szName) : + QHBox(pParent, szName), + m_bLocked(false) +{ +} + +/** + * Class destructor. + */ +QueryPageBase::~QueryPageBase() +{ +} + +/** + * Sets the list's colours and font, according the user's preferences. + */ +void QueryPageBase::applyPrefs() +{ + // Apply colour settings + m_pView->setPaletteBackgroundColor(Config().getColor( + KScopeConfig::QueryWindowBack)); + m_pView->setPaletteForegroundColor(Config().getColor( + KScopeConfig::QueryWindowFore)); + m_pView->setFont(Config().getFont(KScopeConfig::QueryWindow)); +} + +/** + * Restores a locked query from the given query file. + * NOTE: The query file is deleted when loading is complete. + * @param sProjPath The full path of the project directory + * @param sFileName The name of the query file to load + * @return true if successful, false otherwise + */ +bool QueryPageBase::load(const QString& sProjPath, const QString& sFileName) +{ + QString sTemp, sFile, sFunc, sLine, sText; + int nState; + + // Try to open the query file for reading + QFile file(sProjPath + "/" + sFileName); + if (!file.open(IO_ReadOnly)) + return false; + + { + // Use a new scope for the QTextStream object, to ensure its + // destruction before the file is deleted + QTextStream str(&file); + + // Make sure the file's version is correct + sTemp = str.readLine(); + if (sTemp != FILE_VERSION) { + file.remove(); + return false; + } + + // Try to read the file header + if (!readHeader(str)) + return false; + + // Read query records + sTemp = str.readLine(); + nState = 0; + while (sTemp != QString::null) { + switch (nState) { + // File path + case 0: + sFile = sTemp; + break; + + // Function name + case 1: + sFunc = sTemp; + break; + + // Line number + case 2: + sLine = sTemp; + break; + + // Text string + case 3: + sText = sTemp; + addRecord(sFile, sFunc, sLine, sText); + break; + } + + nState = (nState + 1) % 4; + sTemp = str.readLine(); + } + } + + // Delete the query file + file.remove(); + + return true; +} + +/** + * Writes the contents of the page to a file. + * This method is called for pages that shoukld be stored before the owner + * project is closed (@see shouldSave()). + * @param sProjPath The full path of the project directory + * @param sFileName Holds the file name to which the page was saved, upon + * return + * @return true if successful, false otherwise + */ +bool QueryPageBase::save(const QString& sProjPath, QString& sFileName) +{ + QListViewItemIterator itr(m_pView); + + // Get the file name to use + sFileName = getFileName(sProjPath); + if (sFileName.isEmpty()) + return false; + + // Open the query file for writing + QFile file(sProjPath + "/" + sFileName); + if (!file.open(IO_WriteOnly)) + return false; + + QTextStream str(&file); + + // Write the version string + str << FILE_VERSION << "\n"; + + writeHeader(str); + + // Write all records + for(; itr.current(); ++itr) { + str << itr.current()->text(0) << "\n" + << itr.current()->text(1) << "\n" + << itr.current()->text(2) << "\n" + << itr.current()->text(3) << "\n"; + } + + return true; +} + +/** + * Selects the next record in the view. + */ +void QueryPageBase::selectNext() +{ + m_pView->selectNext(); +} + +/** + * Selects the previous record in the view. + */ +void QueryPageBase::selectPrev() +{ + m_pView->selectPrev(); +} + +#include "querypagebase.moc" diff --git a/src/querypagebase.h b/src/querypagebase.h new file mode 100644 index 0000000..8603874 --- /dev/null +++ b/src/querypagebase.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYPAGEBASE_H +#define QUERYPAGEBASE_H + +#include <qhbox.h> + +class QueryView; + +/** + * Defines a page in a QueryWidget's tab widget. + * This is a abstract base class for QueryPage and HistoryPage. It defines + * the common behaviour for all pages, which includes appearance, display + * of tab text, page locking, storage and retrieval of information to + * and from files and basic navigation. + * Each page embeds a list widget derived from QueryView. The actual type + * of widget is defined by the different page classes. + * @author Elad Lahav + */ +class QueryPageBase : public QHBox +{ +Q_OBJECT +public: + QueryPageBase(QWidget* pParent = 0, const char* szName = 0); + ~QueryPageBase(); + + void applyPrefs(); + bool load(const QString&, const QString&); + bool save(const QString&, QString&); + void selectNext(); + void selectPrev(); + + + /** + * Determines whether this page can be locked. + * Can be used by inheriting classes to define non-lockable pages. + * @return Always true + */ + virtual bool canLock() { return true; } + + /** + * Locks or unlocks this page. + * @param bLocked true to lock the page, false to unlock it. + */ + void setLocked(bool bLocked) { m_bLocked = bLocked; } + + /** + * Determines whether this page is locked. + * @return true if the page is locked, false otherwise + */ + bool isLocked() { return m_bLocked; } + + /** + * Determines whether this page should be saved when the project is closed. + * By default, pages are saved if and only if they are locked. + * @return true to save the page, false otherwise + */ + virtual bool shouldSave() const { return m_bLocked; }; + + /** + * Constructs a caption for this page. + * The caption appears in the page's tab button and as the page's + * tooltip. + * @param bBrief true to generate a brief caption, false otherwise + * @return The page's title + */ + virtual QString getCaption(bool bBrief = false) const = 0; + +signals: + /** + * Emitted when a record is selected in the view widget. + * @param sFile The "File" field of the selected record + * @param nLine The "Line" field of the selected record + */ + void lineRequested(const QString& sFile, uint nLine); + +protected: + /** The embedded list. */ + QueryView* m_pView; + + /** Indicates whether this page is locked. A locked page is never + overriden by new data, and is also saved to a disc file when the + session is closed. */ + bool m_bLocked; + + /** + * Creates a new list item and adds it to the embedded view. + * This method is used to add records read from a stored file. + * @param sFile The "File" field of the record + * @param sFunc The "Function" field of the record + * @param sLine The "Line" field of the record + * @param sText The "Text" field of the record + */ + virtual void addRecord(const QString& sFile, const QString& sFunc, + const QString& sLine, const QString& sText) = 0; + + /** + * Creates a file path to store this page. + * The path is composed of the project's path and a unique file name + * in that directory. + * @param sProjPath The project's directory + * @return The page's file path + */ + virtual QString getFileName(const QString& sProjPath) const = 0; + + /** + * Tries to read the file header of a stored page. + * The contents of the header differ among inheriting classes. + * @param str A text stream initialised to the open page file + * @return true if the header was read successfully and contains the + * expected information, false otherwise + */ + virtual bool readHeader(QTextStream& str) = 0; + + /** + * Writes a header to a page's file. + * The contents of the header differ among inheriting classes. + * @param str A text stream initialised to the open page file + */ + virtual void writeHeader(QTextStream& str) = 0; +}; + +#endif diff --git a/src/queryresultsmenu.cpp b/src/queryresultsmenu.cpp new file mode 100644 index 0000000..74bcdb4 --- /dev/null +++ b/src/queryresultsmenu.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <klocale.h> +#include "queryresultsmenu.h" + +/** + * Class constructor. + * @param pParent Parent widget + * @param szName Optional object name + */ +QueryResultsMenu::QueryResultsMenu(QWidget* pParent, const char* szName) : + QPopupMenu(pParent, szName), + m_pItem(NULL) +{ + // Create the menu + insertItem(i18n("&View Source"), this, SLOT(slotViewSource()), 0, + ViewSource); + insertItem(i18n("Find &Definition"), this, SLOT(slotFindDef()), 0, + FindDef); + insertSeparator(); + insertItem(i18n("&Copy"), this, SLOT(slotCopy()), 0, Copy); + insertSeparator(); + insertItem(i18n("&Filter..."), this, SLOT(slotFilter()), 0, Filter); + insertItem(i18n("&Show All"), this, SIGNAL(showAll()), 0, ShowAll); + insertSeparator(); + insertItem(i18n("&Remove Item"), this, SLOT(slotRemove()), 0, Remove); +} + +/** + * Class destructor. + */ +QueryResultsMenu::~QueryResultsMenu() +{ +} + +/** + * Displays the popup-menu at the requested coordinates. + * @param pItem The item on which the menu was requested + * @param ptPos The requested position for the menu + * @param nCol The column over which the menu was requested, -1 if no + * column is associated with the request + */ +void QueryResultsMenu::slotShow(QListViewItem* pItem, const QPoint& ptPos, + int nCol) +{ + // Save the requested item and column number to use in signals + m_pItem = pItem; + m_nCol = nCol; + + if (m_pItem == NULL) { + // No item selected, disable everything but the "Filter" and "Show All" + // items + setItemEnabled(ViewSource, false); + setItemEnabled(FindDef, false); + setItemEnabled(Copy, false); + setItemEnabled(Remove, false); + } + else { + // Item selected, enable record-specific actions + setItemEnabled(ViewSource, true); + setItemEnabled(Copy, true); + setItemEnabled(Remove, true); + + // The "Find Definition" item should only be enabled if the mouse + // was clicked over a valid function name + setItemEnabled(FindDef, (m_nCol == 0) && + (m_pItem->text(0) != "<global>")); + + // Set menu contents according to the column number + switch (m_nCol) { + case 0: + changeItem(Copy, "&Copy Function"); + break; + + case 1: + changeItem(Copy, "&Copy File"); + break; + + case 2: + changeItem(Copy, "&Copy Line Number"); + break; + + case 3: + changeItem(Copy, "&Copy Text"); + break; + + default: + m_nCol = 0; + } + } + + // Show the menu + popup(ptPos); +} + +/** + * Emits the viewSource() signal. + * This slot is activated when the "View Source" item is selected. + */ +void QueryResultsMenu::slotViewSource() +{ + if (m_pItem != NULL) + emit viewSource(m_pItem); +} + +/** + * Emits the findDef() signal. + * This slot is activated when the "Find Definition" item is selected. + */ +void QueryResultsMenu::slotFindDef() +{ + if (m_pItem != NULL) + emit findDef(m_pItem->text(0)); +} + +/** + * Emits the copy() signal. + * This slot is activated when the "Copy [Column]" item is selected. + */ +void QueryResultsMenu::slotCopy() +{ + if (m_pItem != NULL) + emit copy(m_pItem, m_nCol); +} + +/** + * Emits the filter() signal. + * This slot is activated when the "Filter..." item is selected. + */ +void QueryResultsMenu::slotFilter() +{ + emit filter(m_nCol); +} + +/** + * Emits the remove() signal. + * This slot is activated when the "Remove" item is selected. + */ +void QueryResultsMenu::slotRemove() +{ + if (m_pItem != NULL) + emit remove(m_pItem); +} + +#include "queryresultsmenu.moc" diff --git a/src/queryresultsmenu.h b/src/queryresultsmenu.h new file mode 100644 index 0000000..099dd2e --- /dev/null +++ b/src/queryresultsmenu.h @@ -0,0 +1,110 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYRESULTSMENU_H +#define QUERYRESULTSMENU_H + +#include <qpopupmenu.h> +#include <qlistview.h> +#include <qregexp.h> + +/** + * Provides a popup-menu for list views containing query results. + * The popup menu contains commands for copying field text out of items and + * for removing items. + * This class assumes a certain ordering of the list columns. If an owner + * object uses a different configuration, it needs to call setColumns() after + * constructing the object. + * @author Elad Lahav + */ +class QueryResultsMenu : public QPopupMenu +{ + Q_OBJECT + +public: + QueryResultsMenu(QWidget* pParent = 0, const char* szName = 0); + ~QueryResultsMenu(); + +public slots: + void slotShow(QListViewItem*, const QPoint&, int nCol); + +signals: + /** + * Indicates that the "View Source" menu item was selected. + * @param pItem The item for which the menu was displayed + */ + void viewSource(QListViewItem* pItem); + + /** + * Indicates that the "Find Definition" menu item was selected. + * @param sFunc The function to look for + */ + void findDef(const QString& sFunc); + + /** + * Indicates that the "Copy [Column]" menu item was selected. + * @param pItem The item for which the menu was displayed + * @param nCol The requested column + */ + void copy(QListViewItem* pItem, int nCol); + + /** + * Indicates that the "Filter..." menu item was selected. + * @param nCol The column in which to search + */ + void filter(int nCol); + + /** + * Indicates that the "Show All" menu item was selected. + */ + void showAll(); + + /** + * Indicates that the "Remove Item" menu item was selected. + * @param pItem The item for which the menu was displayed + */ + void remove(QListViewItem* pItem); + +private: + /** Menu item IDs. */ + enum { ViewSource, FindDef, Copy, Filter, ShowAll, Remove }; + + /** The item for which the popup menu is provided (cannot be NULL). */ + QListViewItem* m_pItem; + + /** The list column for which the query was invoked. */ + int m_nCol; + +private slots: + void slotViewSource(); + void slotFindDef(); + void slotCopy(); + void slotFilter(); + void slotRemove(); +}; + +#endif diff --git a/src/queryview.cpp b/src/queryview.cpp new file mode 100644 index 0000000..c56a2b0 --- /dev/null +++ b/src/queryview.cpp @@ -0,0 +1,444 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qapplication.h> +#include <qclipboard.h> +#include <klocale.h> +#include "queryview.h" +#include "queryresultsmenu.h" +#include "queryviewdlg.h" +#include "cscopefrontend.h" +#include "searchresultsdlg.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The name of the widget + */ +QueryView::QueryView(QWidget* pParent, const char* szName) : + QListView(pParent, szName), + m_pLastItem(NULL) +{ + // Create the popup-menu + m_pQueryMenu = new QueryResultsMenu(this); + + // Initialise the list's columns + setAllColumnsShowFocus(true); + addColumn(i18n("Function")); + addColumn(i18n("File")); + addColumn(i18n("Line")); + addColumn(i18n("Text")); + setColumnAlignment(2, Qt::AlignRight); + + setShowSortIndicator(true); + + // A record is selected if it is either double-clicked, or the ENTER + // key is pressed while the record is highlighted + connect(this, SIGNAL(doubleClicked(QListViewItem*)), this, + SLOT(slotRecordSelected(QListViewItem*))); + connect(this, SIGNAL(returnPressed(QListViewItem*)), this, + SLOT(slotRecordSelected(QListViewItem*))); + + // Show the popup-menu when requested + connect(this, + SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)), + m_pQueryMenu, SLOT(slotShow(QListViewItem*, const QPoint&, int))); + + // Handle popup-menu commands + connect(m_pQueryMenu, SIGNAL(viewSource(QListViewItem*)), this, + SLOT(slotRecordSelected(QListViewItem*))); + connect(m_pQueryMenu, SIGNAL(findDef(const QString&)), this, + SLOT(slotFindDef(const QString&))); + connect(m_pQueryMenu, SIGNAL(copy(QListViewItem*, int)), this, + SLOT(slotCopy(QListViewItem*, int))); + connect(m_pQueryMenu, SIGNAL(filter(int)), this, SLOT(slotFilter(int))); + connect(m_pQueryMenu, SIGNAL(showAll()), this, + SLOT(slotShowAll())); + connect(m_pQueryMenu, SIGNAL(remove(QListViewItem*)), this, + SLOT(slotRemoveItem(QListViewItem*))); +} + +/** + * Class destructor. + */ +QueryView::~QueryView() +{ +} + +/** + * Creates a new list item showing a query result record. + * @param sFunc The name of the function + * @param sFile The file path + * @param sLine The line number in the above file + * @param sText The line's text + * @param pParent The parent item (ignored) + */ +void QueryView::addRecord(const QString& sFunc, const QString& sFile, + const QString& sLine, const QString& sText, QListViewItem* /* pParent */) +{ + QListViewItem* pItem; + + pItem = new QueryViewItem(this, m_pLastItem, 2); + pItem->setText(0, sFunc); + pItem->setText(1, sFile); + pItem->setText(2, sLine); + pItem->setText(3, sText); + + m_pLastItem = pItem; +} + +/** + * Selects an item. + * When an item is selected, it is highlighted and made visible. By + * definition, the lineRequested() signal is also emitted. + * This method is used for selecting records programmatically (@see + * selectNext() for example). It has nothing to do with user selection. + * @param pItem The list item to select + */ +void QueryView::select(QListViewItem* pItem) +{ + ensureItemVisible(pItem); + setSelected(pItem, true); + slotRecordSelected(pItem); +} + +/** + * Selects the next record in the list (if one exists). + * The function selects the next item as follows: + * - The first item in the list, if there is no current item + * - The current item, if it is not selected + * - The item immediately below the current item, otherwise + */ +void QueryView::selectNext() +{ + QListViewItem* pItem; + + // Do nothing if the list is empty + if (firstChild() == NULL) + return; + + // Find the next record + pItem = currentItem(); + if (pItem == NULL) { + pItem = firstChild(); + } + else if (pItem->isSelected()) { + pItem = pItem->itemBelow(); + if (pItem == NULL) + return; + } + + // Select the new item + select(pItem); +} + +/** + * Selects the previous record in the list (if one exists). + * The function selects the previous item as follows: + * - The first item in the list, if there is no current item + * - The current item, if it is not selected + * - The item immediately above the current item, otherwise + */ +void QueryView::selectPrev() +{ + QListViewItem* pItem; + + // Do nothing if the list is empty + if (firstChild() == NULL) + return; + + // Find the item immediately above this one + pItem = currentItem(); + if (pItem == NULL) { + pItem = firstChild(); + } + else if (pItem->isSelected()) { + pItem = pItem->itemAbove(); + if (pItem == NULL) + return; + } + + // Select the new item + select(pItem); +} + +/** + * Informs the view that query progress information has been received. + * The view emits the needToShow() signal telling its parent that the widget + * should become visible (if not already so). + */ +void QueryView::queryProgress() +{ + if (!isVisible()) + emit needToShow(); +} + +/** + * Called when a query using this view terminates. + * @param nRecords Number of records generated by the query + */ +void QueryView::queryFinished(uint nRecords, QListViewItem*) +{ + // Auto-select a single record (no need to emit the show() signal in + // that case) + if (nRecords == 1) { + emit select(firstChild()); + return; + } + + // Report a query that has returned an empty record set + if (nRecords == 0) + addRecord(i18n("No results"), "", "", "", NULL); + + // Data is available, instruct the owner object to show the view + emit needToShow(); +} + +/** + * Creates an iterator and initialises it to point to the first _visible_ + * item in the list. + * @return A new iterator initialised to the beginning of the list + */ +QueryView::Iterator QueryView::getIterator() +{ + QListViewItem* pItem; + + for (pItem = firstChild(); pItem != NULL && !pItem->isVisible(); + pItem = pItem->nextSibling()); + + return Iterator(pItem); +} + +/** + * Handles double-click events over the view. + * NOTE: We override this method since the QListView implementation opens + * expandable items. This is undesired for tree-like query views (such as the + * call tree. + * @param pEvent Event description object + */ +void QueryView::contentsMouseDoubleClickEvent(QMouseEvent* pEvent) +{ + QListViewItem* pItem; + + // Handle only left button double-clicks + if (pEvent == NULL || pEvent->button() != LeftButton) + return; + + // Find the clicked item + pItem = itemAt(contentsToViewport(pEvent->pos())); + if (pItem == NULL) + return; + + // Emit the doubleClicked() signal + emit doubleClicked(pItem); +} + +/** + * Emits the lineRequested() signal when a list item is selected. + * This slot is connected to the doubleClicked() and returnPressed() + * signals of the list view. + * @param pItem The selected item + */ +void QueryView::slotRecordSelected(QListViewItem* pItem) +{ + QString sFileName, sLine; + + // Get the file name and line number + sFileName = pItem->text(1); + sLine = pItem->text(2); + + // Do not process the "No results" item + if (!sLine.isEmpty()) + emit lineRequested(sFileName, sLine.toUInt()); +} + +/** + * Looks up the definition of a given function. + * Results are displayed in a popup window. + * This slot is connected to the findDef() signal emitted by the results menu. + * @param sFunc The function to look for + */ +void QueryView::slotFindDef(const QString& sFunc) +{ + QueryViewDlg* pDlg; + + // Create a query view dialogue + pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this); + + // Display a line when it is selected in the dialogue + connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this, + SIGNAL(lineRequested(const QString&, uint))); + + // Start the query + pDlg->query(CscopeFrontend::Definition, sFunc); +} + +/** + * Copies the text of the requested field (item+column) to the clipboard. + * This slot is connected to the copy() signal of the QueryResultsMenu object. + * @param pItem The item from which to copy + * @param nCol The index of the item field to copy + */ +void QueryView::slotCopy(QListViewItem* pItem, int nCol) +{ + QApplication::clipboard()->setText(pItem->text(nCol), + QClipboard::Clipboard); +} + +/** + * Hides all items in the page that do not meet the given search criteria. + * This slot is connected to the search() signal of the QueryResultsMenu + * object. + * The search is incremental: only visible items are checked, so that a new + * search goes over the results of the previous one. + * @param nCol The list column to search in + */ +void QueryView::slotFilter(int nCol) +{ + SearchResultsDlg dlg(this); + QRegExp re; + QListViewItem* pItem; + bool bNegate; + + // Prepare the dialogue + dlg.setColumn(nCol); + + // Show the dialogue + if (dlg.exec() != QDialog::Accepted) + return; + + // Get the selected regular expression + dlg.getPattern(re); + bNegate = dlg.isNegated(); + + // Disable visual updates while search is in progress + setUpdatesEnabled(false); + + // Iterate over all items in the list + pItem = firstChild(); + while (pItem != NULL) { + // Filter visible items only + if (pItem->isVisible() && + (re.search(pItem->text(nCol)) == -1) != bNegate) { + pItem->setVisible(false); + } + + pItem = pItem->nextSibling(); + } + + // Redraw the list + setUpdatesEnabled(true); + triggerUpdate(); +} + +/** + * Makes all list items visible. + * This slot is connected to the showAll() signal of the QueryResultsMenu + * object. + */ +void QueryView::slotShowAll() +{ + QListViewItem* pItem; + + // Iterate over all items in the list + pItem = firstChild(); + while (pItem != NULL) { + pItem->setVisible(true); + pItem = pItem->nextSibling(); + } +} + +/** + * Deletes the item on which a popup-menu has been invoked. + * This slot is connected to the remove() signal of the QueryResultsMenu + * object. + * @param pItem The item to remove + */ +void QueryView::slotRemoveItem(QListViewItem* pItem) +{ + delete pItem; +} + +/** + * Moves the iterator to the next _visible_ item in the list. + */ +void QueryView::Iterator::next() +{ + if (m_pItem == NULL) + return; + + do { + m_pItem = m_pItem->nextSibling(); + } while (m_pItem != NULL && !m_pItem->isVisible()); +} + +/** + * @return The function associated with the list item the iterator points to + */ +QString QueryView::Iterator::getFunc() +{ + if (m_pItem == NULL) + return ""; + + return m_pItem->text(0); +} + +/** + * @return The file associated with the list item the iterator points to + */ +QString QueryView::Iterator::getFile() +{ + if (m_pItem == NULL) + return ""; + + return m_pItem->text(1); +} + +/** + * @return The line number associated with the list item the iterator points + * to + */ +QString QueryView::Iterator::getLine() +{ + if (m_pItem == NULL) + return ""; + + return m_pItem->text(2); +} + +/** + * @return The text associated with the list item the iterator points to + */ +QString QueryView::Iterator::getText() +{ + if (m_pItem == NULL) + return ""; + + return m_pItem->text(3); +} + +#include "queryview.moc" diff --git a/src/queryview.h b/src/queryview.h new file mode 100644 index 0000000..c896d6b --- /dev/null +++ b/src/queryview.h @@ -0,0 +1,217 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYVIEW_H +#define QUERYVIEW_H + +#include <qlistview.h> +#include <qregexp.h> + +class QueryResultsMenu; + +/** + * Items in a query view. + * The sole purpose for creating a new class is to be able to sort query + * results numerically by line number. + * @author Elad Lahav + */ +class QueryViewItem : public QListViewItem +{ +public: + /** + * Class constructor. + * Used for list views. + * @param pView The view widget + * @param pAfter The item to preceed the new one + * @param nLineCol The index of the line column + */ + QueryViewItem(QListView* pView, QListViewItem* pAfter, + int nLineCol) : QListViewItem(pView, pAfter), m_nLineCol(nLineCol) + {} + + /** + * Class constructor. + * Used for tree views. + * @param pParent The parent item + * @param pAfter The item to preceed the new one + * @param nLineCol The index of the line column + */ + QueryViewItem(QListViewItem* pParent, QListViewItem* pAfter, + int nLineCol) : QListViewItem(pParent, pAfter), m_nLineCol(nLineCol) + {} + + /** + * Compares two items. + * If the given column holds line numbers, than the items are compared + * by their numeric values. Otherwise, a standard text comparison is + * performed. + * @param pItem The item to compare to + * @param nCol The column by which to compare + * @param bAscend Whether sorting in ascending or descending order + * @return 0 if the items are equal, 1 if the current item is greater, + * -1 if the current item is smaller + */ + virtual int compare(QListViewItem* pItem, int nCol, bool bAscend) const { + if (nCol == m_nLineCol) { + uint nLineCur, nLineOther; + int nResult; + + // Get the line numbers of each item + nLineCur = text(nCol).toUInt(); + nLineOther = pItem->text(nCol).toUInt(); + + // Compare the line numbers + nResult = nLineCur - nLineOther; + if (nResult == 0) + return 0; // Items are equal + else if (nResult > 0) + return 1; // The first item is greater + else + return -1; // The second item is greater + } + + return QListViewItem::compare(pItem, nCol, bAscend); + } + +private: + /** The index of the column holding the line numbers. */ + int m_nLineCol; +}; + +/** + * A list view widget for displaying locations in the source code. Each record + * (list item) represents a single line of code. + * The main purpose of this class is for showing query results (@see + * QueryViewDriver), but is can also serve as a base class for any widget + * which needs to refer to locations in the source code (@see + * HistoryView). + * The view has 4 columns, for showing the file path, function name, line + * number and line text of a code location. + * The widget owns a popup menu which allows users to copy information + * from records, filter records, and more. + * @author Elad Lahav + */ +class QueryView : public QListView +{ + Q_OBJECT + +public: + QueryView(QWidget* pParent = 0, const char* szName = 0); + ~QueryView(); + + virtual void addRecord(const QString&, const QString&, const QString&, + const QString&, QListViewItem* pParent = NULL); + virtual void select(QListViewItem*); + virtual void selectNext(); + virtual void selectPrev(); + virtual void queryProgress(); + virtual void queryFinished(uint, QListViewItem* pParent = NULL); + + /** + * Provides an iterator over the list of query results. + * @author Elad Lahav + */ + class Iterator + { + public: + /** + * Default constructor. + */ + Iterator() : m_pItem(NULL) {} + + /** + * Copy constructor. + * @param itr The copied object + */ + Iterator(const Iterator& itr) : m_pItem(itr.m_pItem) {} + + /** + * @return true if the iterator points _beyond_ the end of the list, + * false otherwise + */ + bool isEOF() { return m_pItem == NULL; } + + void next(); + + QString getFunc(); + QString getFile(); + QString getLine(); + QString getText(); + + private: + /** Points to the current list item. */ + QListViewItem* m_pItem; + + /** + * Private constructor used to return initialised iterators. + * This constructor can only be called from within QueryView. + * @param pItem The initial list item + */ + Iterator(QListViewItem* pItem) : m_pItem(pItem) {} + + friend class QueryView; + }; + + Iterator getIterator(); + +signals: + /** + * Notifies the owner widget that it needs to be visible since some + * information is available to display. + * This information may be an advancement of the progress bar, + * availability of query results, etc. + */ + void needToShow(); + + /** + * Emitted when a list record is selected. + * Selection is done by either double-clicking a query or by highlighting + * it and then pressing the ENTER key. + * @param sFile The "File" field of the selected record + * @param nLine The "Line" field of the selected record + */ + void lineRequested(const QString& sFile, uint nLine); + +protected: + /** A popup-menu for manipulating query result items. */ + QueryResultsMenu* m_pQueryMenu; + + /** A pointer to the last item (used for appending results). */ + QListViewItem* m_pLastItem; + + void contentsMouseDoubleClickEvent(QMouseEvent*); + +protected slots: + virtual void slotRecordSelected(QListViewItem*); + virtual void slotFindDef(const QString&); + virtual void slotCopy(QListViewItem*, int); + virtual void slotFilter(int); + virtual void slotShowAll(); + virtual void slotRemoveItem(QListViewItem*); +}; + +#endif diff --git a/src/queryviewdlg.cpp b/src/queryviewdlg.cpp new file mode 100644 index 0000000..93cd85e --- /dev/null +++ b/src/queryviewdlg.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "queryviewdlg.h" +#include "queryviewdriver.h" + +/** + * Class constructor. + * @param nFlags Controls the behaviour of the diaogue + * @param pParent The parent widget + * @param szName The widget's name + */ +QueryViewDlg::QueryViewDlg(uint nFlags, QWidget* pParent, + const char* szName) : + QueryViewLayout(pParent, szName), + m_nFlags(nFlags) +{ + // Set the destructive flag, if required + if (nFlags & DestroyOnClose) + setWFlags(getWFlags() | WDestructiveClose); + + // Create a driver for running queries + m_pDriver = new QueryViewDriver(m_pView, this); + + // Show the dialogue when instructed by the driver + connect(m_pView, SIGNAL(needToShow()), this, SLOT(slotShow())); + + // Propagate the lineRequested() signal from the QueryView object + connect(m_pView, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotLineRequested(const QString&, uint))); + + // Make the dialogue modal + setModal(true); +} + +/** + * Class destructor. + */ +QueryViewDlg::~QueryViewDlg() +{ +} + +/** + * Starts a query. + * @param nType The type of the query + * @param sText The query's text + * @param bCase true for case-sensitive queries, false otherwise + */ +void QueryViewDlg::query(uint nType, const QString& sText, bool bCase) +{ + m_pDriver->query(nType, sText, bCase); +} + +/** + * Make the dialogue visible when instructed by the driver. + * This slot is connected to the show() signal emitted by the QueryViewDriver + * object. + */ +void QueryViewDlg::slotShow() +{ + show(); +} + +/** + * Propagates the lineRequested() signal from the view object. + * If the CloseOnSelect flag is set, the dialogue is closed. + * This slot is connected to the lineRequested() signal emitted by the + * QueryView widget. + */ +void QueryViewDlg::slotLineRequested(const QString& sFileName, uint nLine) +{ + emit lineRequested(sFileName, nLine); + + if (m_nFlags & CloseOnSelect) + close(); +} + +/** + * @return A QueryView iterator initialised to the beginning of the result + * list + */ +QueryView::Iterator QueryViewDlg::getIterator() +{ + return m_pView->getIterator(); +} + +#include "queryviewdlg.moc" diff --git a/src/queryviewdlg.h b/src/queryviewdlg.h new file mode 100644 index 0000000..fc1c2f7 --- /dev/null +++ b/src/queryviewdlg.h @@ -0,0 +1,88 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYVIEWDLG_H +#define QUERYVIEWDLG_H + +#include "queryviewlayout.h" +#include "queryview.h" + +class QueryViewDriver; + +/** + * A dialogue for running and displaying queries. + * The dialogue is built around a QueryView widget, and uses a QueryViewDriver + * object to run a query. The dialogue is used in different contexts, such + * as executing quick definitions, displaying multiple call nodes in a graph, + * etc. + * The dialogue is always modal, but should not be launched using exec(). + * Instead, it is created as a modeless, hidden, dialogue. It then becomes + * modal (and visible) only if and when information is available (@see + * QueryViewDriver::show()). + * @author Elad Lahav + */ +class QueryViewDlg : public QueryViewLayout +{ + Q_OBJECT + +public: + QueryViewDlg(uint nFlags = 0, QWidget* pParent = 0, + const char* szName = 0); + ~QueryViewDlg(); + + /** These flags control the behaviour of the dialogue. */ + enum { CloseOnSelect = 0x1, DestroyOnClose = 0x2, + DestroyOnSelect = CloseOnSelect | DestroyOnClose }; + + void query(uint, const QString&, bool bCase = true); + + QueryView::Iterator getIterator(); + +signals: + /** + * Propagates the lineRequested() signal of the embedded QueryView + * widget. + * @param sFile The "File" field of the selected record + * @param nLine The "Line" field of the selected record + */ + void lineRequested(const QString& sFile, uint nLine); + +private: + /** Flags the control the behaviour of the dialogue. */ + uint m_nFlags; + + /** Used for running Cscope queries and displaying their results in the + view. */ + QueryViewDriver* m_pDriver; + +private slots: + void slotShow(); + void slotLineRequested(const QString&, uint); +}; + +#endif + diff --git a/src/queryviewdriver.cpp b/src/queryviewdriver.cpp new file mode 100644 index 0000000..f04c44d --- /dev/null +++ b/src/queryviewdriver.cpp @@ -0,0 +1,180 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <klocale.h> +#include "queryviewdriver.h" +#include "queryview.h" + +/** + * Class constructor. + * Creates a driver that adds new records as root items in the given view. + * @param pView The view to which this driver should add records + * @param pParent The parent object of the driver + * @param szName The name of the object + */ +QueryViewDriver::QueryViewDriver(QueryView* pView, QObject* pParent, + const char* szName) : QObject(pParent, szName), + m_pView(pView), + m_pItem(NULL), + m_progress(pView), + m_bRunning(false) +{ + m_pCscope = new CscopeFrontend(); + + // Add records to the page when Cscope outputs them + connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this, + SLOT(slotDataReady(FrontendToken*))); + + // Report progress information + connect(m_pCscope, SIGNAL(progress(int, int)), this, + SLOT(slotProgress(int, int))); + + // Perform tasks when the query process terminates + connect(m_pCscope, SIGNAL(finished(uint)), this, + SLOT(slotFinished(uint))); + + connect(m_pView, SIGNAL(destroyed()), this, SLOT(slotViewClosed())); +} + +/** + * Class destructor. + */ +QueryViewDriver::~QueryViewDriver() +{ + delete m_pCscope; +} + +/** + * Executes a query. + * @param nType The type of the query (@see CscopeFrontend) + * @param sText The query's text + * @param bCase true for case-sensitive queries, false otherwise + * @param pItem If non-null, represents an view item passed back to + * the view in a call to addRecord() + */ +void QueryViewDriver::query(uint nType, const QString& sText, bool bCase, + QListViewItem* pItem) +{ + m_pItem = pItem; + + // Make sure sorting is disabled while entries are added + m_pView->setSorting(100); + + // Execute the query + m_pCscope->query(nType, sText, bCase); + m_bRunning = true; + m_pView->setEnabled(false); + m_pView->setUpdatesEnabled(false); +} + +/** + * Adds a query entry to the view. + * Called by a CscopeFrontend object, when a new entry was received in its + * whole from the Cscope back-end process. + * @param pToken The first token in the entry + */ +void QueryViewDriver::slotDataReady(FrontendToken* pToken) +{ + QString sFile, sFunc, sLine, sText; + + // Get the file name + sFile = pToken->getData(); + pToken = pToken->getNext(); + + // Get the function name + sFunc = pToken->getData(); + pToken = pToken->getNext(); + + // Get the line number + sLine = pToken->getData(); + if (!sLine.toInt()) { + // Line number could not be 0! + // means that function name was empty + sLine = sFunc; + sFunc = "<global>"; + } + else { + pToken = pToken->getNext(); + } + + // Get the line's text + sText = pToken->getData(); + pToken = pToken->getNext(); + + // Add a new item at the end of the list + m_pView->addRecord(sFunc, sFile, sLine, sText, m_pItem); +} + +/** + * Handles a finished query event, reported by the Cscope frontend object. + * If no resutls are available, a proper message is displayed. If only one + * record was generated by Cscope, it is automatically selected for viewing. + * @param nRecords The number of records the query has generated + */ +void QueryViewDriver::slotFinished(uint nRecords) +{ + // The query is no longer running + m_bRunning = false; + m_pView->setEnabled(true); + m_pView->setUpdatesEnabled(true); + m_pView->triggerUpdate(); + + // Destroy the progress bar + m_progress.finished(); + + // Let owner widget decide what to do based on the number of records + m_pView->queryFinished(nRecords, m_pItem); +} + +/** + * Displays search progress information. + * This slot is connected to the progress() signal emitted by a + * CscopeFrontend object. + * @param nFiles The number of files scanned + * @param nTotal The total number of files in the project + */ +void QueryViewDriver::slotProgress(int nFiles, int nTotal) +{ + // A progress report is available, instruct the owner object to show the + // view + if (nTotal > 1) + m_pView->queryProgress(); + + // Set the progress bar + m_progress.setProgress(nFiles, nTotal); +} + +/** + * Called when the owner view is destroyed. + */ +void QueryViewDriver::slotViewClosed() +{ + m_pView = NULL; + m_pCscope->kill(); +} + +#include "queryviewdriver.moc" diff --git a/src/queryviewdriver.h b/src/queryviewdriver.h new file mode 100644 index 0000000..77ff9ed --- /dev/null +++ b/src/queryviewdriver.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYVIEWDRIVER_H +#define QUERYVIEWDRIVER_H + +#include <qobject.h> +#include <qlistview.h> +#include "cscopefrontend.h" + +class QueryView; + +/** + * Executes a Cscope query and displays the results in a QueryView widget. + * This class is used in conjunction with QueryView to create a query + * display object. The driver uses the view widget to display result records + * of an executed query. It also uses the view as a parent widget for the + * query progress bar. + * @author Elad Lahav + */ +class QueryViewDriver : public QObject +{ + Q_OBJECT + +public: + QueryViewDriver(QueryView*, QObject* pParent = 0, const char* szName = 0); + ~QueryViewDriver(); + + void query(uint, const QString&, bool bCase, QListViewItem* pItem = NULL); + + /** + * @return true if a query is currently running, false otherwise + */ + bool isRunning() { return m_bRunning; } + +private: + /** Cscope object for running queries. */ + CscopeFrontend* m_pCscope; + + /** The view to which this object adds result records. */ + QueryView* m_pView; + + /** QueryView item passed to addRecord(). */ + QListViewItem* m_pItem; + + /** Displays query progress information. */ + CscopeProgress m_progress; + + /** This flag is set to true when a query is executed, and back to false + when the the CscopeFrontend object emits the finished() signal. */ + bool m_bRunning; + +private slots: + void slotDataReady(FrontendToken*); + void slotFinished(uint); + void slotProgress(int, int); + void slotViewClosed(); +}; + +#endif diff --git a/src/queryviewlayout.ui b/src/queryviewlayout.ui new file mode 100644 index 0000000..ae097c5 --- /dev/null +++ b/src/queryviewlayout.ui @@ -0,0 +1,167 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>QueryViewLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>QueryViewLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>654</width> + <height>499</height> + </rect> + </property> + <property name="caption"> + <string>Query Results</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QueryView"> + <property name="name"> + <cstring>m_pView</cstring> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Right-click inside the list for more options.</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>QueryView</class> + <header location="local">queryview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1003">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>QueryViewLayout</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>buttonCancel</sender> + <signal>clicked()</signal> + <receiver>QueryViewLayout</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>queryview.h</includehint> +</includehints> +</UI> diff --git a/src/querywidget.cpp b/src/querywidget.cpp new file mode 100644 index 0000000..113f216 --- /dev/null +++ b/src/querywidget.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtoolbutton.h> +#include <qtooltip.h> +#include <klocale.h> +#include <kmessagebox.h> +#include "querywidget.h" +#include "kscopepixmaps.h" +#include "kscopeconfig.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +QueryWidget::QueryWidget(QWidget* pParent, const char* szName) : + QueryWidgetLayout(pParent, szName), + m_pPageMenu(NULL), + m_pLockAction(NULL), + m_pHistPage(NULL), + m_bHistEnabled(true), + m_nQueryPages(0) +{ + // Pages can be closed by clicking their tabs + m_pQueryTabs->setHoverCloseButton(true); + + // Change the lock action state according to the current page + connect(m_pQueryTabs, SIGNAL(currentChanged(QWidget*)), this, + SLOT(slotCurrentChanged(QWidget*))); + + // Close a query when its tab button is clicked + connect(m_pQueryTabs, SIGNAL(closeRequest(QWidget*)), this, + SLOT(slotClosePage(QWidget*))); + + // Show the menu when requested + connect(m_pQueryTabs, SIGNAL(contextMenu(const QPoint&)), this, + SLOT(slotContextMenu(const QPoint&))); + connect(m_pQueryTabs, SIGNAL(contextMenu(QWidget*, const QPoint&)), this, + SLOT(slotContextMenu(QWidget*, const QPoint&))); +} + +/** + * Class destructor. + */ +QueryWidget::~QueryWidget() +{ +} + +/** + * Runs a query in a query page. + * A query page is first selected, with a new one created if required. The + * method then creates a Cscope process and runs the query. + * @param nType The query's numeric type code + * @param sText The query's text, as entered by the user + * @param bCase true for case-sensitive queries, false otherwise + */ +void QueryWidget::initQuery(uint nType, const QString& sText, bool bCase) +{ + QueryPage* pPage; + + // Make sure we have a query page + findQueryPage(); + pPage = (QueryPage*)currentPage(); + + // Use the current page, or a new page if the current one is locked + if (pPage->isLocked()) { + addQueryPage(); + pPage = (QueryPage*)currentPage(); + } + + // Reset the page's results list + pPage->clear(); + pPage->query(nType, sText, bCase); + + // Set the page's tab text according to the new query + setPageCaption(pPage); +} + +/** + * Applies the user's colour and font preferences to all pages. + */ +void QueryWidget::applyPrefs() +{ + QueryPage* pPage; + int nPages, i; + + // Iterate query pages + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(i); + pPage->applyPrefs(); + setPageCaption(pPage); + } +} + +/** + * Loads all pages saved when the project was closed. + * @param sProjPath The full path of the project directory + * @param slFiles The list of query file names to load + */ +void QueryWidget::loadPages(const QString& sProjPath, + const QStringList& slFiles) +{ + QStringList::ConstIterator itr; + QueryPageBase* pPage; + QString sName; + + // Iterate through query files + for (itr = slFiles.begin(); itr != slFiles.end(); ++itr) { + // Set the target page, based on the file type (query or history) + if ((*itr).startsWith("History")) { + findHistoryPage(); + pPage = m_pHistPage; + } + else { + findQueryPage(); + pPage = (QueryPage*)currentPage(); + } + + // Load a query file to this page, and lock the page + if (pPage->load(sProjPath, *itr)) { + setPageCaption(pPage); + setPageLocked(pPage, true); + } + } +} + +/** + * Stores all pages marked for saving into files in the project directory. + * @param sProjPath The full path of the project directory + * @param slFiles Holds a list of query file names, upon return + */ +void QueryWidget::savePages(const QString& sProjPath, QStringList& slFiles) +{ + int nPageCount, i; + QueryPage* pPage; + QString sFileName; + + // Iterate pages + nPageCount = m_pQueryTabs->count(); + for (i = 0; i < nPageCount; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(i); + if (pPage->shouldSave()) { + // Store this query page + if (pPage->save(sProjPath, sFileName) && !sFileName.isEmpty()) + slFiles.append(sFileName); + } + } +} + +/** + * Adds a new position record to the active history page. + * @param sFile The file path + * @param nLine The line number + * @param sText The contents of the line pointed to by the file path and + * line number + */ +void QueryWidget::addHistoryRecord(const QString& sFile, uint nLine, + const QString& sText) +{ + // Validate file name and line number + if (sFile.isEmpty() || nLine == 0) + return; + + // Do nothing if history logging is disabled + if (!m_bHistEnabled) + return; + + // Make sure there is an active history page + findHistoryPage(); + + // Add the position entry to the active page + m_pHistPage->addRecord(sFile, nLine, sText); +} + +/** + * Sets the tab caption and tool-tip for the given page. + * @param pPage The page whose tab needs to be changed + */ +void QueryWidget::setPageCaption(QueryPageBase* pPage) +{ + m_pQueryTabs->changeTab(pPage, + pPage->getCaption(Config().getUseBriefQueryCaptions())); + m_pQueryTabs->setTabToolTip(pPage, pPage->getCaption()); +} + +/** + * Creates a new query page, and adds it to the tab widget. + * The new page is set as the current one. + */ +void QueryWidget::addQueryPage() +{ + QueryPage* pPage; + QString sTitle; + + // Create the page + pPage = new QueryPage(this); + + // Add the page, and set it as the current one + m_pQueryTabs->insertTab(pPage, GET_PIXMAP(TabUnlocked), "Query", + m_nQueryPages++); + setCurrentPage(pPage); + + // Emit the lineRequested() signal when a query record is selected on + // this page + connect(pPage, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotRequestLine(const QString&, uint))); +} + +/** + * Creates a new query page, and emits signal about it. + */ +void QueryWidget::slotNewQueryPage() +{ + addQueryPage(); + emit newQuery(); +} + +/** + * Locks or unlocks a query. + * This slot is connected to the toggled() signal of the lock query button. + * @param bOn true if the new state of the button is "on", false if it is + * "off" + */ +void QueryWidget::slotLockCurrent(bool bOn) +{ + QueryPageBase* pPage; + + pPage = currentPage(); + + if (pPage != NULL) + setPageLocked(currentPage(), bOn); +} + +/** + * Locks or unlocks a query, by toggling the current state. + */ +void QueryWidget::slotLockCurrent() +{ + QueryPageBase* pPage; + + pPage = currentPage(); + if (pPage != NULL) + setPageLocked(pPage, !pPage->isLocked()); +} + +/** + * Reruns the query whose results are displayed in the current page. + */ +void QueryWidget::slotRefreshCurrent() +{ + QueryPage* pPage; + + // Make sure the current page is a valid, non-empty one + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage == NULL) + return; + + // Clear the current page contents + pPage->refresh(); +} + +/** + * Selects the next query result record in the current query page. + */ +void QueryWidget::slotNextResult() +{ + QueryPage* pPage; + + // Select the next record in the current page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) + pPage->selectNext(); +} + +/** + * Selects the next query result record in the current query page. + */ +void QueryWidget::slotPrevResult() +{ + QueryPage* pPage; + + // Select the next record in the current page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) + pPage->selectPrev(); +} + +/** + * Closes the current query page. + */ +void QueryWidget::slotCloseCurrent() +{ + QWidget* pPage; + + // Close the current page + pPage = currentPage(); + if (pPage != NULL) + slotClosePage(pPage); +} + +/** + * Closes all query pages. + */ +void QueryWidget::slotCloseAll() +{ + int nPageCount, i; + QueryPage* pPage; + + // Close all pages + nPageCount = m_pQueryTabs->count(); + for (i = 0; i < nPageCount; i++) { + pPage = (QueryPage*)m_pQueryTabs->page(0); + m_pQueryTabs->removePage(pPage); + delete pPage; + } + + m_pHistPage = NULL; +} + +/** + * Handles the "Go->Back" menu command. + * Moves to the previous position in the position history. + */ +void QueryWidget::slotHistoryPrev() +{ + if (m_pHistPage != NULL) { + m_bHistEnabled = false; + m_pHistPage->selectPrev(); + m_bHistEnabled = true; + } +} + +/** + * Handles the "Go->Forward" menu command. + * Moves to the next position in the position history. + */ +void QueryWidget::slotHistoryNext() +{ + if (m_pHistPage != NULL) { + m_bHistEnabled = false; + m_pHistPage->selectNext(); + m_bHistEnabled = true; + } +} + +/** + * Sets the active history page, if any, as the current page. + */ +void QueryWidget::selectActiveHistory() +{ + if (m_pHistPage) + setCurrentPage(m_pHistPage); +} + +/** + * Attaches the page operations menu to this widget. + * The page menu is a popup menu that handles such operations as opening a + * new page, closing a page, locking a page, etc. + * @param pMenu Pointer to the popup menu + * @param pAction Pointer to the "Lock/Unlock" toggle action + */ +void QueryWidget::setPageMenu(QPopupMenu* pMenu, KToggleAction* pAction) +{ + m_pPageMenu = pMenu; + m_pLockAction = pAction; +} + +/** + * Emits a signal indicating a certain source file and line number are + * requested. + * This slot is connected to the recordSelected() signal emitted by any of + * the query pages. The signal emitted by this slot is used to display an + * editor page at the requested line. + * @param sFileName The file's path + * @param nLine The requested line in the file + */ +void QueryWidget::slotRequestLine(const QString& sFileName, uint nLine) +{ + // Disable history if the request came from the active history page + if (currentPage() == m_pHistPage) + m_bHistEnabled = false; + + // Emit the signal + emit lineRequested(sFileName, nLine); + + // Re-enable history + if (currentPage() == m_pHistPage) + m_bHistEnabled = true; +} + +/** + * Update the lock button when the current query page changes. + * @param pWidget The new current page + */ +void QueryWidget::slotCurrentChanged(QWidget* pWidget) +{ + QueryPage* pPage; + + pPage = (QueryPage*)pWidget; + m_pLockAction->setChecked(pPage->isLocked()); +} + +/** + * Removes the given page from the tab widget. + * This slot is connected to the closeRequest() signal of the KTabBar object. + * @param pPage The page to close + */ +void QueryWidget::slotClosePage(QWidget* pPage) +{ + // Prompt the user before closing a locked query + if (((QueryPage*)pPage)->isLocked()) { + if (KMessageBox::questionYesNo(NULL, i18n("You about about to close" + " a locked page.\nAre you sure?")) == KMessageBox::No) { + return; + } + } + + // Check if the closed page is the active history page + if (pPage == m_pHistPage) + m_pHistPage = NULL; + // Update the number of open history pages + else if (dynamic_cast<HistoryPage*>(pPage) == NULL) + m_nQueryPages--; + + // Remove the page and delete the object + m_pQueryTabs->removePage(pPage); + delete pPage; +} + +/** + * Displays a context menu for page operations. + * This slot is connected to the contextMenu() signal, emitted by + * m_pQueryTabs. + * NOTE: We assume that the first item in the menu is "New". + * @param pt The point over which the mouse was clicked in request for the + * context menu + */ +void QueryWidget::slotContextMenu(const QPoint& pt) +{ + uint i; + + // Disable everything but the "new" action (clicked outside any widget) + for (i = 1; i < m_pPageMenu->count(); i++) + m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), false); + + // Show the menu + m_pPageMenu->popup(pt); +} + +/** + * Displays a context menu for page operations. + * This slot is connected to the contextMenu() signal, emitted by + * m_pQueryTabs. + * @param pWidget The page under the mouse + * @param pt The point over which the mouse was clicked in request for + * the context menu + */ +void QueryWidget::slotContextMenu(QWidget* pWidget, const QPoint& pt) +{ + uint i; + + // Operations are on the current page, so we must ensure the clicked + // tab becomes the current one + setCurrentPage(pWidget); + + // Enable all operations + for (i = 1; i < m_pPageMenu->count(); i++) + m_pPageMenu->setItemEnabled(m_pPageMenu->idAt(i), true); + + // Show the menu + m_pPageMenu->popup(pt); +} + +/** + * Locks/unlocks the give page. + * @param pPage The page to lock or unlock + * @param bLock true to lock the page, false to unlock it + */ +void QueryWidget::setPageLocked(QueryPageBase* pPage, bool bLock) +{ + if (!pPage->canLock()) + return; + + // Set the locking state of the current page + pPage->setLocked(bLock); + m_pQueryTabs->setTabIconSet(pPage, bLock ? GET_PIXMAP(TabLocked) : + GET_PIXMAP(TabUnlocked)); + + // There can only be one unlocked history page. Check if a non-active + // query page is being unlocked + if (isHistoryPage(pPage) && (pPage != m_pHistPage) && !bLock) { + // Lock the active history page (may be NULL) + if (m_pHistPage != NULL) + setPageLocked(m_pHistPage, true); + + // Set the unlock page as the new active history page + m_pHistPage = (HistoryPage*)pPage; + } +} + +/** + * Ensures the current page is a query page that is ready to accept new + * queries. + * The function first checks the current page. If it is an unlocked query + * page, then nothing needs to be done. Otherwise, it checks for the first + * unlocked query page by iterating over all pages in the tab widget. If this + * fails as well, a new query page is created. + */ +void QueryWidget::findQueryPage() +{ + QueryPage* pPage; + int nPages, i; + + // First check if the current page is an unlocked query page + pPage = dynamic_cast<QueryPage*>(currentPage()); + if (pPage != NULL) { + if (!pPage->isLocked() && !pPage->isRunning()) + return; + } + + // Look for the first unlocked query page + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = dynamic_cast<QueryPage*>(m_pQueryTabs->page(i)); + if (pPage != NULL) { + if (!pPage->isLocked() && !pPage->isRunning()) { + setCurrentPage(pPage); + return; + } + } + } + + // Couldn't find an unlocked query page, create a new one + addQueryPage(); +} + +/** + * Ensures an active history page exists. + * The active history page is the only unlocked history page. If one does not + * exist, it is created. + */ +void QueryWidget::findHistoryPage() +{ + HistoryPage* pPage; + int nPages, i; + QString sTitle; + + // First check if the active history page is unlocked + if (m_pHistPage != NULL && !m_pHistPage->isLocked()) + return; + + // Look for the first unlocked history page + nPages = m_pQueryTabs->count(); + for (i = 0; i < nPages; i++) { + pPage = dynamic_cast<HistoryPage*>(m_pQueryTabs->page(i)); + if (pPage != NULL && !pPage->isLocked()) { + m_pHistPage = pPage; + return; + } + } + + // Couldn't find an unlocked query page, create a new one + m_pHistPage = new HistoryPage(this); + + // Add the page, and set it as the current one + m_pQueryTabs->insertTab(m_pHistPage, GET_PIXMAP(TabUnlocked), ""); + setPageCaption(m_pHistPage); + + // Emit the lineRequested() signal when a query record is selected on + // this page + connect(m_pHistPage, SIGNAL(lineRequested(const QString&, uint)), this, + SLOT(slotRequestLine(const QString&, uint))); +} + +#include "querywidget.moc" diff --git a/src/querywidget.h b/src/querywidget.h new file mode 100644 index 0000000..a798ec0 --- /dev/null +++ b/src/querywidget.h @@ -0,0 +1,152 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef QUERYWIDGET_H +#define QUERYWIDGET_H + +#include <qlistview.h> +#include <qpopupmenu.h> +#include <kaction.h> +#include "querywidgetlayout.h" +#include "tabwidget.h" +#include "querypage.h" +#include "historypage.h" +#include "projectmanager.h" + +/** + * A tabbed-window holding Cscope query results pages. + * @author Elad Lahav + */ + +class QueryWidget : public QueryWidgetLayout +{ + Q_OBJECT + +public: + QueryWidget(QWidget* pParent = 0, const char* szName = 0); + ~QueryWidget(); + + void addQueryPage(); + void initQuery(uint, const QString&, bool); + void applyPrefs(); + void loadPages(const QString&, const QStringList&); + void savePages(const QString&, QStringList&); + void addHistoryRecord(const QString&, uint, const QString&); + void selectActiveHistory(); + void setPageMenu(QPopupMenu*, KToggleAction*); + void getBookmarks(FileLocationList&); + + /** + * Enables/disables new history items. + * @param bEnabled true to enable new history items, false to + * disable + */ + void setHistoryEnabled(bool bEnabled) { m_bHistEnabled = bEnabled; } + +public slots: + void slotNewQueryPage(); + void slotLockCurrent(bool); + void slotLockCurrent(); + void slotRefreshCurrent(); + void slotNextResult(); + void slotPrevResult(); + void slotCloseCurrent(); + void slotCloseAll(); + void slotHistoryPrev(); + void slotHistoryNext(); + +signals: + /** + * Emitted when the a lineRequested() signal is received from any of the + * currently open query pages. + * @param sPath The full path of the requested source file + * @param nLine The requested line number + */ + void lineRequested(const QString& sPath, uint nLine); + + /** + * Emitted when new query page is requested by user + */ + void newQuery(); + +private: + /** A popup menu with query page commands (new query, lock/unlock, close + query, etc.). */ + QPopupMenu* m_pPageMenu; + + /** A toggle-like action for changing the locked state of a query. */ + KToggleAction* m_pLockAction; + + /** The active history page. */ + HistoryPage* m_pHistPage; + + /** Determines whether history items should be added to the active + history page. */ + bool m_bHistEnabled; + + /** The number of query pages currently open. */ + int m_nQueryPages; + + void setPageCaption(QueryPageBase*); + + /** + * @return The active page in the tab widget + */ + inline QueryPageBase* currentPage() { + return (QueryPageBase*)m_pQueryTabs->currentPage(); + } + + /** + * @param pWidget A query page to set as the current one + */ + inline void setCurrentPage(QWidget* pWidget) { + if (pWidget) + m_pQueryTabs->setCurrentPage(m_pQueryTabs->indexOf(pWidget)); + } + + /** + * Determines if a page is a history page. + * @param pPage The page to check + * @return true if the given page is a history page + */ + inline bool isHistoryPage(QWidget* pPage) { + return (dynamic_cast<HistoryPage*>(pPage) != NULL); + } + + void setPageLocked(QueryPageBase*, bool); + void findQueryPage(); + void findHistoryPage(); + +private slots: + void slotRequestLine(const QString&, uint); + void slotCurrentChanged(QWidget*); + void slotClosePage(QWidget*); + void slotContextMenu(const QPoint&); + void slotContextMenu(QWidget*, const QPoint&); +}; + +#endif diff --git a/src/querywidgetlayout.ui b/src/querywidgetlayout.ui new file mode 100644 index 0000000..52e7fb3 --- /dev/null +++ b/src/querywidgetlayout.ui @@ -0,0 +1,62 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>QueryWidgetLayout</class> +<widget class="QWidget"> + <property name="name"> + <cstring>QueryWidgetLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>740</width> + <height>343</height> + </rect> + </property> + <property name="caption"> + <string>Form2</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="TabWidget"> + <property name="name"> + <cstring>m_pQueryTabs</cstring> + </property> + </widget> + </hbox> +</widget> +<customwidgets> + <customwidget> + <class>TabWidget</class> + <header location="local">tabwidget.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>1</container> + <sizepolicy> + <hordata>7</hordata> + <verdata>7</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="437">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000017c49444154388dad95db71c32010458f322e652966f3ef325031a68bf8df14c3f6e27c80c4338927e39df1182474b85c2ed2465f4fde53db76b4bcbf3e55af98414af79709c778b3815cfe9f8fc7576e39803b249afe1ff074e716c062bd76696716cd83a0519c2019dd444e66b8035ad12738a53ba274d0142146a6658a802a386d2ff6632e5d2fd5668c10430f3b56660621801a783fab9fc1add20255cdbf56d131698c45fd0ec49ef1d1f55c7df084fa19eab52a0d012c31d5a43859f554b5bf77dbcbbd62c1e17fb291322a86d367915ee90925a70707aeac70a578062faa854213b745ec7e061f2a0a6815b77dcf2a53d90b591ca2c96327d906b30c5505cae17192a118ec9ff5191508831d4b2b8e4d8b21abf23e5f1307b7db30d6b33cf6cb1cab56c5a1e4d53940eaf28f4a114c67bbbb77c5d926ab142939b5d967f5bdff63e2ceb79b08ecc332c5954db21a2971d9535c1fb331392718ca0691978cf16b9cda6169919c0efcce7ae980fca7b6a6fd56d5dbd07fdbc7f41bcb78aa0bdc5b1e190000000049454e44ae426082</data> + </image> +</images> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>tabwidget.h</includehint> +</includehints> +</UI> diff --git a/src/scanprogressdlg.cpp b/src/scanprogressdlg.cpp new file mode 100644 index 0000000..e380c60 --- /dev/null +++ b/src/scanprogressdlg.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlabel.h> +#include <qpushbutton.h> +#include <klocale.h> +#include "scanprogressdlg.h" + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName The widget's name + */ +ScanProgressDlg::ScanProgressDlg(QWidget* pParent, const char* szName) : + ScanProgressLayout(pParent, szName), + m_nFiles(0), + m_nCurFiles(0) +{ + show(); + + // Emit the cancelled() signal when the "Cancel" button is clicked + connect(m_pCancelButton, SIGNAL(clicked()), this, SIGNAL(cancelled())); +} + +/** + * Class destructor. + */ +ScanProgressDlg::~ScanProgressDlg() +{ +} + +/** + * Adds the given number of files to the total count of files already scanned. + * A visual indication of the progress is given in intervals of more than 100 + * files (to prevent too-frequent GUI updates.) + * @param nFiles The number of files scanned since the last call + */ +void ScanProgressDlg::addFiles(int nFiles) +{ + QString sText; + + // Do nothing if no files were scanned + if (nFiles <= 0) + return; + + // Update the total number of files scanned + m_nFiles += nFiles; + + // Update progress only if more than 100 files were scanned since the last + // update + if ((m_nFiles - m_nCurFiles) > 100) { + sText.sprintf(i18n("Scanned %d files..."), m_nFiles); + m_pText->setText(sText); + m_nCurFiles = m_nFiles; + } +} + +#include "scanprogressdlg.moc" diff --git a/src/scanprogressdlg.h b/src/scanprogressdlg.h new file mode 100644 index 0000000..84564de --- /dev/null +++ b/src/scanprogressdlg.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef SCANPROGRESSDLG_H +#define SCANPROGRESSDLG_H + +#include <qwidget.h> +#include <scanprogresslayout.h> + +/** + * Displays the progress of a file scan operation. + * This dialogue is displayed while a ProjectFilesDlg dialogue scans a + * directory tree for all files matching the patterns defined for the + * project's source files. + * @author Elad Lahav + */ + +class ScanProgressDlg : public ScanProgressLayout +{ + Q_OBJECT + +public: + ScanProgressDlg(QWidget* pParent = 0, const char* szName = 0); + ~ScanProgressDlg(); + + void addFiles(int); + +signals: + /** + * Indicates that the dialogue's "Cancel" button hsa been clicked by the + * user. + */ + void cancelled(); + +private: + /** The total number of files scanned thus far. */ + int m_nFiles; + + /** The number of files currently displayed in the progress report (which + may be smaller than m_nFiles since not every call to addFiles() updates + the progress display.)*/ + int m_nCurFiles; +}; + +#endif diff --git a/src/scanprogresslayout.ui b/src/scanprogresslayout.ui new file mode 100644 index 0000000..85482a8 --- /dev/null +++ b/src/scanprogresslayout.ui @@ -0,0 +1,115 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>ScanProgressLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>ScanProgressLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>198</width> + <height>103</height> + </rect> + </property> + <property name="caption"> + <string>Scanning Directory</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_pText</cstring> + </property> + <property name="text"> + <string>Scanned 0 files...</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/searchlist.cpp b/src/searchlist.cpp new file mode 100644 index 0000000..ccff869 --- /dev/null +++ b/src/searchlist.cpp @@ -0,0 +1,270 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qheader.h> +#include "searchlist.h" + +/** + * Intercepting additional key events of QLineEdit to browse the list + * @param pKey The pressed key event + */ +void SearchLineEdit::keyPressEvent(QKeyEvent* pKey) +{ + switch(pKey->key()) { + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + emit keyPressed(pKey); + break; + + default: + QLineEdit::keyPressEvent(pKey); + break; + } +} + +/** + * Class constructor. + * @param pParent Owner list view widget + */ +ListToolTip::ListToolTip(SearchList* pParent) : + QToolTip(pParent->getList()->viewport()), + m_pList(pParent) +{ +} + +/** + * Displays a tool-tip according to the current location of the mouse + * pointer. + * @param pt The mouse pointer coordinates + */ +void ListToolTip::maybeTip(const QPoint& pt) +{ + QString str; + QListView* pList; + QListViewItem* pItem; + + // Get the item at the given point + pList = m_pList->getList(); + pItem = pList->itemAt(pt); + if (pItem == NULL) + return; + + // Get the tip string for this item + if (!m_pList->getTip(pItem, str)) + return; + + // Get the bounding rectangle of the item + const QRect rcItem = pList->itemRect(pItem); + if (!rcItem.isValid()) + return; + + // Get the header coordinates + const QRect rcHead = pList->header()->rect(); + if (!rcHead.isValid()) + return; + + // Calculate the tool-tip rectangle + QRect rcCell(rcHead.left(), rcItem.top(), rcItem.width(), rcItem.height()); + + // Display the tool-tip + tip(rcCell, str); +} + +/** + * Class constructor. + * @param nSearchCol The list column on which to perform string look-ups + * @param pParent The parent widget + * @param szName The widget's name + */ +SearchList::SearchList(int nSearchCol, QWidget* pParent, const char* szName) : + QVBox(pParent, szName), + m_nSearchCol(nSearchCol) +{ + // Create the child widgets + m_pEdit = new SearchLineEdit(this); + m_pList = new QListView(this); + + // Set up the tooltip generator + QToolTip::remove(m_pList); + m_pToolTip = new ListToolTip(this); + + connect(m_pEdit, SIGNAL(textChanged(const QString&)), this, + SLOT(slotFindItem(const QString&))); + connect(m_pList, SIGNAL(doubleClicked(QListViewItem*)), this, + SLOT(slotItemSelected(QListViewItem*))); + connect(m_pList, SIGNAL(returnPressed(QListViewItem*)), this, + SLOT(slotItemSelected(QListViewItem*))); + connect(m_pEdit, SIGNAL(returnPressed()), this, + SLOT(slotItemSelected())); + connect(m_pEdit, SIGNAL(keyPressed(QKeyEvent*)), this, + SLOT(slotKeyPressed(QKeyEvent*))); +} + +/** + * Class destructor. + */ +SearchList::~SearchList() +{ + delete m_pToolTip; +} + +/** + * Sets the keyboad focus to the search box. + */ +void SearchList::slotSetFocus() +{ + m_pEdit->setFocus(); +} + +/** + * Selects a list item whose string begins with the text entered in the edit + * widget. + * This slot is connected to the textChanged() signal of the line edit widget. + * @param sText The new text in the edit widget + */ +void SearchList::slotFindItem(const QString& sText) +{ + QListViewItem* pItem; + + // Try to find an item that contains this text + // Priority to exactly matched, + // then try to find line begins with the text, + // and if not found, then try to find the line contains the text + pItem = m_pList->findItem(sText, m_nSearchCol, + ExactMatch | BeginsWith | Contains); + + // Select this item + if (pItem != 0) { + m_pList->setSelected(pItem, true); + m_pList->ensureItemVisible(pItem); + } +} + +/** + * Lets inheriting classes process an item selection made through the list + * widget. + * This slot is connected to the doubleClicked() and returnPressed() + * signals of the list widget. + */ +void SearchList::slotItemSelected(QListViewItem* pItem) +{ + processItemSelected(pItem); + m_pEdit->setText(""); +} + +/** + * Lets inheriting classes process an item selection made through the edit + * widget. + * This slot is connected to the returnPressed() signal of the edit widget. + */ +void SearchList::slotItemSelected() +{ + QListViewItem* pItem; + + if ((pItem = m_pList->selectedItem()) != NULL) { + m_pEdit->setText(pItem->text(m_nSearchCol)); + processItemSelected(pItem); + } + + m_pEdit->setText(""); +} + +#define SEARCH_MATCH(pItem) \ + pItem->text(m_nSearchCol).startsWith(m_pEdit->text()) + +/** + * Sets a new current item based on key events in the edit box. + * This slot is connected to the keyPressed() signal of the edit widget. + * @param pKey The key evant passed by the edit box + */ +void SearchList::slotKeyPressed(QKeyEvent* pKey) +{ + QListViewItem* pItem, * pNewItem; + int nPageSize, nPos; + + // Select the current item, or the first one if there is no current item + pItem = m_pList->currentItem(); + + // Set a new current item based on the pressed key + switch (pKey->key()) { + case Qt::Key_Up: + if (pItem) { + for (pNewItem = pItem->itemAbove(); + pNewItem && !SEARCH_MATCH(pNewItem); + pNewItem = pNewItem->itemAbove()); + + if (pNewItem) + pItem = pNewItem; + } + break; + + case Qt::Key_Down: + if (pItem) { + for (pNewItem = pItem->itemBelow(); + pNewItem && !SEARCH_MATCH(pNewItem); + pNewItem = pNewItem->itemBelow()); + + if (pNewItem) + pItem = pNewItem; + } + break; + + case Qt::Key_PageUp: + nPageSize = m_pList->visibleHeight() / pItem->height(); + for (nPos = 0; + pItem && pItem->itemAbove() && (nPos < nPageSize); + nPos++) + pItem = pItem->itemAbove(); + break; + + case Qt::Key_PageDown: + nPageSize = m_pList->visibleHeight() / pItem->height(); + for (nPos = 0; + pItem && pItem->itemBelow() && (nPos < nPageSize); + nPos++) + pItem = pItem->itemBelow(); + break; + + default: + pKey->ignore(); + return; + } + + // Select the first item if no other item was selected + if (pItem == NULL) + pItem = m_pList->firstChild(); + + // Select the new item + if (pItem) { + m_pList->setSelected(pItem, true); + m_pList->ensureItemVisible(pItem); + } +} + +#include "searchlist.moc" diff --git a/src/searchlist.h b/src/searchlist.h new file mode 100644 index 0000000..ffa7ac8 --- /dev/null +++ b/src/searchlist.h @@ -0,0 +1,144 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef SEARCHLIST_H +#define SEARCHLIST_H + +#include <qwidget.h> +#include <qvbox.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qtooltip.h> + +class SearchList; + +/** + * Defines a line text edit for searchable list view. + * The widget is based on QLineEdit with additional key functions + * Supported key events (up and down) are emitted as signals + * @author Albert Yosher + */ +class SearchLineEdit : public QLineEdit +{ + Q_OBJECT +public: + SearchLineEdit(QWidget* pParent) : QLineEdit(pParent) {}; + ~SearchLineEdit() {}; + +signals: + /** + * Emitted when one of the up/down or page up/page down keys were pressed + * inside this edit widget. + * @param pEvent The event received for this key press + */ + void keyPressed(QKeyEvent* pEvent); + +private: + virtual void keyPressEvent(QKeyEvent*); +}; + +/** + * A tool-tip class for the search list. + * Enables sub-classes of the list to provide a customised tool-tip for each + * list item. + * @author Gabor Fekete + */ +class ListToolTip : public QToolTip +{ +public: + ListToolTip(SearchList* pParent); + +protected: + virtual void maybeTip(const QPoint& pt); + +private: + /** The owner widget. */ + SearchList* m_pList; +}; + + +/** + * Defines a searchable list view. + * The widget is composed of a list view, and an edit box used to enter + * search data. Whenever the text in the edit box changes, the list view is + * set to point to the first item that matches the new text. + * @author Elad Lahav + */ +class SearchList : public QVBox +{ + Q_OBJECT + +public: + SearchList(int nSearchCol, QWidget* pParent = 0, const char* szName = 0); + ~SearchList(); + + /** + * @return A pointer to the list part of the widget. + */ + QListView* getList() { return m_pList; } + + /** + * Constructs a tool-tip for the given item. + * @param pItem The item for which a tip is required + * @param sTip The constructed tip string (on return) + * @return True to display the tip, false otherwise + */ + virtual bool getTip(QListViewItem* pItem, QString& sTip) = 0; + +public slots: + void slotSetFocus(); + +protected: + /** The search edit-box. */ + QLineEdit* m_pEdit; + + /** The list part of the widget. */ + QListView* m_pList; + + /** + * Called whenever the user selects an item in the list by either double- + * clicking it, or by highlighting the item and pressing the ENTER key. + * @param pItem The selected list item + */ + virtual void processItemSelected(QListViewItem* pItem) = 0; + +protected slots: + void slotFindItem(const QString&); + void slotItemSelected(QListViewItem*); + void slotItemSelected(); + void slotKeyPressed(QKeyEvent*); + +private: + /** Specifies the search column, i.e., the list column whose strings are + compared with the text in the search edit-box. */ + int m_nSearchCol; + + /** A tool-tip for the list entries. */ + ListToolTip* m_pToolTip; +}; + +#endif diff --git a/src/searchresultsdlg.cpp b/src/searchresultsdlg.cpp new file mode 100644 index 0000000..bb63fa5 --- /dev/null +++ b/src/searchresultsdlg.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qpushbutton.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qradiobutton.h> +#include "searchresultsdlg.h" + +int SearchResultsDlg::s_nType = PlainText; +bool SearchResultsDlg::s_bCaseSensitive = true; +bool SearchResultsDlg::s_bNegate = false; + +/** + * Class constructor. + * @param pParent The parent widget + * @param szName Optional widget name + */ +SearchResultsDlg::SearchResultsDlg(QWidget* pParent, const char* szName) : + SearchResultsLayout(pParent, szName, true, 0) +{ + // Select the last selected type radio button + switch (s_nType) { + case PlainText: + m_pTextRadio->setChecked(true); + break; + + case RegExp: + m_pRegExpRadio->setChecked(true); + break; + + case SimpRegExp: + m_pSimpRegExpRadio->setChecked(true); + break; + } + + // Set the default value of the check-boxes + m_pCaseSenCheck->setChecked(s_bCaseSensitive); + m_pNegateCheck->setChecked(s_bNegate); + + // Terminate the dialogue when either the "OK" or "Cancel" buttons are + // clicked + connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); +} + +/** + * Class destructor. + */ +SearchResultsDlg::~SearchResultsDlg() +{ +} + +/** + * Determines the default column on which to search. + * The column's name appears in the column combo-box. + */ +void SearchResultsDlg::setColumn(int nCol) +{ + m_pColumnCB->setCurrentItem(nCol); +} + +/** + * @return The selected column on which to perform the search + */ +int SearchResultsDlg::getColumn() +{ + return m_pColumnCB->currentItem(); +} + +/** + * Creates a regular expression based on the given pattern and type of search. + * @param re A regular expression object to set + */ +void SearchResultsDlg::getPattern(QRegExp& re) +{ + QString sPattern; + + sPattern = m_pSearchEdit->text(); + + // Create the regular expression + switch (s_nType) { + case PlainText: + re.setPattern(QRegExp::escape(sPattern)); + re.setWildcard(false); + break; + + case RegExp: + re.setPattern(sPattern); + re.setWildcard(false); + break; + + case SimpRegExp: + re.setPattern(sPattern); + re.setWildcard(true); + break; + } + + // Set the case-(in)sensitive parameter + re.setCaseSensitive(s_bCaseSensitive); +} + +/** + * Reads user values from the widgets, and closes the dialogue. + * This slot is connected to the clicked() signal emitted by the "OK" button. + */ +void SearchResultsDlg::accept() +{ + QString sText; + + // Determine the selected type and store its value for the next invocation + if (m_pTextRadio->isChecked()) + s_nType = PlainText; + else if (m_pRegExpRadio->isChecked()) + s_nType = RegExp; + else if (m_pSimpRegExpRadio->isChecked()) + s_nType = SimpRegExp; + + // Determine search parameters + s_bCaseSensitive = m_pCaseSenCheck->isChecked(); + s_bNegate = m_pNegateCheck->isChecked(); + + // Remove white space from the search text + sText = m_pSearchEdit->text(); + sText.stripWhiteSpace(); + if (sText.isEmpty()) { + QDialog::reject(); + return; + } + + // Close the dialogue + QDialog::accept(); +} + +#include "searchresultsdlg.moc" + diff --git a/src/searchresultsdlg.h b/src/searchresultsdlg.h new file mode 100644 index 0000000..d636f8f --- /dev/null +++ b/src/searchresultsdlg.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef SEARCHRESULTSDLG_H +#define SEARCHRESULTSDLG_H + +#include <qregexp.h> +#include <qcheckbox.h> +#include "searchresultslayout.h" + +/** + * A dialogue for defining searches on query results. + * The dialogue is activated from the query results menu. + * @author Elad Lahav + */ +class SearchResultsDlg : public SearchResultsLayout +{ + Q_OBJECT + +public: + SearchResultsDlg(QWidget* pParent = 0, const char* szName = 0); + ~SearchResultsDlg(); + + void setColumn(int); + int getColumn(); + void getPattern(QRegExp&); + + /** + * @return true if the search pattern should be negated, false otherwise + */ + bool isNegated() { return m_pNegateCheck->isChecked(); } + +protected slots: + virtual void accept(); + +private: + /** Possible search types. */ + enum { PlainText = 0, RegExp, SimpRegExp }; + + /** Remembers the last search type. */ + static int s_nType; + + /** Remembers the last value of the Case Sensitive check-box. */ + static bool s_bCaseSensitive; + + /** Remembers the last value of the Negate Search check-box. */ + static bool s_bNegate; +}; + +#endif diff --git a/src/searchresultslayout.ui b/src/searchresultslayout.ui new file mode 100644 index 0000000..cdcde53 --- /dev/null +++ b/src/searchresultslayout.ui @@ -0,0 +1,214 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SearchResultsLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SearchResultsLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>361</width> + <height>307</height> + </rect> + </property> + <property name="caption"> + <string>Filter Query Results</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Search For:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_pSearchEdit</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Search In:</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>171</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Function</string> + </property> + </item> + <item> + <property name="text"> + <string>File</string> + </property> + </item> + <item> + <property name="text"> + <string>Line</string> + </property> + </item> + <item> + <property name="text"> + <string>Text</string> + </property> + </item> + <property name="name"> + <cstring>m_pColumnCB</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Search Type</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_pTextRadio</cstring> + </property> + <property name="text"> + <string>Plain Text</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_pRegExpRadio</cstring> + </property> + <property name="text"> + <string>RegE&xp</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_pSimpRegExpRadio</cstring> + </property> + <property name="text"> + <string>Simplified RegExp</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pCaseSenCheck</cstring> + </property> + <property name="text"> + <string>Case Sensitive</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pNegateCheck</cstring> + </property> + <property name="text"> + <string>Negate Search</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>201</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pOKButton</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>m_pSearchEdit</tabstop> + <tabstop>m_pColumnCB</tabstop> + <tabstop>m_pTextRadio</tabstop> + <tabstop>m_pRegExpRadio</tabstop> + <tabstop>m_pSimpRegExpRadio</tabstop> + <tabstop>m_pCaseSenCheck</tabstop> + <tabstop>m_pOKButton</tabstop> + <tabstop>m_pCancelButton</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/src/symbolcompletion.cpp b/src/symbolcompletion.cpp new file mode 100644 index 0000000..2ec8194 --- /dev/null +++ b/src/symbolcompletion.cpp @@ -0,0 +1,344 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtimer.h> +#include <klocale.h> +#include "symbolcompletion.h" + +bool SymbolCompletion::s_bACEnabled; +uint SymbolCompletion::s_nACMinChars; +uint SymbolCompletion::s_nACDelay; +uint SymbolCompletion::s_nACMaxEntries; + +/** + * Class constructor. + * @param pEditor The editor object for which symbol completion is required + * @param pParent Parent object + * @param szName Optional object name + */ +SymbolCompletion::SymbolCompletion(SymbolCompletion::Interface* pEditor, + QObject* pParent, const char* szName) : + QObject(pParent, szName), + m_pEditor(pEditor), + m_pCCObject(NULL) +{ + // Initialise member objects + m_pCscope = new CscopeFrontend(); + m_pAutoCompTimer = new QTimer(this); + + // Add entries to the completion list when they are available + connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this, + SLOT(slotAddEntry(FrontendToken*))); + + // Show the completion list when the query finishes + connect(m_pCscope, SIGNAL(finished(uint)), this, + SLOT(slotQueryFinished(uint))); + + // Initiate automatic symbol completion when timer expires + connect(m_pAutoCompTimer, SIGNAL(timeout()), this, + SLOT(slotAutoCompleteTimeout())); +} + +/** + * Class destructor. + */ +SymbolCompletion::~SymbolCompletion() +{ + delete m_pCscope; +} + +/** + * Stops a completion process. + * This includes killing a running query, and stoping the auto-completion + * timer. + */ +void SymbolCompletion::abort() +{ + if (m_pCscope->isRunning()) + m_pCscope->kill(); + + m_pAutoCompTimer->stop(); +} + +/** + * Configures auto-completion parameters. + * @param bEnabled true to enable auto-completion, false otherwise + * @param nMinChars Minimal number of characters a symbol needs to start + * auto-completion + * @param nDelay Auto-completion time interval (in milliseconds) + * @param nMaxEntries The maximal number of completion entries + */ +void SymbolCompletion::initAutoCompletion(bool bEnabled, uint nMinChars, + uint nDelay, uint nMaxEntries) +{ + s_bACEnabled = bEnabled; + s_nACMinChars = nMinChars; + s_nACDelay = nDelay; + s_nACMaxEntries = nMaxEntries; +} + +/** + * Starts a completion process immediately for the symbol currently under the + * cursor in the editor object. + * Symbol completion is only available if the cursor is positioned at the end + * of the symbol. + */ +void SymbolCompletion::slotComplete() +{ + QString sSymbol; + uint nPosInWord; + + // Read the symbol currently under the cursor + sSymbol = m_pEditor->getWordUnderCursor(&nPosInWord); + + // The completion was triggered by user + m_bAutoCompletion = false; + + // start completion process, prefix is only on the left from the cursor + complete(sSymbol.left(nPosInWord)); +} + +/** + * Initiates an auto-completion timer. + * When the timer times-out, is starts the symbol completion process. + */ +void SymbolCompletion::slotAutoComplete() +{ + if (s_bACEnabled) + m_pAutoCompTimer->start(s_nACDelay, true); +} + +/** + * Creates a list of possible completions to the symbol currently being + * edited. + * @param sPrefix The symbol to complete + * @param nMaxEntries The maximal number of entries to display + */ +void SymbolCompletion::complete(const QString& sPrefix, int nMaxEntries) +{ + // Create a regular expression to extract symbol names from the query + // results + m_reSymbol.setPattern(sPrefix + "[a-zA-Z0-9_]*"); + + // If the new prefix is itself a prefix of the old one, we only need to + // filter the current entries + if (!m_sPrefix.isEmpty() && sPrefix.startsWith(m_sPrefix)) { + filterEntries(); + m_sPrefix = sPrefix; + slotQueryFinished(0); + return; + } + + // Prepare member variables + m_sPrefix = sPrefix; + m_nMaxEntries = nMaxEntries; + m_elEntries.clear(); + + // Run the code-completion query + m_pCscope->query(CscopeFrontend::Definition, sPrefix + ".*"); +} + +/** + * Removes from the current completion list all symbols that do not match + * the current regular expression. + * This function is used to aviod requerying the database on certain + * situations. + */ +void SymbolCompletion::filterEntries() +{ + EntryList::Iterator itr; + + // Iterate over the list and check each entry against the current RE + for (itr = m_elEntries.begin(); itr != m_elEntries.end();) { + if (m_reSymbol.search((*itr).text) == -1) + itr = m_elEntries.erase(itr); + else + ++itr; + } +} + +/** + * Conevrts the completion list into a single-entry one, containing the given + * message. + * @param sMsg The text of the message to include in the list. + */ +void SymbolCompletion::makeErrMsg(const QString& sMsg) +{ + Entry entry; + + // Clear the current list + m_elEntries.clear(); + + // Create the message item and add it to the list + entry.text = sMsg; + entry.userdata = "NO_INSERT"; // The message should not be insertable + m_elEntries.append(entry); + + // Make sure a new completion request will start a new query + m_sPrefix = ""; +} + +/** + * Creates a new entry in the list when a query record is available. + * This slot is connected to the dataReady() signal of the CscopeFrontend + * object. + * @param pToken Points to the head of a record's linked-list + */ +void SymbolCompletion::slotAddEntry(FrontendToken* pToken) +{ + Entry entry; + QString sText; + + // Do not add entries beyond the requested limit + if (m_elEntries.count() > m_nMaxEntries) + return; + + // Get the line text + pToken = pToken->getNext()->getNext()->getNext(); + sText = pToken->getData(); + + // Find the symbol within the line + if (m_reSymbol.search(sText) == -1) + return; + + // Add the new entry to the completion list + entry.text = m_reSymbol.capturedTexts().first(); + entry.userdata = ""; + entry.comment = sText; + + m_elEntries.append(entry); +} + +/** + * Displays a code completion list, based on the results of the last query. + * @param nRecords (ingnored) + */ +void SymbolCompletion::slotQueryFinished(uint /* nRecords */) +{ + KTextEditor::CodeCompletionInterface* pCCI; + uint nEntryCount; + EntryList::Iterator itr; + QString sPrevText; + + // Get the number of entries + nEntryCount = m_elEntries.count(); + + // Do not show the box the only completion option is the prefix itself + if (m_bAutoCompletion && (nEntryCount == 1) && + (m_elEntries.first().text == m_sPrefix)) { + return; + } + + // Get a pointer to the CC interface + m_pCCObject = m_pEditor->getCCObject(); + pCCI = dynamic_cast<KTextEditor::CodeCompletionInterface*>(m_pCCObject); + if (!pCCI) + return; + + // Insert the correct part of the completed symbol, when chosen by the + // user + connect(m_pCCObject, + SIGNAL(filterInsertString(KTextEditor::CompletionEntry*, QString*)), + this, + SLOT(slotFilterInsert(KTextEditor::CompletionEntry*, QString*))); + + // Check the number of entries in the list + if (nEntryCount == 0) { + // No completion options, display an appropriate message + makeErrMsg(i18n("No matching completion found...")); + } + else if (nEntryCount > m_nMaxEntries) { + // The query has resulted in too many entries, display an + // appropriate message + makeErrMsg(i18n("Too many options...")); + } + else { + // Sort the entries + m_elEntries.sort(); + + // Make sure entries are unique + for (itr = m_elEntries.begin(); itr != m_elEntries.end();) { + if ((*itr).text == sPrevText) { + itr = m_elEntries.erase(itr); + } + else { + sPrevText = (*itr).text; + ++itr; + } + } + } + + // Display the completion list + pCCI->showCompletionBox(m_elEntries); +} + +/** + * Determines which part of the completion entry should be added to the code + * when that entry is selected. + * @param pEntry Points to the selected entry + * @param pTextToInsert Contains the string to insert, upon return + */ +void SymbolCompletion::slotFilterInsert(KTextEditor::CompletionEntry* pEntry, + QString* pTextToInsert) +{ + // Insert the completed entry, unless it contains an error message + if (pEntry->userdata.isEmpty()) + *pTextToInsert = pEntry->text.mid(m_sPrefix.length()); + else + *pTextToInsert = ""; + + // Disconnect the CC object signals + disconnect(m_pCCObject, 0, this, 0); + m_pCCObject = NULL; +} + +/** + * Checks if the current symbol is eligible for auto-completion, and if so, + * starts the completion process. + * Auto-completion is performed for symbols that have the required minimal + * number of entries, and the cursor is positioned at the end of the word. + * This slot is connected to the timeout() signal of the auto-completion + * timer. + */ +void SymbolCompletion::slotAutoCompleteTimeout() +{ + QString sPrefix; + uint nPosInWord, nLength; + + // Read the symbol currently under the cursor + sPrefix = m_pEditor->getWordUnderCursor(&nPosInWord); + nLength = sPrefix.length(); + + // Check conditions, and start the completion process + if ((nLength >= s_nACMinChars) && (nPosInWord == nLength)) { + // The completion was triggered by auto-completion + m_bAutoCompletion = true; + complete(sPrefix, s_nACMaxEntries); + } +} + +#include "symbolcompletion.moc" diff --git a/src/symbolcompletion.h b/src/symbolcompletion.h new file mode 100644 index 0000000..6fe57e2 --- /dev/null +++ b/src/symbolcompletion.h @@ -0,0 +1,195 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef SYMBOLCOMPLETION_H +#define SYMBOLCOMPLETION_H + +#include <qobject.h> +#include <qregexp.h> +#include <ktexteditor/codecompletioninterface.h> +#include <ktexteditor/view.h> +#include "cscopefrontend.h" + +/** + * This class executes symbol definition queries based on symbol prefixes. + * The results can then be displayed as symbol completion lists. + * @author Albert Yosher + */ +class SymbolCompletion : public QObject +{ + Q_OBJECT + +public: + /** + * A pure-virtual class that allows a SymbolCompletion object access to + * text-editing objects. + * Classes that wish to utilise SymbolCompletion need to inplement this + * interface. + * @author Albert Yosher + */ + struct Interface + { + /** + * Class destructor. + * NOTE: A virtual destructor is required by GCC 4.0 + */ + virtual ~Interface() {} + + /** + * Returns the word currently under the editing cursor. + * Symbol completion will be provided for this word only if the cursor + * is positioned at the end of this word. + * @param pPosInWord Set this value to the offset in the word on + * which the cursor is positioned + */ + virtual QString getWordUnderCursor(uint* pPosInWord) = 0; + + /** + * Returns a target object for displaying the completion list. + * @return A pointer to an object implementing + * KTextEditor::CodeCompletionInterface, or NULL if the + * implementation does not support this interface. + */ + virtual QObject* getCCObject() = 0; + }; + + SymbolCompletion(SymbolCompletion::Interface*, QObject* pParent = 0, + const char* szName = 0); + ~SymbolCompletion(); + + void abort(); + + static void initAutoCompletion(bool, uint, uint, uint); + +public slots: + void slotComplete(); + void slotAutoComplete(); + +private: + /** + * Symbol completion entry object, used in the completion list. + * Implements operators required for sorting the completion list. + * @author Albert Yosher + */ + class Entry : public KTextEditor::CompletionEntry + { + public: + /** + * Determines whether a given entry is smaller than this one. + * @param entry The entry to compare with + * @return true if the given entry is smaller, false otherwise + */ + bool operator < (const SymbolCompletion::Entry& entry) const { + return (text < entry.text); + } + + /** + * Determines whether a given entry is equal to this one. + * @param entry The entry to compare with + * @return true if the given entry equals this one, false otherwise + */ + bool operator == (const SymbolCompletion::Entry& entry) const { + return (text == entry.text); + } + }; + + /** + * A sortable version of the value list used by CodeCompletionInterface. + * @author Albert Yosher + */ + class EntryList : public QValueList<Entry> + { + public: + /** + * Sorts completion list. + */ + void sort() { qHeapSort(*this); } + + /** + * Type casting support required for calling showCompletionBox(). + * @return A casted reference to this object + */ + operator QValueList<KTextEditor::CompletionEntry>() + { return *(QValueList<KTextEditor::CompletionEntry>*)this; } + }; + + /** Editor object for which symbol completion is provided. */ + Interface* m_pEditor; + + /** An object that supports KTextEditor::CodeCompletionInterface, as + supplied by the editor. */ + QObject* m_pCCObject; + + /** Cscope process used to run completion queries. */ + CscopeFrontend* m_pCscope; + + /** The prefix used for the current query. */ + QString m_sPrefix; + + /** A list of possible completions for the given prefix. */ + EntryList m_elEntries; + + /** The maximal number of completions to accept. */ + uint m_nMaxEntries; + + /** Regular expression for extracting a symbol out of Cscope's text field. + NOTE: This member is required due to a bug in Cscope that renders the + symbol field useless. */ + QRegExp m_reSymbol; + + /** Auto-completion timer. */ + QTimer* m_pAutoCompTimer; + + /** Auto-completion flag */ + bool m_bAutoCompletion; + + void complete(const QString&, int nMaxEntries = 1000); + void filterEntries(); + void makeErrMsg(const QString&); + + /** true if auto-completion is enabled, false otherwise. */ + static bool s_bACEnabled; + + /** The minimum number of characters a symbol must have for + auto-completion. */ + static uint s_nACMinChars; + + /** The interval between the time slotAutoComplete() is called and the + time the completion process begins (in milliseconds). */ + static uint s_nACDelay; + + /** The maximal number of entries for auto-completion. */ + static uint s_nACMaxEntries; + +private slots: + void slotAutoCompleteTimeout(); + void slotAddEntry(FrontendToken*); + void slotQueryFinished(uint); + void slotFilterInsert(KTextEditor::CompletionEntry*, QString*); +}; + +#endif diff --git a/src/symboldlg.cpp b/src/symboldlg.cpp new file mode 100644 index 0000000..3301678 --- /dev/null +++ b/src/symboldlg.cpp @@ -0,0 +1,334 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qlabel.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <kcombobox.h> +#include <klocale.h> +#include "symboldlg.h" +#include "cscopefrontend.h" +#include "kscopeconfig.h" + +QStringList SymbolDlg::s_slHistory; + +/** + * Class constructor. + * @param pParent Parent widget + * @param szName This widget's name + */ +SymbolDlg::SymbolDlg(QWidget* pParent, const char* szName) : + SymbolLayout(pParent, szName, true, 0), + m_progress(m_pHintList) +{ + // Create a persistent Cscope process + m_pCscope = new CscopeFrontend(); + + // Initialise the hint list (hidden by default) + m_pHintList->addColumn(i18n("Suggested Symbols")); + m_pHintList->hide(); + ((QWidget*)m_pHintGroup)->hide(); + m_pBeginWithRadio->toggle(); + adjustSize(); + + // Close the dialogue when either the "OK" or "Cancel" button are clicked + connect(m_pOKButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + // Run a symbol completion query when the "Hint" button is clicked + connect(m_pHintButton, SIGNAL(clicked()), this, SLOT(slotHintClicked())); + + // Add results to the hint list + connect(m_pCscope, SIGNAL(dataReady(FrontendToken*)), this, + SLOT(slotHintDataReady(FrontendToken*))); + + // Set hint button availability based on the type of query + connect(m_pTypeCombo, SIGNAL(activated(int)), this, + SLOT(slotTypeChanged(int))); + + // Selecting an item in the hint list sets it as the current text + connect(m_pHintList, SIGNAL(selectionChanged(QListViewItem*)), this, + SLOT(slotHintItemSelected(QListViewItem*))); + + // Double-clicking an item in the hint list accepts that item as the + // result of the query (i.e., the item is selcted and the dialogue is + // closed) + connect(m_pHintList, SIGNAL(doubleClicked(QListViewItem*)), this, + SLOT(accept())); + + // Refresh the hint list when the hint options change + connect(m_pBeginWithRadio, SIGNAL(toggled(bool)), this, + SLOT(slotHintOptionChanged(bool))); + connect(m_pContainRadio, SIGNAL(toggled(bool)), this, + SLOT(slotHintOptionChanged(bool))); + + // Show hint query progress information + connect(m_pCscope, SIGNAL(progress(int, int)), this, + SLOT(slotHintProgress(int, int))); + connect(m_pCscope, SIGNAL(finished(uint)), this, + SLOT(slotHintFinished(uint))); +} + +/** + * Class destructor. + */ +SymbolDlg::~SymbolDlg() +{ + delete m_pCscope; +} + +/** + * Displays the requested type of query in the type combo-box. + * @param nType The requested type + */ +void SymbolDlg::setType(uint nType) +{ + m_pTypeCombo->setCurrentItem(nType); + slotTypeChanged(nType); +} + +/** + * @param sSymbol The initial text of the combo-box + */ +void SymbolDlg::setSymbol(const QString& sSymbol) +{ + m_pSymbolHC->setCurrentText(sSymbol); +} + +/** + * @param slSymHistory A list of previously queried symbols + */ +void SymbolDlg::setHistory(QStringList& slSymHistory) +{ + m_pSymbolHC->setHistoryItems(slSymHistory); +} + +/** + * @return The current text of the symbol combo-box + */ +QString SymbolDlg::getSymbol() const +{ + QString sResult; + + sResult = m_pSymbolHC->currentText().stripWhiteSpace(); + if (m_pSubStringCheck->isChecked()) + sResult = ".*" + sResult + ".*"; + + return sResult; +} + +/** + * @return The type of query requested by the user + * @note The returned value does not conform to the type used for running + * Cscope queries. Use getQueryType() to translate between these + * values. + */ +uint SymbolDlg::getType() const +{ + return m_pTypeCombo->currentItem(); +} + +bool SymbolDlg::getCase() const +{ + return !m_pCaseCheck->isChecked(); +} + +/** + * A convinience static function for creating and showing SymbolDlg dialogue. + * @param pParent The parent widget + * @param nType The type of query requested by the user (may be + * changed in the dialogue) + * @param sSymbol The initial text of the combo-box + * @return The text entered by the user in the symbol combo-box, or an empty + * string if the dialogue was cancelled + */ +QString SymbolDlg::promptSymbol(QWidget* pParent, uint& nType, + const QString& sSymbol, bool& bCase) +{ + SymbolDlg dlg(pParent); + + // Initialise the dialogue + dlg.setType(nType); + dlg.setHistory(s_slHistory); + dlg.setSymbol(sSymbol); + + // Display the dialogue + if (dlg.exec() != QDialog::Accepted) + return ""; + + // Return the text entered by the user + nType = dlg.getType(); + bCase = dlg.getCase(); + dlg.m_pSymbolHC->addToHistory(dlg.getSymbol()); + s_slHistory = dlg.m_pSymbolHC->historyItems(); + return dlg.getSymbol(); +} + +/** + * Translates a symbol dialogue type into a Cscope query type. + * @param nType The type to translate + * @return A query type matching the symbol dialogue type + */ +uint SymbolDlg::getQueryType(uint nType) +{ + if (nType == CallTree) + return CscopeFrontend::None; + + if (nType <= Text) + return nType; + + return nType + 1; +} + +/** + * Runs a symbol definition query, looking for symbols starting with the + * currently entered text. + * If the hint list is not visible, it is shown first. + * This slot is connected to the clicked() signal of the "Hint" button. + */ +void SymbolDlg::slotHintClicked() +{ + QString sText, sRegExp; + + // Show the hint list if necessary + if (!m_pHintList->isVisible()) { + m_pHintList->show(); + ((QWidget*)m_pHintGroup)->show(); + adjustSize(); + } + + // Clear the previous contents + m_pHintList->clear(); + + // Get the currently entered text (must have at least one character) + sText = m_pSymbolHC->currentText().stripWhiteSpace(); + if (sText.isEmpty()) + return; + + // Create the regular expression + if (m_pBeginWithRadio->isOn()) + sRegExp = sText + "[a-zA-Z0-9_]*"; + else + sRegExp = "[a-zA-Z0-9_]*" + sText + "[a-zA-Z0-9_]*"; + + m_reHint.setPattern(sRegExp); + + // Run a Cscope symbol definition query using a regular expression + m_pCscope->query(CscopeFrontend::Definition, sRegExp); +} + +/** + * Called when a new record is ready to be added to the hint list. + * NOTE: Cscope 15.5 has a bug where the "function" field of the record + * displays the regular expression instead of the matched symbol name. For + * this reason, we need to extract the symbol from the "Text" field. + * @param pToken The head of the record's token list + */ +void SymbolDlg::slotHintDataReady(FrontendToken* pToken) +{ + QString sText; + + // Get the line text + pToken = pToken->getNext()->getNext()->getNext(); + sText = pToken->getData(); + + // Find the symbol within the line + if (m_reHint.search(sText) == -1) + return; + + // Find the symbol within the list, if found - do not add + if (m_pHintList->findItem(m_reHint.capturedTexts().first(), 0)) + return; + + // Add a list item + (void)new QListViewItem(m_pHintList, m_reHint.capturedTexts().first()); + +} + +/** + * Sets the text of a selected hint list item as the current text of the + * symbol combo-box. + * This slot is connected to the doubleClicked() signal of the hint list-view. + * @param pItem The clicked list item + */ +void SymbolDlg::slotHintItemSelected(QListViewItem* pItem) +{ + m_pSymbolHC->setCurrentText(pItem->text(0)); +} + +/** + * Refreshes the hint list based on the newly selected option. + * This slot is connected to the toggled() signal of the hint options radio + * buttons. + * NOTE: The list is only refreshed if the system profile is set to Fast. + * @param bOn true if the button was toggled on + */ +void SymbolDlg::slotHintOptionChanged(bool bOn) +{ + if (bOn && Config().getSysProfile() == KScopeConfig::Fast) + slotHintClicked(); +} + +/** + * Display a progress bar while the hint query is working. + * This slot is connected to the progress() signal emitted by the Cscope + * frontend object. + * @param nProgress Progress value + * @param nTotal The final expected value + */ +void SymbolDlg::slotHintProgress(int nProgress, int nTotal) +{ + m_progress.setProgress(nProgress, nTotal); +} + +/** + * Destroys all progress information widget when the query process terminates. + * This slot is connected to the finished() signal emitted by the Cscope + * process. + */ +void SymbolDlg::slotHintFinished(uint /* ignored */) +{ + m_progress.finished(); +} + +/** + * Enables/disables the hint button, based on the newly selected type. + * This slot is connected to the activated() signal of the type combo-box. + * @param nType The newly selected type + */ +void SymbolDlg::slotTypeChanged(int nType) +{ + if (nType == FileName || nType == Including) + m_pHintButton->setEnabled(false); + else + m_pHintButton->setEnabled(true); +} + +#include "symboldlg.moc" diff --git a/src/symboldlg.h b/src/symboldlg.h new file mode 100644 index 0000000..4360213 --- /dev/null +++ b/src/symboldlg.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef SYMBOLDLG_H +#define SYMBOLDLG_H + +#include <qregexp.h> +#include "symbollayout.h" +#include "cscopefrontend.h" + +/** + * A dialogue that prompts the user for the text of a query. + * When a query is requested, the user needs to fill in the required + * information (usually a symbol name). This dialogue allows the user to + * enter this information, as well as complete a symbol name, and use + * previously entered text. + * @author Elad Lahav + */ + +class SymbolDlg : public SymbolLayout +{ + Q_OBJECT + +public: + SymbolDlg(QWidget* pParent = 0, const char* szName = 0); + ~SymbolDlg(); + + enum { Reference = 0, Definition, Called, Calling, Text, Pattern, + FileName, Including, CallTree }; + + void setType(uint); + void setSymbol(const QString&); + void setHistory(QStringList&); + QString getSymbol() const; + uint getType() const; + bool getCase() const; + + static QString promptSymbol(QWidget*, uint&, const QString&, bool&); + static uint getQueryType(uint); + static void resetHistory() { s_slHistory.clear(); } + +private: + /** A cscope process used for symbol completion. */ + CscopeFrontend* m_pCscope; + + /** A regular expression for extracting the symbol name out of the text + token of a Cscope record. + @see note in slotHintDataReady(). */ + QRegExp m_reHint; + + /** Displays query progress information. */ + CscopeProgress m_progress; + + static QStringList s_slHistory; + +private slots: + void slotHintClicked(); + void slotHintDataReady(FrontendToken*); + void slotHintItemSelected(QListViewItem*); + void slotHintOptionChanged(bool); + void slotHintProgress(int, int); + void slotHintFinished(uint); + void slotTypeChanged(int); +}; + +#endif + diff --git a/src/symbollayout.ui b/src/symbollayout.ui new file mode 100644 index 0000000..09b2885 --- /dev/null +++ b/src/symbollayout.ui @@ -0,0 +1,297 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SymbolLayout</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SymbolLayout</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>343</width> + <height>456</height> + </rect> + </property> + <property name="caption"> + <string>KScope Query</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Type</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Symbol</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>References to</string> + </property> + </item> + <item> + <property name="text"> + <string>Definition of</string> + </property> + </item> + <item> + <property name="text"> + <string>Functions called by</string> + </property> + </item> + <item> + <property name="text"> + <string>Functions calling</string> + </property> + </item> + <item> + <property name="text"> + <string>Find text</string> + </property> + </item> + <item> + <property name="text"> + <string>Find EGrep pattern</string> + </property> + </item> + <item> + <property name="text"> + <string>Find file</string> + </property> + </item> + <item> + <property name="text"> + <string>Files #including</string> + </property> + </item> + <item> + <property name="text"> + <string>Call graph for</string> + </property> + </item> + <property name="name"> + <cstring>m_pTypeCombo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KHistoryCombo"> + <property name="name"> + <cstring>m_pSymbolHC</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="insertionPolicy"> + <enum>AtTop</enum> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pSubStringCheck</cstring> + </property> + <property name="text"> + <string>Search for &a Sub-String</string> + </property> + <property name="accel"> + <string>Alt+A</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_pCaseCheck</cstring> + </property> + <property name="text"> + <string>Case Insensitive</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>71</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pOKButton</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pHintButton</cstring> + </property> + <property name="text"> + <string>Hi&nt</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCancelButton</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QListView"> + <property name="name"> + <cstring>m_pHintList</cstring> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>m_pHintGroup</cstring> + </property> + <property name="title"> + <string>Hint Options</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_pBeginWithRadio</cstring> + </property> + <property name="text"> + <string>S&ymbols Beginning With...</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>m_pContainRadio</cstring> + </property> + <property name="text"> + <string>Sym&bols Containing...</string> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>m_pSymbolHC</tabstop> + <tabstop>m_pTypeCombo</tabstop> + <tabstop>m_pSubStringCheck</tabstop> + <tabstop>m_pOKButton</tabstop> + <tabstop>m_pHintButton</tabstop> + <tabstop>m_pCancelButton</tabstop> + <tabstop>m_pHintList</tabstop> + <tabstop>m_pBeginWithRadio</tabstop> + <tabstop>m_pContainRadio</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/src/tab_list.png b/src/tab_list.png Binary files differnew file mode 100644 index 0000000..b0cb478 --- /dev/null +++ b/src/tab_list.png diff --git a/src/tabwidget.cpp b/src/tabwidget.cpp new file mode 100644 index 0000000..2795a84 --- /dev/null +++ b/src/tabwidget.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include <qtooltip.h> +#include <klocale.h> +#include "tabwidget.h" +#include "kscopepixmaps.h" + +/** + * Class constructor. + * @param pParent A pointer to the parent widget + * @param szName Optional widget name + */ +TabWidget::TabWidget(QWidget* pParent, const char* szName) : + KTabWidget(pParent, szName) +{ + // Create a popup menu + m_pMenu = new QPopupMenu(this); + + // Set the current tab based on the menu selection + connect(m_pMenu, SIGNAL(activated(int)), this, SLOT(setCurrentPage(int))); + + // Create a button at the top-right corner of the tab widget + m_pButton = new QToolButton(this); + m_pButton->setIconSet(Pixmaps().getPixmap(KScopePixmaps::TabList)); + QToolTip::add(m_pButton, i18n("Shows a list of all open tabs")); + m_pButton->adjustSize(); + setCornerWidget(m_pButton, TopRight); + + // Show the popup-menu when the button is clicked + connect(m_pButton, SIGNAL(clicked()), this, SLOT(slotShowTabList())); +} + +/** + * Class destructor. + */ +TabWidget::~TabWidget() +{ +} + +/** + * Creates and displays a popup-menu containing all tab labels. + * This slot is connected to the clicked() signal emitted by the list button. + */ +void TabWidget::slotShowTabList() +{ + int i; + + // Delete the previous menu + m_pMenu->clear(); + + // Create and populate the menu + for (i = 0; i < count(); i++) + m_pMenu->insertItem(label(i), i); + + // Show the menu + m_pMenu->popup(mapToGlobal(m_pButton->pos())); +} + +#include "tabwidget.moc" diff --git a/src/tabwidget.h b/src/tabwidget.h new file mode 100644 index 0000000..74672ae --- /dev/null +++ b/src/tabwidget.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef TABWIDGET_H +#define TABWIDGET_H + + +#include <qtoolbutton.h> +#include <qpopupmenu.h> +#include <ktabwidget.h> + +/** + * An extension to the standard KDE tab widget that allows the user to select + * a tab from a list displayed as a popup menu. + * @author Elad Lahav + */ +class TabWidget : public KTabWidget +{ +Q_OBJECT +public: + TabWidget(QWidget* pParent = 0, const char* szName = 0); + ~TabWidget(); + +private: + /** The list button. */ + QToolButton* m_pButton; + + /** A popup-menu containing all tab labels. */ + QPopupMenu* m_pMenu; + +private slots: + void slotShowTabList(); +}; + +#endif diff --git a/src/treewidget.cpp b/src/treewidget.cpp new file mode 100644 index 0000000..b303194 --- /dev/null +++ b/src/treewidget.cpp @@ -0,0 +1,260 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#include "treewidget.h" +#include "queryviewdriver.h" + +/** + * Class constructor. + * @param pParent Parent widget + * @param szName The name of the widget + */ +TreeWidget::TreeWidget(QWidget* pParent, const char* szName) : + QueryView(pParent, szName), + m_nQueryType(CscopeFrontend::Called) +{ + setRootIsDecorated(true); + + // Create a driver object + m_pDriver = new QueryViewDriver(this, this); + + // Query a tree item when it is expanded for the first time + connect(this, SIGNAL(expanded(QListViewItem*)), this, + SLOT(slotQueryItem(QListViewItem*))); +} + +/** + * Class destructor. + */ +TreeWidget::~TreeWidget() +{ +} + +/** + * Determines the mode of the tree. + * @param mode The new mode (@see Mode) + */ +void TreeWidget::setMode(Mode mode) +{ + m_nQueryType = (mode == Called) ? CscopeFrontend::Called : + CscopeFrontend::Calling; +} + +/** + * Sets a new root item for the tree. + * @param sFunc The name of the function to serve as root + */ +void TreeWidget::setRoot(const QString& sFunc) +{ + QListViewItem* pRoot; + + // Remove the current root, if any + if ((pRoot = firstChild()) != NULL) + delete pRoot; + + // Create a new root item + pRoot = new QListViewItem(this, sFunc); + pRoot->setExpandable(true); +} + +/** + * Runs a query on the root item. + */ +void TreeWidget::queryRoot() +{ + QListViewItem* pRoot; + + if ((pRoot = firstChild()) != NULL) + slotQueryItem(pRoot); +} + +/** + * Stores the tree contents in the given file. + * @param pFile An open file to write to + */ +void TreeWidget::save(FILE* pFile) +{ + QTextStream str(pFile, IO_WriteOnly); + QListViewItem* pRoot; + Encoder enc; + + if (m_nQueryType == CscopeFrontend::Called) + str << "calltree {" << endl; + else + str << "callingtree {" << endl; + + // Write the tree to the file + pRoot = firstChild(); + str << pRoot->text(0) << endl; + str << '{' << endl; + saveItems(pRoot->firstChild(), str, enc); + str << '}' << endl; + str << '}' << endl; +} + +/** + * Recursively writes tree items to a file. + * Given an item, the method writes this item and all of its siblings. + * Child items are written recursively. + * @param pItem The first item to write + * @param str An initialised text stream to use for writing + * @param enc An encoder for free-text strings + */ +void TreeWidget::saveItems(QListViewItem* pItem, QTextStream& str, Encoder& enc) +{ + // Iterate over all items in this level + for (; pItem != NULL; pItem = pItem->nextSibling()) { + // Write function parameters + str << pItem->text(0) << " [ " + << "kscope_file=\"" << pItem->text(1) << "\", " + << "kscope_line=" << pItem->text(2) << ", " + << "kscope_text=\"" << enc.encode(pItem->text(3)) << "\"" + << "]" << endl; + + // Write child items + str << "{" << endl; + saveItems(pItem->firstChild(), str, enc); + str << "}" << endl; + } +} + +/** + * Creates a new tree item showing a query result record. + * @param sFunc The name of the function + * @param sFile The file path + * @param sLine The line number in the above file + * @param sText The line's text + * @param pParent The parent for the new item + */ +void TreeWidget::addRecord(const QString& sFunc, const QString& sFile, + const QString& sLine, const QString& sText, QListViewItem* pParent) +{ + QListViewItem* pItem; + + pItem = new QueryViewItem(pParent, m_pLastItem, 2); + pItem->setText(0, sFunc); + pItem->setText(1, sFile); + pItem->setText(2, sLine); + pItem->setText(3, sText); + + pItem->setExpandable(true); + m_pLastItem = pItem; +} + +/** + * Called when a query running on the tree terminates. + * If there were no results, the item becomes non-expandable. + * NOTE: On top of its current behaviour, this function is required in order to + * override the default behaviour, as specified by QueryView. + * @param nResults Number of results + * @param pParent The item for which the query was executed + */ +void TreeWidget::queryFinished(uint nResults, QListViewItem* pParent) +{ + if (nResults == 0) + pParent->setExpandable(false); + else + pParent->setOpen(true); +} + +/** + * Runs a query on the given item, unless it was queried before. + * This slot is connected to the expanded() signal of the list view. + * @param pItem The item to query + */ +void TreeWidget::slotQueryItem(QListViewItem* pItem) +{ + // Do nothing if the item was already queried + // An item has been queried if it has children or marked as non-expandable + if (pItem->firstChild() != NULL || !pItem->isExpandable()) + return; + + // Run the query + m_pDriver->query(m_nQueryType, pItem->text(0), true, pItem); +} + +/** + * Hides all descendant that do not meet the given search criteria. + * This slot is connected to the search() signal of the QueryResultsMenu + * object. + * The search is incremental: only visible items are checked, so that a new + * search goes over the results of the previous one. + * @param pParent The parent item whose child are searched + * @param re The pattern to search + * @param nCol The list column to search in + */ +void TreeWidget::slotSearch(QListViewItem* pParent, const QRegExp& re, + int nCol) +{ + QListViewItem* pItem; + + // Get the first child + if (pParent != NULL) + pItem = pParent->firstChild(); + else + pItem = firstChild(); + + // Iterate over all child items + while (pItem != NULL) { + // Filter visible items only + if (pItem->isVisible() && re.search(pItem->text(nCol)) == -1) + pItem->setVisible(false); + + // Search child items recursively + slotSearch(pItem, re, nCol); + + pItem = pItem->nextSibling(); + } +} + +/** + * Makes all descendants of the given item visible. + * This slot is connected to the showAll() signal of the QueryResultsMenu + * object. + */ +void TreeWidget::slotShowAll(QListViewItem* pParent) +{ + QListViewItem* pItem; + + // Get the first child + if (pParent != NULL) + pItem = pParent->firstChild(); + else + pItem = firstChild(); + + // Iterate over all child items + while (pItem != NULL) { + pItem->setVisible(true); + + // Show child items recursively + slotShowAll(pItem); + + pItem = pItem->nextSibling(); + } +} + +#include "treewidget.moc" diff --git a/src/treewidget.h b/src/treewidget.h new file mode 100644 index 0000000..57c2a98 --- /dev/null +++ b/src/treewidget.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * + * Copyright (C) 2005 Elad Lahav (elad_lahav@users.sourceforge.net) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +#ifndef TREEWIDGET_H +#define TREEWIDGET_H + +#include "queryview.h" +#include "encoder.h" + +class QueryViewDriver; + +/** + * A tree-like widget displaying a hierarchical list of functions. + * The widget has two modes: called functions and calling functions. Depending + * on this mode, child items represent functions called by or calling their + * parent item. + * @author Elad Lahav + */ +class TreeWidget : public QueryView +{ + Q_OBJECT + +public: + TreeWidget(QWidget* pParent = 0, const char* szName = 0); + ~TreeWidget(); + + /** + * The type of tree to display. + */ + enum Mode { Called, Calling }; + + void setMode(Mode); + void setRoot(const QString&); + void queryRoot(); + void save(FILE*); + + virtual void addRecord(const QString&, const QString&, const QString&, + const QString&, QListViewItem*); + virtual void queryFinished(uint, QListViewItem*); + +protected slots: + virtual void slotSearch(QListViewItem*, const QRegExp&, int); + virtual void slotShowAll(QListViewItem*); + +private: + /** The CscopeFrontend query type to use (based on the current mode). */ + uint m_nQueryType; + + /** Runs queries and outputs the results as tree items. */ + QueryViewDriver* m_pDriver; + + void saveItems(QListViewItem*, QTextStream&, Encoder&); + +private slots: + void slotQueryItem(QListViewItem*); +}; + +#endif diff --git a/src/welcomedlg.ui b/src/welcomedlg.ui new file mode 100644 index 0000000..44c385c --- /dev/null +++ b/src/welcomedlg.ui @@ -0,0 +1,126 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>WelcomeDlg</class> +<widget class="QDialog"> + <property name="name"> + <cstring>WelcomeDlg</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>519</width> + <height>386</height> + </rect> + </property> + <property name="caption"> + <string>Welcome</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KTextBrowser"> + <property name="name"> + <cstring>m_pBrowser</cstring> + </property> + <property name="paletteBackgroundColor"> + <color> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </property> + <property name="text"> + <string><h1>Welcome to <font color="#c00000">KScope</font>!</h1> + +If this is the first time you are running Kscope, please follow these steps (click on the links for detailed instructions): +<p> +1. <a href="help:/kscope/configuration.html#config-progs">Configure</a> paths to the required back-end executables<br> +2. <a href="help:/kscope/projects.html#project-create">Create</a> a new project<br> +3. <a href="help:/kscope/projects.html#project-files">Populate</a> the project with source files<br> +4. <a href="help:/kscope/queries.html">Browse</a> the project and <a href="help:/kscope/editing.html">edit</a> files<br> + +</p> + +<p> +For more information, please take a look at KScope's <a href="help:/kscope">manual</a>, or visit the KScope <a href="http://kscope.sourceforge.net">website</a>. +</p> + +<p> +Enjoy! +</p> + +<p> +<font size="-1">This message will only appear once. Use the "<b>Help->Show Welcome Message...</b>" menu command to show it again at any time.</font> +</p></string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>381</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pCloseButton</cstring> + </property> + <property name="text"> + <string>Close</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_pCloseButton</sender> + <signal>clicked()</signal> + <receiver>WelcomeDlg</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>ktextbrowser.h</includehint> +</includehints> +</UI> diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1,3 @@ +doc +po +src diff --git a/templates/cpp b/templates/cpp new file mode 100644 index 0000000..adfe0fd --- /dev/null +++ b/templates/cpp @@ -0,0 +1,26 @@ +/*************************************************************************** + * + * Copyright (C) $YEAR$ $AUTHOR$ ($EMAIL$) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ diff --git a/templates/h b/templates/h new file mode 100644 index 0000000..adfe0fd --- /dev/null +++ b/templates/h @@ -0,0 +1,26 @@ +/*************************************************************************** + * + * Copyright (C) $YEAR$ $AUTHOR$ ($EMAIL$) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ |