Add author-abandoned basket application

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/basket@1072339 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
v3.5.13-sru
tpearson 15 years ago
commit f21e5792b5

@ -0,0 +1 @@
Sébastien Laoût <slaout@linux62.org>

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -0,0 +1,9 @@
To see the Changes log, please visit
http://basket.kde.org/changelog.php
To see which features will be implanted in the future versions,
please visit the roadmap on
http://basket.kde.org/roadmap.php
See it also to know the project status and other informations about
it.

@ -0,0 +1,249 @@
# Doxyfile 1.4.1-KDevelop
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = basket.kdevelop
PROJECT_NUMBER = 1.0.3.1
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
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 = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
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 = /home/seb/Programmation/basket
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,195 @@
/====================================\
| Quick Installation with the Wizard |
\====================================/
Quick Instructions
==================
The installation can easily be performed by launching the
./installer script in a terminal and by following the instructions.
Theire is nothing else to do.
More Information
================
In Konqueror, after having un-compressed the .tar.gz file containing
BasKet Note Pads, choose `Open a terminal' while in the un-compressed
folder (the same where you can read this file).
Then, type "./installer" (without the quotes) and press Enter.
You just have to follow the wizard.
The scrit is there just to simplify your life.
If it does not work or you if want more control (experienced users) on
the configure process, please read the following paragraphs.
/===================================\
| Standard UNIX Way of Installation |
\===================================/
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
Alternatively, 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.

@ -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,10 @@
all:
@echo "This Makefile is only for the CVS repository"
@echo "This will be deleted before making the distribution"
@echo ""
$(MAKE) -f admin/Makefile.common cvs
dist:
$(MAKE) -f admin/Makefile.common dist
.SILENT:

@ -0,0 +1 @@

@ -0,0 +1,42 @@
********************
* BasKet Note Pads *
********************
Purpose:
************
This application provide as many baskets as you wish, and you
can drag and drop various objects (text, URLs, images, sounds...)
into its.
Objects can be edited, copied, dragged... So, you can arrange them as
you want !
It's a DropDrawers clone
(http://www.sigsoftware.com/dropdrawers/index.html) for KDE 3.
If you want to contact me, please mail me at slaout@linux62.org
(I'm a french guy, if you prefer to speak french to me).
Project Status:
*******************
Visit the BasKet Note Pads website at :
http://basket.kde.org/
You can find screenshots of it at :
http://basket.kde.org/screenshots.php
For project status, please see the TODO file of this project at :
http://basket.kde.org/todo.php
You also can see the project roadmap for near versions planned
features at :
http://basket.kde.org/roadmap.php
See changes log at :
http://basket.kde.org/changelog.php
And finaly, new versions will be announced here :
http://basket.kde.org/news.php
If you want to be noticed of new versions, subscribe to the RSS feed,
available with explanations here:
http://basket.kde.org/rss.php
Install:
************
Please see the INSTALL file.

@ -0,0 +1,9 @@
To see the TODO List, please visit
http://basket.kde.org/todo.php
To see which features will be implanted in the future versions,
please visit the roadmap on
http://basket.kde.org/roadmap.php
See it also to know the project status and other informations about
it.

File diff suppressed because it is too large Load Diff

1266
aclocal.m4 vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
backgroundspreviewsdir = $(kde_datadir)/basket/backgrounds/previews
backgroundspreviews_DATA = \
abstract.png \
alien-artifact.png \
basket-title.png \
green-curves.png \
light.png \
painting.png \
pens.png \
pins.png \
rainbow-balls.png \
rounds-line.png \
strings.png \
todo.png \
working.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@ -0,0 +1,15 @@
backgroundsdir = $(kde_datadir)/basket/backgrounds
backgrounds_DATA = \
abstract.png \
alien-artifact.png alien-artifact.png.config \
basket-title.png \
green-curves.png \
light.png \
painting.png \
pens.png \
pins.png \
rainbow-balls.png \
rounds-line.png \
strings.png \
todo.png \
working.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

@ -0,0 +1,2 @@
[BasKet Background Image Configuration]
tiled = true

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

@ -0,0 +1 @@
S<EFBFBD>bastien Lao<61>t <slaout@linux62.org>

@ -0,0 +1,293 @@
<?xml version = '1.0'?>
<kdevelop>
<general>
<author>Sébastien Laoût</author>
<email>slaout@linux62.org</email>
<version>1.0.3.1</version>
<projectmanagement>KDevKDEAutoProject</projectmanagement>
<primarylanguage>C++</primarylanguage>
<keywords>
<keyword>C++</keyword>
<keyword>Code</keyword>
<keyword>Qt</keyword>
<keyword>KDE</keyword>
</keywords>
<projectdirectory>.</projectdirectory>
<absoluteprojectpath>false</absoluteprojectpath>
<description>Taking care of your ideas.</description>
<ignoreparts>
<part>kdevfileview</part>
<part>kdevfileselector</part>
</ignoreparts>
<secondaryLanguages/>
<versioncontrol>kdevsubversion</versioncontrol>
<projectname>basket</projectname>
<defaultencoding></defaultencoding>
</general>
<kdevautoproject>
<general>
<activetarget>src/basket</activetarget>
<useconfiguration>debug</useconfiguration>
</general>
<run>
<mainprogram>/home/seb/Programmation/basket/debug/src/.libs/basket</mainprogram>
<directoryradio>build</directoryradio>
<customdirectory>/</customdirectory>
<programargs>--nofork --use-drkonquy --data-folder ~/.kde/share/apps/basket-debug</programargs>
<terminal>false</terminal>
<autocompile>true</autocompile>
<envvars>
<envvar value="en_US" name="KDE_LANG" />
<envvar value="$HOME/kde-debug/lib:$LD_LIBRARY_PATH" name="LD_LIBRARY_PATH" />
<envvar value="$HOME/kde-debug:$PATH" name="PATH" />
</envvars>
<runarguments>
<basket/>
</runarguments>
<globaldebugarguments></globaldebugarguments>
<globalcwd>/home/seb/Programmation/basket/debug</globalcwd>
<useglobalprogram>true</useglobalprogram>
<autoinstall>false</autoinstall>
<autokdesu>false</autokdesu>
</run>
<configurations>
<optimized>
<builddir>optimized</builddir>
<ccompiler>GccOptions</ccompiler>
<cxxcompiler>GppOptions</cxxcompiler>
<f77compiler>G77Options</f77compiler>
<cxxflags>-O2 -g0</cxxflags>
</optimized>
<debug>
<configargs>--enable-debug=full --without-arts --prefix=$HOME/kde-debug</configargs>
<builddir>debug</builddir>
<ccompiler>kdevgccoptions</ccompiler>
<cxxcompiler>kdevgppoptions</cxxcompiler>
<f77compiler>kdevpgf77options</f77compiler>
<cxxflags>-O0 -g3</cxxflags>
<topsourcedir/>
<cppflags/>
<ldflags/>
<ccompilerbinary/>
<cxxcompilerbinary/>
<f77compilerbinary/>
<cflags/>
<f77flags/>
<envvars/>
</debug>
</configurations>
<make>
<envvars>
<envvar value="1" name="WANT_AUTOCONF_2_5" />
<envvar value="1" name="WANT_AUTOMAKE_1_6" />
</envvars>
<abortonerror>true</abortonerror>
<numberofjobs>1</numberofjobs>
<dontact>false</dontact>
<makebin/>
<prio>0</prio>
<runmultiplejobs>false</runmultiplejobs>
</make>
</kdevautoproject>
<kdevfileview>
<groups>
<group pattern="*.cpp;*.cxx;*.h" name="Sources" />
<group pattern="*.ui" name="User Interface" />
<group pattern="*.png" name="Icons" />
<group pattern="*.po;*.ts" name="Translations" />
<group pattern="*" name="Others" />
<hidenonprojectfiles>false</hidenonprojectfiles>
<hidenonlocation>false</hidenonlocation>
</groups>
<tree>
<hidenonprojectfiles>false</hidenonprojectfiles>
<showvcsfields>false</showvcsfields>
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
</tree>
</kdevfileview>
<kdevdoctreeview>
<ignoretocs>
<toc>gtk</toc>
<toc>gnustep</toc>
<toc>python</toc>
<toc>php</toc>
<toc>perl</toc>
<toc>ada</toc>
<toc>ada_bugs_gcc</toc>
<toc>bash_bugs</toc>
<toc>bash</toc>
<toc>gnome1</toc>
<toc>gtk_bugs</toc>
<toc>haskell</toc>
<toc>haskell_bugs_ghc</toc>
<toc>java_bugs_gcc</toc>
<toc>java_bugs_sun</toc>
<toc>opengl</toc>
<toc>pascal_bugs_fp</toc>
<toc>perl_bugs</toc>
<toc>php_bugs</toc>
<toc>python_bugs</toc>
<toc>ruby</toc>
<toc>ruby_bugs</toc>
<toc>sdl</toc>
<toc>stl</toc>
<toc>sw</toc>
<toc>wxwindows_bugs</toc>
</ignoretocs>
<projectdoc>
<userdocDir>html/</userdocDir>
<apidocDir>html/</apidocDir>
</projectdoc>
<ignoreqt_xml/>
<ignoredoxygen/>
<ignorekdocs/>
<ignoredevhelp>
<toc>atk</toc>
<toc>gdk</toc>
<toc>libgimpbase</toc>
<toc>libgimpcolor</toc>
<toc>libgimp</toc>
<toc>libgimpmath</toc>
<toc>libgimpmodule</toc>
<toc>libgimpwidgets</toc>
<toc>glib</toc>
<toc>gobject</toc>
<toc>gtk</toc>
<toc>pango</toc>
<toc>gdk-pixbuf</toc>
</ignoredevhelp>
</kdevdoctreeview>
<kdevdebugger>
<general>
<dbgshell>libtool</dbgshell>
<programargs>-d --nofork --use-drkonquy --data-folder ~/.kde/share/apps/basket-debug</programargs>
<gdbpath></gdbpath>
<configGdbScript></configGdbScript>
<runShellScript></runShellScript>
<runGdbScript></runGdbScript>
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>false</floatingtoolbar>
</general>
<display>
<staticmembers>true</staticmembers>
<demanglenames>true</demanglenames>
<outputradix>10</outputradix>
</display>
</kdevdebugger>
<kdevfilecreate>
<filetypes/>
<useglobaltypes>
<type ext="ui" />
<type ext="cpp" />
<type ext="h" />
</useglobaltypes>
</kdevfilecreate>
<kdevcvs>
<cvsoptions>-f</cvsoptions>
<commitoptions/>
<addoptions/>
<logoptions/>
<updateoptions>-dP</updateoptions>
<removeoptions>-f</removeoptions>
<revertoptions>-C -d -P</revertoptions>
<diffoptions>-u3 -p</diffoptions>
<rshoptions/>
</kdevcvs>
<kdevcppsupport>
<references>
<pcs>Qt</pcs>
</references>
<codecompletion>
<includeGlobalFunctions>true</includeGlobalFunctions>
<includeTypes>true</includeTypes>
<includeEnums>true</includeEnums>
<includeTypedefs>true</includeTypedefs>
<automaticCodeCompletion>false</automaticCodeCompletion>
<automaticArgumentsHint>true</automaticArgumentsHint>
<automaticHeaderCompletion>true</automaticHeaderCompletion>
<codeCompletionDelay>100</codeCompletionDelay>
<argumentsHintDelay>100</argumentsHintDelay>
<headerCompletionDelay>250</headerCompletionDelay>
<showOnlyAccessibleItems>false</showOnlyAccessibleItems>
<completionBoxItemOrder>0</completionBoxItemOrder>
<howEvaluationContextMenu>true</howEvaluationContextMenu>
<showCommentWithArgumentHint>true</showCommentWithArgumentHint>
<statusBarTypeEvaluation>false</statusBarTypeEvaluation>
<namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
<processPrimaryTypes>true</processPrimaryTypes>
<processFunctionArguments>true</processFunctionArguments>
<preProcessAllHeaders>false</preProcessAllHeaders>
<parseMissingHeaders>false</parseMissingHeaders>
<resolveIncludePaths>true</resolveIncludePaths>
<alwaysParseInBackground>true</alwaysParseInBackground>
<usePermanentCaching>true</usePermanentCaching>
<alwaysIncludeNamespaces>true</alwaysIncludeNamespaces>
<includePaths>.;</includePaths>
</codecompletion>
<creategettersetter>
<prefixGet></prefixGet>
<prefixSet>set</prefixSet>
<prefixVariable>m_,_</prefixVariable>
<parameterName>value</parameterName>
<inlineGet>true</inlineGet>
<inlineSet>true</inlineSet>
</creategettersetter>
<qt>
<used>true</used>
<version>3</version>
<root>/usr/share/qt3</root>
<includestyle>3</includestyle>
<designerintegration>EmbeddedKDevDesigner</designerintegration>
<qmake>/usr/bin/qmake-qt3</qmake>
<designer>/usr/bin/designer-qt3</designer>
<designerpluginpaths/>
</qt>
<splitheadersource>
<enabled>false</enabled>
<synchronize>true</synchronize>
<orientation>Vertical</orientation>
</splitheadersource>
</kdevcppsupport>
<cppsupportpart>
<filetemplates>
<interfacesuffix>.h</interfacesuffix>
<implementationsuffix>.cpp</implementationsuffix>
</filetemplates>
</cppsupportpart>
<kdevdocumentation>
<projectdoc>
<docsystem/>
<docurl/>
<usermanualurl/>
</projectdoc>
</kdevdocumentation>
<dist>
<custom>false</custom>
<bzip>false</bzip>
<archname>basket-%v.tar.gz</archname>
<appname>basket</appname>
<version>1.0.3.1</version>
<release/>
<vendor/>
<licence/>
<summary/>
<group/>
<packager/>
<description>Taking care of your ideas.</description>
<changelog/>
<devpackage>false</devpackage>
<docspackage>false</docspackage>
<appicon>false</appicon>
<arch>0</arch>
<genHTML>false</genHTML>
<useRPM>false</useRPM>
<ftpkde>false</ftpkde>
<appskde>false</appskde>
<url/>
</dist>
<ctagspart>
<customArguments/>
<customTagfilePath/>
</ctagspart>
</kdevelop>

Binary file not shown.

@ -0,0 +1,53 @@
%define name basket
%define version 1.0.3.1
%define release mantic0
Summary: Taking care of your ideas.
Name: %{name}
Version: %{version}
Release: %{release}
License: GPL
Vendor: slaout@linux62.org
Url: http://basket.kde.org/
Packager: packages@mantic.org
Group: Utils
Source: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}
%description
Taking care of your ideas.
A note-taking application that makes it easy to write down ideas as you think, and quickly find them back later. Organizing your notes has never been so easy.
%prep
%setup
if [ "`kde-config --prefix`" ]; then
CONFIGURE_PREFIX="`kde-config --prefix`"
elif [ "${KDEDIR}" ]; then
CONFIGURE_PREFIX="${KDEDIR}"
elif [ -d "/opt/kde" ]; then
CONFIGURE_PREFIX="/opt/kde"
elif [ -d "/opt/kde3" ]; then
CONFIGURE_PREFIX="/opt/kde3"
else
CONFIGURE_PREFIX="/usr"
fi
./configure --prefix="${CONFIGURE_PREFIX}" --enable-final
%build
%configure
#%make
%install
make install DESTDIR=$RPM_BUILD_ROOT
cd $RPM_BUILD_ROOT
find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > /var/tmp/file.list.%{name}
find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> /var/tmp/file.list.%{name}
find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> /var/tmp/file.list.%{name}
%clean
rm -rf $RPM_BUILD_ROOT/*
rm -rf $RPM_BUILD_DIR/%{name}-%{version}
rm -rf /var/tmp/file.list.%{name}
%files -f /var/tmp/file.list.%{name}

@ -0,0 +1,253 @@
/* 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 libgpgme is available */
#undef HAVE_LIBGPGME
/* 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 to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
/*
* 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
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
#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
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/*
* 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

35434
configure vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
./admin/configure.in.min
configure.in.in
configure.in.bot

@ -0,0 +1,217 @@
dnl =======================================================
dnl FILE: ./admin/configure.in.min
dnl =======================================================
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., 51 Franklin Street, Fifth Floor,
dnl Boston, MA 02110-1301, 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(basket, '1.0.3.1') 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.0.0)
AC_PATH_KDE
dnl =======================================================
dnl FILE: configure.in.in
dnl =======================================================
#MIN_CONFIG(3.0.0)
dnl PACKAGE set before
AC_C_BIGENDIAN
AC_CHECK_KDEMAXPATHLEN
KDE_CHECK_LARGEFILE
dnl -----------------------------------------------------------------
dnl AC_LIB_GPGME([ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl -----------------------------------------------------------------
OPTION=" --with-encryption=yes/no compile with encryption support (gpgme)"
AC_DEFUN([AC_ENCRYPTION], [
AH_TEMPLATE([HAVE_LIBGPGME], [Define if libgpgme is available])
AC_ARG_WITH(encryption, [$OPTION], [
if test "$withval" = "no"; then
ac_gpg=
$2
elif test "$withval" = "yes"; then
ac_gpg=yes
else
ac_gpg=yes
fi
],[ac_gpg=yes])
if test "$ac_gpg" != ""; then
AM_PATH_GPGME(1.0.0, ac_libgpgme=yes, ac_libgpgme=no)
AM_PATH_GPG_ERROR(1.0, ac_libgpgerror=yes, ac_libgpgerror=no)
if test "$ac_libgpgme" != "no" -a "$ac_libgpgerror" != "no"; then
AC_DEFINE([HAVE_LIBGPGME])
ac_have_gpgme="yes"
$1
else
:
$2
fi
fi
AM_CONDITIONAL(HAVE_LIBGPGME, test "$ac_have_gpgme" = "yes")
])
AC_ENCRYPTION([], [basket_warning_gpgme=yes])
KDE_CHECK_HEADER(kontact/core.h, [KONTACT_SUBDIR="yes"], [KONTACT_SUBDIR="no"])
if test "$KONTACT_SUBDIR" = "no"; then
basket_warning_kontact=yes
DO_NOT_COMPILE="$DO_NOT_COMPILE kontact_plugin"
fi
KDE_CREATE_SUBDIRSLIST
AC_CONFIG_FILES([ Makefile ])
AC_CONFIG_FILES([ backgrounds/Makefile ])
AC_CONFIG_FILES([ backgrounds-previews/Makefile ])
AC_CONFIG_FILES([ doc/Makefile ])
AC_CONFIG_FILES([ doc/en/Makefile ])
AC_CONFIG_FILES([ file-integration/Makefile ])
AC_CONFIG_FILES([ images/Makefile ])
AC_CONFIG_FILES([ kontact_plugin/Makefile ])
AC_CONFIG_FILES([ po/Makefile ])
AC_CONFIG_FILES([ src/Makefile ])
AC_CONFIG_FILES([ tags/Makefile ])
AC_CONFIG_FILES([ welcome/Makefile ])
AC_OUTPUT
# configure.in.bot
# This file is used for printing important messages at the end of configure
echo ""
if test x$basket_warning_gpgme = xyes; then
echo " ===================================="
echo " === BasKet Note Pads - WARNING ==================================="
echo " ===================================="
echo " ="
echo " = BasKet Note Pads requires gpgme version 1.0 and"
echo " = libgpg-error version 1.0."
echo " = BasKet Note Pads will still be built, but there is no encryption."
echo " ="
echo " = Packages you need to install if you want encryption:"
echo " = Suse: gpgme-devel"
echo " = Kubuntu: libgpgme11-dev"
echo " = Fedora Core: gpgme-devel"
echo " = Mandriva: libgpgme11-devel"
echo " = Gentoo: app-crypt/gpgme"
echo " ="
fi
if test x$basket_warning_kontact = xyes; then
echo " ===================================="
echo " === BasKet Note Pads - WARNING ==================================="
echo " ===================================="
echo " ="
echo " = BasKet Note Pads requires kdepim."
echo " = BasKet Note Pads will still be built, but there is no"
echo " = Kontact integration."
echo " ="
echo " = Packages you need to install if you want Kontact integration:"
echo " = Suse: kdepim3-devel"
echo " = Kubuntu: kdepim-dev"
echo " = Fedora Core: kdepim-devel"
echo " = Mandriva: libkdepim2-common-devel & libkdepim2-kontact-devel"
echo " = Gentoo: kde-base/kontact"
echo " ="
fi
# Check if KDE_SET_PREFIX was called, and --prefix was passed to configure
if test -n "$kde_libs_prefix" -a -n "$given_prefix"; then
# And if so, warn when they don't match
if test "$kde_libs_prefix" != "$given_prefix"; then
# And if kde doesn't know about the prefix yet
echo ":"`kde-config --path exe`":" | grep ":$given_prefix/bin/:" 2>&1 >/dev/null
if test $? -ne 0; then
echo ""
echo "Warning: you chose to install this package in $given_prefix,"
echo "but KDE was found in $kde_libs_prefix."
echo "For this to work, you will need to tell KDE about the new prefix, by ensuring"
echo "that KDEDIRS contains it, e.g. export KDEDIRS=$given_prefix:$kde_libs_prefix"
echo "Then restart KDE."
echo ""
fi
fi
fi
if test x$GXX = "xyes" -a x$kde_have_gcc_visibility = "xyes" -a x$kde_cv_val_qt_gcc_visibility_patched = "xno"; then
echo ""
echo "Your GCC supports symbol visibility, but the patch for Qt supporting visibility"
echo "was not included. Therefore, GCC symbol visibility support remains disabled."
echo ""
echo "For better performance, consider including the Qt visibility supporting patch"
echo "located at:"
echo ""
echo "http://bugs.kde.org/show_bug.cgi?id=109386"
echo ""
echo "and recompile all of Qt and KDE. Note, this is entirely optional and"
echo "everything will continue to work just fine without it."
echo ""
fi
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

@ -0,0 +1,40 @@
# configure.in.bot
# This file is used for printing important messages at the end of configure
echo ""
if test x$basket_warning_gpgme = xyes; then
echo " ===================================="
echo " === BasKet Note Pads - WARNING ==================================="
echo " ===================================="
echo " ="
echo " = BasKet Note Pads requires gpgme version 1.0 and"
echo " = libgpg-error version 1.0."
echo " = BasKet Note Pads will still be built, but there is no encryption."
echo " ="
echo " = Packages you need to install if you want encryption:"
echo " = Suse: gpgme-devel"
echo " = Kubuntu: libgpgme11-dev"
echo " = Fedora Core: gpgme-devel"
echo " = Mandriva: libgpgme11-devel"
echo " = Gentoo: app-crypt/gpgme"
echo " ="
fi
if test x$basket_warning_kontact = xyes; then
echo " ===================================="
echo " === BasKet Note Pads - WARNING ==================================="
echo " ===================================="
echo " ="
echo " = BasKet Note Pads requires kdepim."
echo " = BasKet Note Pads will still be built, but there is no"
echo " = Kontact integration."
echo " ="
echo " = Packages you need to install if you want Kontact integration:"
echo " = Suse: kdepim3-devel"
echo " = Kubuntu: kdepim-dev"
echo " = Fedora Core: kdepim-devel"
echo " = Mandriva: libkdepim2-common-devel & libkdepim2-kontact-devel"
echo " = Gentoo: kde-base/kontact"
echo " ="
fi

@ -0,0 +1,53 @@
#MIN_CONFIG(3.0.0)
AM_INIT_AUTOMAKE(basket, '1.0.3.1')
AC_C_BIGENDIAN
AC_CHECK_KDEMAXPATHLEN
KDE_CHECK_LARGEFILE
dnl -----------------------------------------------------------------
dnl AC_LIB_GPGME([ACTION-IF-TRUE], [ACTION-IF-FALSE])
dnl -----------------------------------------------------------------
OPTION=" --with-encryption=yes/no compile with encryption support (gpgme)"
AC_DEFUN([AC_ENCRYPTION], [
AH_TEMPLATE([HAVE_LIBGPGME], [Define if libgpgme is available])
AC_ARG_WITH(encryption, [$OPTION], [
if test "$withval" = "no"; then
ac_gpg=
$2
elif test "$withval" = "yes"; then
ac_gpg=yes
else
ac_gpg=yes
fi
],[ac_gpg=yes])
if test "$ac_gpg" != ""; then
AM_PATH_GPGME(1.0.0, ac_libgpgme=yes, ac_libgpgme=no)
AM_PATH_GPG_ERROR(1.0, ac_libgpgerror=yes, ac_libgpgerror=no)
if test "$ac_libgpgme" != "no" -a "$ac_libgpgerror" != "no"; then
AC_DEFINE([HAVE_LIBGPGME])
ac_have_gpgme="yes"
$1
else
:
$2
fi
fi
AM_CONDITIONAL(HAVE_LIBGPGME, test "$ac_have_gpgme" = "yes")
])
AC_ENCRYPTION([], [basket_warning_gpgme=yes])
KDE_CHECK_HEADER(kontact/core.h, [KONTACT_SUBDIR="yes"], [KONTACT_SUBDIR="no"])
if test "$KONTACT_SUBDIR" = "no"; then
basket_warning_kontact=yes
DO_NOT_COMPILE="$DO_NOT_COMPILE kontact_plugin"
fi

@ -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 = basket
SUBDIRS = $(AUTODIRS)

@ -0,0 +1,2 @@
KDE_DOCS = basket
KDE_LANG = en

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.0//EN" "dtd/kdex.dtd" [
<!ENTITY kappname "&basket;">
<!ENTITY basket "<application>BasKet</application>">
<!ENTITY % addindex "IGNORE">
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
]>
<!-- Important note: please use template.docbook instead of this file.
This is only the conversion of app.sgml into DocBook SGML.
template.docbook gives you more information on what you can and
should do. Thanks. -->
<book lang="&language;">
<bookinfo>
<title>The BasKet Handbook</title>
<authorgroup>
<author>
<firstname>Sébastien</firstname>
<surname>Laoût</surname>
<affiliation><address><email>slaout@linux62.org</email></address></affiliation>
</author>
</authorgroup>
<date>01/18/2005</date>
<releaseinfo>1.0.3.1</releaseinfo>
<abstract>
<para>Taking care of your ideas.</para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>BasKet</keyword>
</keywordset>
</bookinfo>
<chapter id="introduction">
<title>Introduction</title>
<para>&basket; is mainly an all-purpose notes taker, but a particular one:</para>
</chapter>
<chapter id="installation">
<title>Installation</title>
<sect1 id="how-to-obtain-BasKet">
<title>How to obtain &basket;</title>
<para></para>
</sect1>
<sect1 id="requirements">
<title>Requirements</title>
<para></para>
</sect1>
<sect1 id="compilation-and-installation">
<title>Compilation and Installation</title>
<para>Compiling BasKet is very easy. The following should do it:
<screen>
<prompt>%</prompt> <userinput><command>./configure</command></userinput>
<prompt>%</prompt> <userinput><command>make</command></userinput>
<prompt>%</prompt> <userinput><command>make</command> install</userinput>
</screen>
</para>
<para>That should do it! Should you run into any problems,
please report them to the <ulink
url="mailto:slaout@linux62.org">author</ulink></para>
</sect1>
</chapter>
<chapter id="using-BasKet">
<title>Using BasKet</title>
<para></para>
</chapter>
<chapter id="questions-answers-and-tips">
<title>Questions, Answers, and Tips</title>
<qandaset id="faq">
<title>Frequently asked questions</title>
<qandaentry>
<question>
<para>Question 1</para>
</question>
<answer>
<para>The answer</para>
</answer>
</qandaentry>
</qandaset>
</chapter>
</book>
<!--
Local Variables:
mode: sgml
sgml-omittag: nil
sgml-shorttag: t
sgml-general-insert-case: lower
End:
-->

@ -0,0 +1,23 @@
# MIME Types Information:
applicationmimedir = $(kde_mimedir)/application
applicationmime_DATA = x-basket-archive.desktop x-basket-template.desktop
# Magic MIME Types Discovery:
magicdir = $(kde_confdir)/magic
magic_DATA = basket.magic
# Thumbnail Creator:
INCLUDES = $(all_includes)
kde_module_LTLIBRARIES = basketthumbcreator.la
basketthumbcreator_la_SOURCES = basketthumbcreator.cpp
basketthumbcreator_la_LIBADD = $(LIB_KIO)
basketthumbcreator_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
kde_services_DATA = basketthumbcreator.desktop
# Icons:
KDE_ICON = AUTO
#kde_icon_KDEICON = \
# cr128-mimetype-baskets.png cr16-mimetype-baskets.png cr22-mimetype-baskets.png \
# cr32-mimetype-baskets.png cr48-mimetype-baskets.png cr64-mimetype-baskets.png \
# cr128-mimetype-baskett.png cr16-mimetype-baskett.png cr22-mimetype-baskett.png \
# cr32-mimetype-baskett.png cr48-mimetype-baskett.png cr64-mimetype-baskett.png

@ -0,0 +1,2 @@
0 string BasKetNP:archive\n application/x-basket-archive
0 string BasKetNP:template\n application/x-basket-template

@ -0,0 +1,117 @@
/***************************************************************************
* Copyright (C) 2006 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstringlist.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qtextstream.h>
#include <ktempdir.h>
#include "basketthumbcreator.h"
bool BasketThumbCreator::create(const QString &path, int /*width*/, int /*height*/, QImage &image)
{
// Create the temporar folder:
KTempDir tempDir;
tempDir.setAutoDelete(true);
QString tempFolder = tempDir.name();
QDir dir;
dir.mkdir(tempFolder);
const Q_ULONG BUFFER_SIZE = 1024;
QFile file(path);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::Latin1);
QString line = stream.readLine();
if (line != "BasKetNP:archive" && line != "BasKetNP:template") {
file.close();
return false;
}
while (!stream.atEnd()) {
// Get Key/Value Pair From the Line to Read:
line = stream.readLine();
int index = line.find(':');
QString key;
QString value;
if (index >= 0) {
key = line.left(index);
value = line.right(line.length() - index - 1);
} else {
key = line;
value = "";
}
if (key == "preview*") {
bool ok;
ulong size = value.toULong(&ok);
if (!ok) {
file.close();
return false;
}
// Get the preview file:
QFile previewFile(tempFolder + "preview.png");
if (previewFile.open(IO_WriteOnly)) {
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
previewFile.writeBlock(buffer, sizeRead);
size -= sizeRead;
}
previewFile.close();
delete buffer;
image = QImage(tempFolder + "preview.png");
file.close();
return true;
}
} else if (key.endsWith("*")) {
// We do not know what it is, but we should read the embedded-file in order to discard it:
bool ok;
ulong size = value.toULong(&ok);
if (!ok) {
file.close();
return false;
}
// Get the archive file:
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
size -= sizeRead;
}
delete buffer;
}
}
file.close();
}
return false;
}
ThumbCreator::Flags BasketThumbCreator::flags() const
{
return (Flags) (DrawFrame | BlendIcon);
}
extern "C"
{
ThumbCreator *new_creator()
{
return new BasketThumbCreator();
}
};

@ -0,0 +1,18 @@
[Desktop Entry]
Encoding=UTF-8
Type=Service
Name=Basket Archives & Templates
Name[de]=Korbarchiv und Korbvorlagen
Name[es]=Archivo de cestas y plantillas
Name[fr]=Archive de paniers et modèles
Name[it]=Archivi e modelli di canestri
Name[ja]=バスケットアーカイブとテンプレート
Name[nb]=Kurvarkiv og kurvmaler
Name[nn]=Korgarkiv og korgmalar
Name[pt]=Arquivos e modelos de cestos
Name[ru]=Шаблоны и контейнеры Basket
Name[tr]=Basket Arşivleri & Şablonları
ServiceTypes=ThumbCreator
MimeTypes=application/x-basket-archive,application/x-basket-template
CacheThumbnail=true
X-KDE-Library=basketthumbcreator

@ -0,0 +1,29 @@
/***************************************************************************
* Copyright (C) 2006 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstring.h>
#include <qimage.h>
#include <kio/thumbcreator.h>
class BasketThumbCreator : public ThumbCreator
{
bool create(const QString &path, int width, int height, QImage &image);
Flags flags() const;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

@ -0,0 +1,17 @@
[Desktop Entry]
Encoding=UTF-8
MimeType=application/x-basket-archive
Type=MimeType
Comment=Basket Archive
Comment[de]=Korbarchiv
Comment[es]=Archivo de cestas
Comment[fr]=Archive de paniers
Comment[it]=Archivio di canestri
Comment[ja]=バスケットアーカイブ
Comment[nb]=Kurvarkiv
Comment[nn]=Korgarkiv
Comment[pt]=Ficheiro de cestos
Comment[ru]=Контейнер Basket
Comment[tr]=Basket Arşivi
Icon=baskets
Patterns=*.baskets

@ -0,0 +1,17 @@
[Desktop Entry]
Encoding=UTF-8
MimeType=application/x-basket-template
Type=MimeType
Comment=Basket Template
Comment[de]=Korbvorlage
Comment[es]=Plantilla de cesta
Comment[fr]=Modèle de panier
Comment[it]=Modello di canestri
Comment[ja]=バスケットテンプレート
Comment[nb]=Kurvmal
Comment[nn]=Korgmal
Comment[pt]=Modelo de cesto
Comment[ru]=Шаблон корзины
Comment[tr]=Basket Şabolonu
Icon=baskett
Patterns=*.baskett

@ -0,0 +1,4 @@
imagesdir = $(kde_datadir)/basket/images
images_DATA = insertion_help.png \
tag_export_help.png \
tag_export_on_every_lines_help.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

@ -0,0 +1,233 @@
#!/bin/bash
function error
{
echo ""
echo " ======================================================================== "
echo " (( An Error has Been Encountered ))"
echo " ======================================================================== "
echo ""
echo ""
echo " In the most cases, some libraries are missing or cannot be found."
echo " Think to install the *-dev or *-devel packages of your distribution."
echo " For example, if libmng cannot be found,"
echo " please check if libmng AND libmng-devel packages are installed on your system."
echo " See the reported errors to know which librarie need to be installed."
echo ""
echo $'\a' # Beep to avert user of the error
exit 1
}
##echo " (( An error has been encountered ))"
##echo " ((654321 987654321 987654321 98765432 23456789 123456789 123456789 123456))"
##echo" ((654321 987654321 987654321 98765432 23456789 123456789 123456789 123456))"
clear
echo ""
echo " ======================================================================== "
echo " (( BasKet Note Pads Quick Installer ))"
echo " ======================================================================== "
echo ""
echo ""
echo " Welcome to the BasKet Note Pads installer assistant."
echo " It will configure, build and install BasKet Note Pads."
echo ""
echo ""
echo " What do you want to do?"
echo ""
echo " 1/ Install BasKet Note Pads system wide (you will need the root password)"
echo " 2/ Install BasKet Note Pads in your user folder"
#echo " 3/ Uninstall BasKet Note Pads (you should not: it is so fantastic ;-) )"
echo ""
echo -n "Your choice (default is 1): "
read -n 1 WHAT_TO_DO
echo ""
if [ "_$WHAT_TO_DO" == "_2" ]; then
SYS_WIDE=0
WHAT_TO_DO=2 # To transform it from string to int
else
# if [ $WHAT_TO_DO == 3 ]; then
# SYS_WIDE=1
# else # [ WHAT_TO_DO == 1 ] or default
SYS_WIDE=1
WHAT_TO_DO=1 # If user entered another number than those he should
# fi
fi
if [ $SYS_WIDE == 0 ]; then
prefix=`kde-config --localprefix --expandvars`
else
prefix=`kde-config --prefix --expandvars`
fi
# Uninstall of BasKet:
if [ $WHAT_TO_DO == 3 ]; then
# Search installed basket:
prefix=`kde-config --localprefix --expandvars` # First loacally
if [ -f $prefix/bin/basket ]; then
SYS_WIDE=0
else
prefix=`kde-config --prefix --expandvars` # And then system wide
if [ -f $prefix/bin/basket ]; then
SYS_WIDE=1
else
echo "BasKet Note Pads does not seem to be installed."
exit 1
fi
fi
# TODO: Also definitively remove your baskets?
# At this stage, SYS_WIDE and prefix are set and uninstall can begin:
if [ $SYS_WIDE == 1 ]; then
su
make uninstall || ./configure --prefix=$prefix && make uninstall
logout
else
make uninstall || ./configure --prefix=$prefix && make uninstall
fi
exit 0
fi
appVersion=$(cat basket.spec | grep "%define version " | cut -d " " -f 3)
isDevel=$(echo "$appVersion" | grep -i -E "(alpha|beta|pre|rc|svn)")
clear
echo ""
echo " ======================================================================== "
echo " (( BasKet Note Pads Quick Installer ))"
echo " ======================================================================== "
echo ""
echo ""
echo ""
echo ""
echo " If you do not know what they are, you can ignore errors or warnings."
echo ""
echo " The process can take several minutes."
echo " A beep will notify you when it will be done."
echo " Press ENTER to start."
echo ""
echo ""
read -s -n 1 # read 1 character without echo, ended by ENTER
if [ ! -e configure ]; then
clear
echo ""
echo " ======================================================================== "
echo " (( Preparation from SVN ))"
echo " ======================================================================== "
echo ""
echo ""
echo "make -f Makefile.cvs"
make -f Makefile.cvs || error
fi
clear
echo ""
echo " ======================================================================== "
echo " (( Step 1 / 3 : Configuration ))"
echo " ======================================================================== "
echo ""
echo ""
if [ "_$isDevel" == "_" ]; then
echo "./configure --prefix=$prefix"
./configure --prefix=$prefix || error
else
echo "./configure --enable-debug=full --prefix=$prefix"
./configure --enable-debug=full --prefix=$prefix || error
fi
clear
echo ""
echo " ======================================================================== "
echo " (( Step 2 / 3 : Compilation ))"
echo " ======================================================================== "
echo ""
echo ""
echo "make"
make || error
clear
echo ""
echo " ======================================================================== "
echo " (( Step 3 / 3 : Installation ))"
echo " ======================================================================== "
echo ""
echo ""
echo " The application has successfuly been compiled."
echo ""
echo ""
echo $'\a' # Beep to avert user the configuration/compilation is ended and he must act to enter the password
if [ "_$SYS_WIDE" == "_n" ]; then
# First make the bin folder to not copy basket file to bin file if bin/ doesn't exist
mkdir $prefix/bin
make install
else
echo " Please now enter the root password in order to install "
echo " BasKet Note Pads on the system."
echo ""
sudo make install || exit 1
echo ""
echo ""
fi
clear
echo ""
echo " ======================================================================== "
echo " (( End of BasKet Note Pads Installation ))"
echo " ======================================================================== "
echo ""
echo ""
echo " Do you want to run BasKet Note Pads now?"
echo " If an older version is currently running it will be exited before."
echo ""
echo " Notice that you willn't have to exit BasKet : it will be restored each time"
echo " you log in to KDE."
echo ""
echo ""
echo -n "Start or restart BasKet Note Pads? [y/n] (default is y): "
read -n 1 RESTART
if [ "_$RESTART" != "_" ]; then # If pressed Enter, a new line was already print
echo ""
fi
if [ "_$RESTART" != "_n" ]; then
# Get the pid of the process basket, if currently running
pid=`ps aux | awk '$11 == "basket" { print $2 }'`
if [ "_$pid" == "_" ]; then
dummy=0
else
kill -s SIGTERM $pid
fi
if [ "_$SYS_WIDE" == "_n" ]; then
echo "$prefix/bin/basket"
$prefix/bin/basket
else
echo "basket"
basket
fi
fi
clear
echo ""
echo " ======================================================================== "
echo " (( Congratulation: BasKet Note Pads is now Installed onto your System ))"
echo " ======================================================================== "
echo ""
echo ""
echo " In the future, if you want to uninstall BasKet Note Pads, you will have to"
if [ "_$SYS_WIDE" == "_n" ]; then
echo " enter the command make uninstall in this folder."
else
echo " enter the command su -c 'make uninstall' in this folder."
fi
echo ""
echo ""

@ -0,0 +1,18 @@
INCLUDES = -I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir) $(all_includes)
kde_module_LTLIBRARIES = libkontact_basket.la
libkontact_basket_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
libkontact_basket_la_LIBADD = -lkpinterfaces -lDCOP -lqt-mt -lkdecore -lkdeui
noinst_HEADERS = basket_plugin.h uniqueapphandler.h
libkontact_basket_la_SOURCES = basket_plugin.cpp uniqueapphandler.cpp basketdcopiface.stub
METASOURCES = AUTO
basketdcopiface_DIR = $(top_srcdir)/src
servicedir = $(kde_servicesdir)/kontact
service_DATA = basket.desktop basket_v4.desktop
basketsetdlgdir = $(kde_datadir)/kontact/ksettingsdialog
basketsetdlg_DATA = kontact_basketplugin.setdlg

@ -0,0 +1,42 @@
[Desktop Entry]
Encoding=UTF-8
Type=Service
Icon=basket
ServiceTypes=Kontact/Plugin,KPluginInfo
X-KDE-Library=libkontact_basket
X-KDE-KontactPluginVersion=5
X-KDE-KontactPartLibraryName=libbasketpart
X-KDE-KontactPartExecutableName=basket
X-KDE-KontactPartLoadOnStart=true
X-KDE-KontactPluginHasSummary=false
X-KDE-PluginInfo-Website=http://basket.kde.org/
X-KDE-PluginInfo-Name=kontact_basketplugin
X-KDE-PluginInfo-Version=1.0.3.1
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
Comment=BasKet Note Pads plugin for Kontact
Comment[de]=Plugin BasKet Notizblätter für Kontact
Comment[es]=Complemento de los blocs de notas BasKet para Kontact
Comment[fr]=Module Blocs notes BasKet pour Kontact
Comment[it]=Plugin Blocco appunti BasKet per Kontact
Comment[ja]=BasKet メモパッドの Kontact 統合プラグイン
Comment[nb]=Kurvnotat-tillegg for Kontakt
Comment[nn]=Korgnotat-tillegg for Kontakt
Comment[pt]=Plugin do Bloco de Notas BasKet para o Kontact
Comment[ru]=Модуль Альбом заметок Basket для Kontact
Comment[tr]=Kontact için Basket Not Tutucu Eklentisi
Name=Baskets
Name[de]=Körbe
Name[es]=Cestas
Name[fr]=Paniers
Name[it]=Canestri
Name[ja]=バスケット
Name[nb]=Kurver
Name[nn]=Korger
Name[pt]=Cestos
Name[ru]=Корзины
Name[tr]=Sepetler

@ -0,0 +1,107 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kgenericfactory.h>
#include <kparts/componentfactory.h>
#include <kontact/core.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <dcopref.h>
#include "basketdcopiface_stub.h"
#include "basket_plugin.h"
#include "basket_options.h"
#include "basket_part.h"
typedef KGenericFactory<BasketPlugin, Kontact::Core> BasketPluginFactory;
K_EXPORT_COMPONENT_FACTORY( libkontact_basket,
BasketPluginFactory( "kontact_basketplugin" ) )
BasketPlugin::BasketPlugin( Kontact::Core *core, const char *, const QStringList& )
: Kontact::Plugin( core, core, "basket" )
{
setInstance( BasketPluginFactory::instance() );
insertNewAction(new KAction( i18n("&New Basket..."), "basket", CTRL+SHIFT+Key_B,
this, SLOT(newBasket()), actionCollection(), "basket_new" ));
m_uniqueAppWatcher = new Kontact::UniqueAppWatcher(
new Kontact::UniqueAppHandlerFactory<BasketUniqueAppHandler>(), this);
}
BasketPlugin::~BasketPlugin()
{
}
KParts::ReadOnlyPart* BasketPlugin::createPart()
{
BasketPart* part = static_cast<BasketPart*>(loadPart());
if(!part)
return 0;
m_stub = new BasketDcopInterface_stub(dcopClient(), "basket", "BasketIface");
connect(part, SIGNAL(showPart()), this, SLOT(showPart()));
return part;
}
void BasketPlugin::newBasket()
{
(void) part(); // ensure part is loaded
Q_ASSERT(m_stub);
if (m_stub) {
kdDebug() << k_funcinfo << endl;
m_stub->newBasket();
}
}
void BasketPlugin::showPart()
{
core()->selectPlugin(this);
}
#if 0
bool BasketPlugin::createDCOPInterface( const QString& serviceType )
{
kdDebug() << k_funcinfo << serviceType << endl;
return false;
}
#endif
bool BasketPlugin::isRunningStandalone()
{
return m_uniqueAppWatcher->isRunningStandalone();
}
void BasketUniqueAppHandler::loadCommandLineOptions()
{
KCmdLineArgs::addCmdLineOptions(basket_options);
}
int BasketUniqueAppHandler::newInstance()
{
(void)plugin()->part();
DCOPRef kmail("basket", "BasketIface");
DCOPReply reply = kmail.call("handleCommandLine", false);
if (reply.isValid()) {
bool handled = reply;
if ( !handled )
return Kontact::UniqueAppHandler::newInstance();
}
return 0;
}
#include "basket_plugin.moc"

@ -0,0 +1,63 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKET_PLUGIN_H
#define BASKET_PLUGIN_H
#include <klocale.h>
#include <kparts/part.h>
#include <kontact/plugin.h>
#include "uniqueapphandler.h"
#include "basketdcopiface_stub.h"
class KAboutData;
class BasketUniqueAppHandler : public Kontact::UniqueAppHandler
{
public:
BasketUniqueAppHandler( Kontact::Plugin* plugin ) : Kontact::UniqueAppHandler( plugin ) {}
virtual void loadCommandLineOptions();
virtual int newInstance();
};
class BasketPlugin : public Kontact::Plugin
{
Q_OBJECT
public:
BasketPlugin( Kontact::Core *core, const char *name,
const QStringList & );
~BasketPlugin();
int weight() const { return 700; }
virtual bool isRunningStandalone();
//virtual bool createDCOPInterface( const QString& serviceType );
public slots:
void newBasket();
void showPart();
protected:
KParts::ReadOnlyPart *createPart();
BasketDcopInterface_stub *m_stub;
Kontact::UniqueAppWatcher *m_uniqueAppWatcher;
};
#endif

@ -0,0 +1,43 @@
[Desktop Entry]
Encoding=UTF-8
Type=Service
Icon=basket
ServiceTypes=Kontact/Plugin,KPluginInfo
X-KDE-Library=libkontact_basket
X-KDE-KontactPluginVersion=4
X-KDE-KontactPartLibraryName=libbasketpart
X-KDE-KontactPartExecutableName=basket
X-KDE-KontactPartLoadOnStart=true
X-KDE-KontactPluginHasSummary=false
X-KDE-PluginInfo-Website=http://basket.kde.org/
X-KDE-PluginInfo-Name=kontact_basketplugin
X-KDE-PluginInfo-Version=1.0.3.1
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
Comment=BasKet Note Pads plugin for Kontact
Comment[de]=Plugin BasKet Notizblätter für Kontact
Comment[es]=Complemento de los blocs de notas BasKet para Kontact
Comment[fr]=Module Blocs notes BasKet pour Kontact
Comment[it]=Plugin Blocco appunti BasKet per Kontact
Comment[ja]=BasKet メモパッドの Kontact 統合プラグイン
Comment[nb]=Kurvnotat-tillegg for Kontakt
Comment[nn]=Korgnotat-tillegg for Kontakt
Comment[pt]=Plugin do Bloco de Notas BasKet para o Kontact
Comment[ru]=Модуль Альбом заметок Basket для Kontact
Comment[tr]=Kontact için Basket Not Tutucu Eklentisi
Name=Baskets
Name[de]=Körbe
Name[es]=Cestas
Name[fr]=Paniers
Name[it]=Canestri
Name[ja]=バスケット
Name[nb]=Kurver
Name[nn]=Korger
Name[pt]=Cestos
Name[ru]=Корзины
Name[tr]=Sepetler

@ -0,0 +1,56 @@
/****************************************************************************
**
** DCOP Stub Implementation created by dcopidl2cpp from basketdcopiface.kidl
**
** WARNING! All changes made in this file will be lost!
**
*****************************************************************************/
#include "basketdcopiface_stub.h"
#include <dcopclient.h>
#include <kdatastream.h>
BasketDcopInterface_stub::BasketDcopInterface_stub( const QCString& app, const QCString& obj )
: DCOPStub( app, obj )
{
}
BasketDcopInterface_stub::BasketDcopInterface_stub( DCOPClient* client, const QCString& app, const QCString& obj )
: DCOPStub( client, app, obj )
{
}
BasketDcopInterface_stub::BasketDcopInterface_stub( const DCOPRef& ref )
: DCOPStub( ref )
{
}
void BasketDcopInterface_stub::newBasket()
{
if ( !dcopClient() ) {
setStatus( CallFailed );
return;
}
QByteArray data;
dcopClient()->send( app(), obj(), "newBasket()", data );
setStatus( CallSucceeded );
}
void BasketDcopInterface_stub::handleCommandLine()
{
if ( !dcopClient() ) {
setStatus( CallFailed );
return;
}
QByteArray data, replyData;
QCString replyType;
if ( dcopClient()->call( app(), obj(), "handleCommandLine()", data, replyType, replyData ) ) {
setStatus( CallSucceeded );
} else {
callFailed();
}
}

@ -0,0 +1,24 @@
[Basket]
Name=Baskets
Name[de]=Körbe
Name[es]=Cestas
Name[fr]=Paniers
Name[it]=Canestri
Name[ja]=バスケット
Name[nb]=Kurver
Name[nn]=Korger
Name[es]=Cestas
Name[pt]=Cestos
Name[ru]=Корзины
Comment=BasKet Note Pads component
Comment[de]=Komponente BasKet Notizblätter
Comment[es]=Componente para las notas de basket
Comment[fr]=Composant Blocs notes BasKet
Comment[it]=Componente Blocco appunti BasKet
Comment[ja]=BasKet メモパッドコンポーネント
Comment[nb]=Kurvnotat-komponent
Comment[nn]=Korgnotat-komponent
Comment[es]=Componente para las notas de basket
Comment[pt]=Componente do Bloco de Notas BasKet
Comment[ru]=Модуль Альбом заметок Basket для Kontact
Icon=basket

@ -0,0 +1,171 @@
/*
This file is part of KDE Kontact.
Copyright (c) 2003 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "uniqueapphandler.h"
#include <kstartupinfo.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kontact/core.h>
#include <kwin.h>
#include <dcopclient.h>
#include <kdebug.h>
/*
Test plan for the various cases of interaction between standalone apps and kontact:
1) start kontact, select "Mail".
1a) type "korganizer" -> it switches to korganizer
1b) type "kmail" -> it switches to kmail
1c) type "kaddressbook" -> it switches to kaddressbook
1d) type "kmail foo@kde.org" -> it opens a kmail composer, without switching
1e) type "knode" -> it switches to knode
1f) type "kaddressbook --new-contact" -> it opens a kaddressbook contact window
1g) type "knode news://foobar/group" -> it pops up "can't resolve hostname"
2) close kontact. Launch kmail. Launch kontact again.
2a) click "Mail" icon -> kontact doesn't load a part, but activates the kmail window
2b) type "kmail foo@kde.org" -> standalone kmail opens composer.
2c) close kmail, click "Mail" icon -> kontact loads the kmail part.
2d) type "kmail" -> kontact is brought to front
3) close kontact. Launch korganizer, then kontact.
3a) both Todo and Calendar activate the running korganizer.
3b) type "korganizer" -> standalone korganizer is brought to front
3c) close korganizer, click Calendar or Todo -> kontact loads part.
3d) type "korganizer" -> kontact is brought to front
4) close kontact. Launch kaddressbook, then kontact.
4a) "Contacts" icon activate the running kaddressbook.
4b) type "kaddressbook" -> standalone kaddressbook is brought to front
4c) close kaddressbook, type "kaddressbook -a foo@kde.org" -> kontact loads part and opens editor
4d) type "kaddressbook" -> kontact is brought to front
5) close kontact. Launch knode, then kontact.
5a) "News" icon activate the running knode.
5b) type "knode" -> standalone knode is brought to front
5c) close knode, type "knode news://foobar/group" -> kontact loads knode and pops up msgbox
5d) type "knode" -> kontact is brought to front
*/
using namespace Kontact;
int UniqueAppHandler::newInstance()
{
// This bit is duplicated from KUniqueApplication::newInstance()
if ( kapp->mainWidget() ) {
kapp->mainWidget()->show();
KWin::forceActiveWindow( kapp->mainWidget()->winId() );
KStartupInfo::appStarted();
}
// Then ensure the part appears in kontact
mPlugin->core()->selectPlugin( mPlugin );
return 0;
}
bool UniqueAppHandler::process( const QCString &fun, const QByteArray &data,
QCString& replyType, QByteArray &replyData )
{
if ( fun == "newInstance()" ) {
replyType = "int";
KCmdLineArgs::reset(); // forget options defined by other "applications"
loadCommandLineOptions();
// This bit is duplicated from KUniqueApplication::processDelayed()
QDataStream ds( data, IO_ReadOnly );
KCmdLineArgs::loadAppArgs( ds );
if ( !ds.atEnd() ) { // backwards compatibility
QCString asn_id;
ds >> asn_id;
kapp->setStartupId( asn_id );
}
QDataStream _replyStream( replyData, IO_WriteOnly );
_replyStream << newInstance( );
} else if ( fun == "load()" ) {
replyType = "bool";
(void)mPlugin->part(); // load the part without bringing it to front
QDataStream _replyStream( replyData, IO_WriteOnly );
_replyStream << true;
} else {
return DCOPObject::process( fun, data, replyType, replyData );
}
return true;
}
QCStringList UniqueAppHandler::interfaces()
{
QCStringList ifaces = DCOPObject::interfaces();
ifaces += "Kontact::UniqueAppHandler";
return ifaces;
}
QCStringList UniqueAppHandler::functions()
{
QCStringList funcs = DCOPObject::functions();
funcs << "int newInstance()";
funcs << "bool load()";
return funcs;
}
UniqueAppWatcher::UniqueAppWatcher( UniqueAppHandlerFactoryBase* factory, Plugin* plugin )
: QObject( plugin ), mFactory( factory ), mPlugin( plugin )
{
// The app is running standalone if 1) that name is known to DCOP
mRunningStandalone = kapp->dcopClient()->isApplicationRegistered( plugin->name() );
// and 2) it's not registered by kontact (e.g. in another plugin)
if ( mRunningStandalone && kapp->dcopClient()->findLocalClient( plugin->name() ) )
mRunningStandalone = false;
if ( mRunningStandalone ) {
kapp->dcopClient()->setNotifications( true );
connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& ) ),
this, SLOT( unregisteredFromDCOP( const QCString& ) ) );
} else {
mFactory->createHandler( mPlugin );
}
}
UniqueAppWatcher::~UniqueAppWatcher()
{
if ( mRunningStandalone )
kapp->dcopClient()->setNotifications( false );
delete mFactory;
}
void UniqueAppWatcher::unregisteredFromDCOP( const QCString& appId )
{
if ( appId == mPlugin->name() && mRunningStandalone ) {
disconnect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString& ) ),
this, SLOT( unregisteredFromDCOP( const QCString& ) ) );
kdDebug(5601) << k_funcinfo << appId << endl;
mFactory->createHandler( mPlugin );
kapp->dcopClient()->setNotifications( false );
mRunningStandalone = false;
}
}
#include "uniqueapphandler.moc"

@ -0,0 +1,120 @@
/*
This file is part of KDE Kontact.
Copyright (c) 2003 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KONTACT_UNIQUEAPPHANDLER_H
#define KONTACT_UNIQUEAPPHANDLER_H
#include <dcopobject.h>
#include <kontact/plugin.h>
#include <kdepimmacros.h>
namespace Kontact
{
/**
* DCOP Object that has the name of the standalone application (e.g. "kmail")
* and implements newInstance() so that running the separate application does
* the right thing when kontact is running.
* By default this means simply bringing the main window to the front,
* but newInstance can be reimplemented.
*/
class KDE_EXPORT UniqueAppHandler : public DCOPObject
{
K_DCOP
public:
UniqueAppHandler( Plugin* plugin ) : DCOPObject( plugin->name() ), mPlugin( plugin ) {}
/// This must be reimplemented so that app-specific command line options can be parsed
virtual void loadCommandLineOptions() = 0;
/// We can't use k_dcop and dcopidl here, because the data passed
/// to newInstance can't be expressed in terms of normal data types.
virtual int newInstance();
Plugin* plugin() const { return mPlugin; }
private:
Plugin* mPlugin;
};
/// Base class for UniqueAppHandler
class UniqueAppHandlerFactoryBase
{
public:
virtual UniqueAppHandler* createHandler( Plugin* ) = 0;
};
/**
* Used by UniqueAppWatcher below, to create the above UniqueAppHandler object
* when necessary.
* The template argument is the UniqueAppHandler-derived class.
* This allows to remove the need to subclass UniqueAppWatcher.
*/
template <class T> class UniqueAppHandlerFactory : public UniqueAppHandlerFactoryBase
{
public:
virtual UniqueAppHandler* createHandler( Plugin* plugin ) {
(void)plugin->dcopClient(); // ensure that we take over the DCOP name
return new T( plugin );
}
};
/**
* If the standalone application is running by itself, we need to watch
* for when the user closes it, and activate the uniqueapphandler then.
* This prevents, on purpose, that the standalone app can be restarted.
* Kontact takes over from there.
*
*/
class KDE_EXPORT UniqueAppWatcher : public QObject
{
Q_OBJECT
public:
/**
* Create an instance of UniqueAppWatcher, which does everything necessary
* for the "unique application" behavior: create the UniqueAppHandler as soon
* as possible, i.e. either right now or when the standalone app is closed.
*
* @param factory templatized factory to create the handler. Example:
* ... Note that the watcher takes ownership of the factory.
* @param plugin is the plugin application
*/
UniqueAppWatcher( UniqueAppHandlerFactoryBase* factory, Plugin* plugin );
virtual ~UniqueAppWatcher();
bool isRunningStandalone() const { return mRunningStandalone; }
protected slots:
void unregisteredFromDCOP( const QCString& appId );
private:
bool mRunningStandalone;
UniqueAppHandlerFactoryBase* mFactory;
Plugin* mPlugin;
};
} // namespace
#endif /* KONTACT_UNIQUEAPPHANDLER_H */

@ -0,0 +1,223 @@
#!/bin/bash
TARGET=`pwd`
if [ -e $TARGET'/debug' ]; then
BUILD=$TARGET'/debug'
else
BUILD=$TARGET
fi
LINKS=`echo ~`'/kde-debug'
HOME=`echo ~`
dest_files=(
"$LINKS/share/apps/basket/backgrounds/abstract.png"
"$LINKS/share/apps/basket/backgrounds/alien-artifact.png"
"$LINKS/share/apps/basket/backgrounds/alien-artifact.png.config"
"$LINKS/share/apps/basket/backgrounds/basket-title.png"
"$LINKS/share/apps/basket/backgrounds/green-curves.png"
"$LINKS/share/apps/basket/backgrounds/light.png"
"$LINKS/share/apps/basket/backgrounds/painting.png"
"$LINKS/share/apps/basket/backgrounds/pens.png"
"$LINKS/share/apps/basket/backgrounds/pins.png"
"$LINKS/share/apps/basket/backgrounds/rainbow-balls.png"
"$LINKS/share/apps/basket/backgrounds/rounds-line.png"
"$LINKS/share/apps/basket/backgrounds/todo.png"
"$LINKS/share/apps/basket/backgrounds/working.png"
"$LINKS/share/apps/basket/backgrounds/previews/abstract.png"
"$LINKS/share/apps/basket/backgrounds/previews/alien-artifact.png"
"$LINKS/share/apps/basket/backgrounds/previews/basket-title.png"
"$LINKS/share/apps/basket/backgrounds/previews/green-curves.png"
"$LINKS/share/apps/basket/backgrounds/previews/light.png"
"$LINKS/share/apps/basket/backgrounds/previews/painting.png"
"$LINKS/share/apps/basket/backgrounds/previews/pens.png"
"$LINKS/share/apps/basket/backgrounds/previews/pins.png"
"$LINKS/share/apps/basket/backgrounds/previews/rainbow-balls.png"
"$LINKS/share/apps/basket/backgrounds/previews/rounds-line.png"
"$LINKS/share/apps/basket/backgrounds/previews/todo.png"
"$LINKS/share/apps/basket/backgrounds/previews/working.png"
"$LINKS/share/apps/basket/images/insertion_help.png"
"$LINKS/share/apps/basket/images/tag_export_help.png"
"$LINKS/share/apps/basket/basket_part.rc"
"$LINKS/share/apps/basket/basketui.rc"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_priority_high.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_important.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_for_later.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_preference_excelent.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_priority_medium.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_progress_000.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_progress_100.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_preference_bad.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_preference_good.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_checkbox.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_progress_050.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_fun.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_progress_025.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_checkbox_checked.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_progress_075.png"
"$LINKS/share/apps/basket/icons/crystalsvg/16x16/actions/tag_priority_low.png"
"$LINKS/share/apps/kontact/ksettingsdialog/kontact_basketplugin.setdlg"
"$LINKS/share/services/kontact/basket.desktop"
"$LINKS/share/services/basket_config_general.desktop"
"$LINKS/share/services/basket_config_baskets.desktop"
"$LINKS/share/services/basket_config_new_notes.desktop"
"$LINKS/share/services/basket_config_notes_appearance.desktop"
"$LINKS/share/services/basket_config_apps.desktop"
"$LINKS/share/services/basket_part.desktop"
"$LINKS/share/applnk/Utilities/basket.desktop"
"$LINKS/lib/kde3/libkontact_basket.so"
"$LINKS/lib/kde3/libkontact_basket.la"
"$LINKS/lib/kde3/kcm_basket.so"
"$LINKS/lib/kde3/kcm_basket.la"
"$LINKS/lib/kde3/libbasketpart.so"
"$LINKS/lib/kde3/libbasketpart.la"
"$LINKS/lib/libbasketcommon.so"
"$LINKS/lib/libbasketcommon.la"
"$LINKS/bin/basket"
"$LINKS/share/icons/crystalsvg/16x16/actions/likeback_dislike.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/likeback_like.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/likeback_configure.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_priority_high.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_important.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_for_later.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_preference_excelent.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_priority_medium.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_progress_000.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_progress_100.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_preference_bad.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_preference_good.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_checkbox.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_progress_050.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_fun.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_progress_025.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_checkbox_checked.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_progress_075.png"
"$LINKS/share/icons/crystalsvg/16x16/actions/tag_priority_low.png"
"$LINKS/share/icons/crystalsvg/16x16/apps/basket.png"
"$LINKS/share/icons/crystalsvg/128x128/apps/basket.png"
"$LINKS/share/icons/crystalsvg/64x64/apps/basket.png"
"$LINKS/share/icons/crystalsvg/48x48/apps/basket.png"
"$LINKS/share/icons/crystalsvg/22x22/apps/basket.png"
"$LINKS/share/icons/crystalsvg/32x32/apps/basket.png"
"$LINKS/share/icons/crystalsvg/scalable/apps/basket.svg"
)
source_files=(
"$TARGET/backgrounds/abstract.png"
"$TARGET/backgrounds/alien-artifact.png"
"$TARGET/backgrounds/alien-artifact.png.config"
"$TARGET/backgrounds/basket-title.png"
"$TARGET/backgrounds/green-curves.png"
"$TARGET/backgrounds/light.png"
"$TARGET/backgrounds/painting.png"
"$TARGET/backgrounds/pens.png"
"$TARGET/backgrounds/pins.png"
"$TARGET/backgrounds/rainbow-balls.png"
"$TARGET/backgrounds/rounds-line.png"
"$TARGET/backgrounds/todo.png"
"$TARGET/backgrounds/working.png"
"$TARGET/backgrounds-previews/abstract.png"
"$TARGET/backgrounds-previews/alien-artifact.png"
"$TARGET/backgrounds-previews/basket-title.png"
"$TARGET/backgrounds-previews/green-curves.png"
"$TARGET/backgrounds-previews/light.png"
"$TARGET/backgrounds-previews/painting.png"
"$TARGET/backgrounds-previews/pens.png"
"$TARGET/backgrounds-previews/pins.png"
"$TARGET/backgrounds-previews/rainbow-balls.png"
"$TARGET/backgrounds-previews/rounds-line.png"
"$TARGET/backgrounds-previews/todo.png"
"$TARGET/backgrounds-previews/working.png"
"$TARGET/images/insertion_help.png"
"$TARGET/images/tag_export_help.png"
"$TARGET/src/basket_part.rc"
"$TARGET/src/basketui.rc"
"$TARGET/tags/cr16-action-tag_priority_high.png"
"$TARGET/tags/cr16-action-tag_important.png"
"$TARGET/tags/cr16-action-tag_for_later.png"
"$TARGET/tags/cr16-action-tag_preference_excelent.png"
"$TARGET/tags/cr16-action-tag_priority_medium.png"
"$TARGET/tags/cr16-action-tag_progress_000.png"
"$TARGET/tags/cr16-action-tag_progress_100.png"
"$TARGET/tags/cr16-action-tag_preference_bad.png"
"$TARGET/tags/cr16-action-tag_preference_good.png"
"$TARGET/tags/cr16-action-tag_checkbox.png"
"$TARGET/tags/cr16-action-tag_progress_050.png"
"$TARGET/tags/cr16-action-tag_fun.png"
"$TARGET/tags/cr16-action-tag_progress_025.png"
"$TARGET/tags/cr16-action-tag_checkbox_checked.png"
"$TARGET/tags/cr16-action-tag_progress_075.png"
"$TARGET/tags/cr16-action-tag_priority_low.png"
"$TARGET/kontact_plugin/kontact_basketplugin.setdlg"
"$TARGET/kontact_plugin/basket.desktop"
"$TARGET/src/basket_config_general.desktop"
"$TARGET/src/basket_config_baskets.desktop"
"$TARGET/src/basket_config_new_notes.desktop"
"$TARGET/src/basket_config_notes_appearance.desktop"
"$TARGET/src/basket_config_apps.desktop"
"$TARGET/src/basket_part.desktop"
"$TARGET/src/basket.desktop"
"$BUILD/kontact_plugin/.libs/libkontact_basket.so"
"$BUILD/kontact_plugin/.libs/libkontact_basket.la"
"$BUILD/src/.libs/kcm_basket.so"
"$BUILD/src/.libs/kcm_basket.la"
"$BUILD/src/.libs/libbasketpart.so"
"$BUILD/src/.libs/libbasketpart.la"
"$BUILD/src/.libs/libbasketcommon.so"
"$BUILD/src/.libs/libbasketcommon.la"
"$BUILD/src/.libs/basket"
"$TARGET/src/cr16-action-likeback_dislike.png"
"$TARGET/src/cr16-action-likeback_like.png"
"$TARGET/src/cr16-action-likeback_configure.png"
"$TARGET/tags/cr16-action-tag_priority_high.png"
"$TARGET/tags/cr16-action-tag_important.png"
"$TARGET/tags/cr16-action-tag_for_later.png"
"$TARGET/tags/cr16-action-tag_preference_excelent.png"
"$TARGET/tags/cr16-action-tag_priority_medium.png"
"$TARGET/tags/cr16-action-tag_progress_000.png"
"$TARGET/tags/cr16-action-tag_progress_100.png"
"$TARGET/tags/cr16-action-tag_preference_bad.png"
"$TARGET/tags/cr16-action-tag_preference_good.png"
"$TARGET/tags/cr16-action-tag_checkbox.png"
"$TARGET/tags/cr16-action-tag_progress_050.png"
"$TARGET/tags/cr16-action-tag_fun.png"
"$TARGET/tags/cr16-action-tag_progress_025.png"
"$TARGET/tags/cr16-action-tag_checkbox_checked.png"
"$TARGET/tags/cr16-action-tag_progress_075.png"
"$TARGET/tags/cr16-action-tag_priority_low.png"
"$TARGET/src/cr16-app-basket.png"
"$TARGET/src/cr128-app-basket.png"
"$TARGET/src/cr64-app-basket.png"
"$TARGET/src/cr48-app-basket.png"
"$TARGET/src/cr22-app-/basket.png"
"$TARGET/src/cr32-app-/basket.png"
"$TARGET/src/crsc-app-basket.svg"
)
function makedir()
{
if [ ! -d $1 ]; then
echo "Making dir: $1"
mkdir -p $1
fi
}
function softlink()
{
if [ -L $2 ]; then
rm $2
fi
makedir `dirname $2`
echo "Linking: $2->$1"
ln -s $1 $2
}
index=0
element_count=${#source_files[@]}
while [ "$index" -lt "$element_count" ]; do
softlink "${source_files[$index]}" "${dest_files[$index]}"
let "index = $index + 1"
done
softlink "$LINKS/lib" "$LINKS/lib64"

@ -0,0 +1,2 @@
POFILES = AUTO
noinst_HEADERS = basket.pot fr.po nl.po de.po nn.po zh_TW.po zh_CN.po pl_PL.po es.po pt.po

File diff suppressed because it is too large Load Diff

3611
po/cs.po

File diff suppressed because it is too large Load Diff

3509
po/da.po

File diff suppressed because it is too large Load Diff

3481
po/de.po

File diff suppressed because it is too large Load Diff

3339
po/es.po

File diff suppressed because it is too large Load Diff

3483
po/fr.po

File diff suppressed because it is too large Load Diff

3486
po/it.po

File diff suppressed because it is too large Load Diff

3440
po/ja.po

File diff suppressed because it is too large Load Diff

3814
po/nl.po

File diff suppressed because it is too large Load Diff

3518
po/nn.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3431
po/pt.po

File diff suppressed because it is too large Load Diff

3387
po/ru.po

File diff suppressed because it is too large Load Diff

3329
po/tr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,106 @@
# set the include path for X, qt and KDE
INCLUDES = $(all_includes)
# let automoc handle all of the meta source files (moc)
METASOURCES = AUTO
messages: rc.cpp
$(XGETTEXT) *.cpp -o $(podir)/basket.pot
KDE_ICON = AUTO
# these are the headers for your project
noinst_HEADERS = basket.h basketproperties.h mainwindow.h basket_part.h \
debugwindow.h linklabel.h variouswidgets.h xmlwork.h keyboard.h global.h settings.h \
focusedwidgets.h popupmenu.h basketfactory.h exporterdialog.h tag.h kcolorcombo2.h \
newbasketdialog.h tagsedit.h note.h notecontent.h notedrag.h noteedit.h notefactory.h \
filter.h tools.h backgroundmanager.h regiongrabber.h softwareimporters.h \
kicondialog.h kiconcanvas.h kgpgme.h crashhandler.h password.h bnpview.h \
systemtray.h clickablelabel.h colorpicker.h basketlistview.h qeffects.h likeback.h \
formatimporter.h aboutdata.h basketstatusbar.h basketdcopiface.h basket_options.h \
likeback_private.h application.h archive.h htmlexporter.h backup.h
#########################################################################
# COMMON FILES SECTION
#########################################################################
lib_LTLIBRARIES = libbasketcommon.la
AM_CPPFLAGS = $(GPGME_CFLAGS)
libbasketcommon_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
libbasketcommon_la_LIBADD = $(LIB_ARTSKDE) -lkio $(LIB_KDEUI) $(LIB_KDECORE) \
$(LIB_QT) $(LIBSOCKET) $(GPGME_LIBS) $(LIB_KPARTS) -lDCOP -lkdefx -lkdeui
libbasketcommon_la_SOURCES = \
archive.cpp bnpview.cpp settings.cpp basket.cpp basketproperties.cpp \
linklabel.cpp variouswidgets.cpp xmlwork.cpp keyboard.cpp \
global.cpp exporterdialog.cpp htmlexporter.cpp notefactory.cpp softwareimporters.cpp \
focusedwidgets.cpp popupmenu.cpp basketfactory.cpp \
tag.cpp qeffects.cpp kcolorcombo2.cpp newbasketdialog.cpp tagsedit.cpp \
formatimporter.cpp note.cpp notecontent.cpp notedrag.cpp noteedit.cpp \
filter.cpp tools.cpp backgroundmanager.cpp regiongrabber.cpp \
kicondialogui.ui kicondialog.cpp kiconcanvas.cpp kgpgme.cpp likeback.cpp \
crashhandler.cpp passwordlayout.ui password.cpp colorpicker.cpp \
basketlistview.cpp debugwindow.cpp systemtray.cpp aboutdata.cpp \
basketstatusbar.cpp clickablelabel.cpp basketdcopiface.skel backup.cpp
#########################################################################
# APPLICATION SECTION
#########################################################################
# this is the program that gets installed. it's name is used for all
# of the other Makefile.am variables
bin_PROGRAMS = basket
# the application source, library search path, and link libraries
basket_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_KUTILS)
basket_LDADD = libbasketcommon.la
# this is where the desktop file will go
shelldesktopdir = $(xdg_appsdir)
shelldesktop_DATA = basket.desktop
# this is where the shell's XML-GUI resource file goes
rcdir = $(kde_datadir)/basket
rc_DATA = basketui.rc
basket_SOURCES = main.cpp mainwindow.cpp application.cpp
kde_icon_KDEICON = cr128-app-basket.png cr16-app-basket.png cr22-app-basket.png \
cr32-app-basket.png cr48-app-basket.png cr64-app-basket.png hi16-app-basket_old.png \
hi32-app-basket_old.png crsc-app-basket.svg \
cr16-action-likeback_like.png cr16-action-likeback_dislike.png \
cr16-action-likeback_bug.png cr16-action-likeback_feature.png
##################
# KPART SECTION
##################
kde_module_LTLIBRARIES = kcm_basket.la libbasketpart.la
libbasketpart_la_SOURCES = basket_part.cpp
libbasketpart_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) -module -avoid-version -no-undefined
libbasketpart_la_LIBADD = libbasketcommon.la -lkparts -lkdeui $(LIB_KDECORE) $(LIB_QT) -lDCOP
kcm_basket_la_SOURCES = kcm_basket.cpp
kcm_basket_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
kcm_basket_la_LIBADD = libbasketcommon.la $(LIB_KDECORE) $(LIB_QT) -lkdeui
# this is where the desktop file will go
partdesktopdir = $(kde_servicesdir)
partdesktop_DATA = basket_part.desktop
# this is where the part's XML-GUI resource file goes
partdir = $(kde_datadir)/basket
part_DATA = basket_part.rc
kde_services_DATA = \
basket_config_general.desktop \
basket_config_baskets.desktop \
basket_config_new_notes.desktop \
basket_config_notes_appearance.desktop \
basket_config_apps.desktop \
basket_config_features.desktop \
basket_config_notes.desktop

@ -0,0 +1,59 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "aboutdata.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
static const char description[] = I18N_NOOP(
"<p><b>Taking care of your ideas.</b></p>"
"<p>A note-taking application that makes it easy to record ideas as you think, and quickly find them later. "
"Organizing your notes has never been so easy.</p>");
// Or how to make order of disorganized toughts.
AboutData::AboutData()
: KAboutData( "basket", I18N_NOOP("BasKet Note Pads"),
VERSION, description, KAboutData::License_GPL_V2,
"(c) 2003-2007, S\303\251bastien Lao\303\273t", 0,
"http://basket.kde.org/",
"basket-devel@lists.sourceforge.net" )
{
addAuthor( "Kelvie Wong",
I18N_NOOP("Maintainer"),
"kelvie@ieee.org" );
addAuthor( "S\303\251bastien Lao\303\273t",
I18N_NOOP("Original Author"),
"slaout@linux62.org" );
addAuthor( "Petri Damst\303\251n",
I18N_NOOP("Basket encryption, Kontact integration, KnowIt importer"),
"damu@iki.fi" );
addAuthor( "Alex Gontmakher",
I18N_NOOP("Baskets auto lock, save-status icon, HTML copy/paste, basket name tooltip, drop to basket name"),
"gsasha@cs.technion.ac.il" );
addAuthor( "Marco Martin",
I18N_NOOP("Icon"),
"m4rt@libero.it" );
}

@ -0,0 +1,35 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef ABOUTDATA_H
#define ABOUTDATA_H
#include <kaboutdata.h>
/**
@author Sébastien Laoût <slaout@linux62.org>
*/
class AboutData : public KAboutData
{
public:
AboutData();
};
#endif

@ -0,0 +1,61 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kcmdlineargs.h>
#include <qstring.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qtimer.h>
#include "application.h"
#include "global.h"
#include "bnpview.h"
Application::Application()
: KUniqueApplication()
{
}
Application::~Application()
{
}
int Application::newInstance()
{
KUniqueApplication::newInstance();
// Open the basket archive or template file supplied as argument:
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
if (args && args->count() >= 1) {
QString fileName = QFile::decodeName(args->arg(args->count() - 1));
if (QFile::exists(fileName)) {
QFileInfo fileInfo(fileName);
if (!fileInfo.isDir()) { // Do not mis-interpret data-folder param!
// Tags are not loaded until Global::bnpView::lateInit() is called.
// It is called 0ms after the application start.
BNPView::s_fileToOpen = fileName;
QTimer::singleShot( 100, Global::bnpView, SLOT(delayedOpenArchive()) );
// Global::bnpView->openArchive(fileName);
args->clear();
}
}
}
return 0;
}

@ -0,0 +1,38 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef APPLICATION_H
#define APPLICATION_H
#include <kuniqueapplication.h>
#include <qstring.h>
/**
* @author Sébastien Laoût <slaout@linux62.org>
*/
class Application : public KUniqueApplication
{
public:
Application();
~Application();
int newInstance();
};
#endif // APPLICATION_H

@ -0,0 +1,637 @@
/***************************************************************************
* Copyright (C) 2006 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstring.h>
#include <qstringlist.h>
#include <qvaluelist.h>
#include <qmap.h>
#include <qdir.h>
#include <ktar.h>
#include <qdom.h>
#include <kmessagebox.h>
#include <qpixmap.h>
#include <qpainter.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <kprogress.h>
#include <kmainwindow.h>
#include "archive.h"
#include "global.h"
#include "bnpview.h"
#include "basket.h"
#include "basketlistview.h"
#include "basketfactory.h"
#include "tag.h"
#include "xmlwork.h"
#include "tools.h"
#include "backgroundmanager.h"
#include "formatimporter.h"
#include <iostream>
void Archive::save(Basket *basket, bool withSubBaskets, const QString &destination)
{
QDir dir;
KProgressDialog dialog(0, 0, i18n("Save as Basket Archive"), i18n("Saving as basket archive. Please wait..."), /*Not modal, for password dialogs!*/false);
dialog.showCancelButton(false);
dialog.setAutoClose(true);
dialog.show();
KProgress *progress = dialog.progressBar();
progress->setTotalSteps(/*Preparation:*/1 + /*Finishing:*/1 + /*Basket:*/1 + /*SubBaskets:*/(withSubBaskets ? Global::bnpView->basketCount(Global::bnpView->listViewItemForBasket(basket)) : 0));
progress->setValue(0);
// Create the temporar folder:
QString tempFolder = Global::savesFolder() + "temp-archive/";
dir.mkdir(tempFolder);
// Create the temporar archive file:
QString tempDestination = tempFolder + "temp-archive.tar.gz";
KTar tar(tempDestination, "application/x-gzip");
tar.open(IO_WriteOnly);
tar.writeDir("baskets", "", "");
progress->advance(1); // Preparation finished
std::cout << "Preparation finished out of " << progress->totalSteps() << std::endl;
// Copy the baskets data into the archive:
QStringList backgrounds;
saveBasketToArchive(basket, withSubBaskets, &tar, backgrounds, tempFolder, progress);
// Create a Small baskets.xml Document:
QDomDocument document("basketTree");
QDomElement root = document.createElement("basketTree");
document.appendChild(root);
Global::bnpView->saveSubHierarchy(Global::bnpView->listViewItemForBasket(basket), document, root, withSubBaskets);
Basket::safelySaveToFile(tempFolder + "baskets.xml", "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString());
tar.addLocalFile(tempFolder + "baskets.xml", "baskets/baskets.xml");
dir.remove(tempFolder + "baskets.xml");
// Save a Small tags.xml Document:
QValueList<Tag*> tags;
listUsedTags(basket, withSubBaskets, tags);
Tag::saveTagsTo(tags, tempFolder + "tags.xml");
tar.addLocalFile(tempFolder + "tags.xml", "tags.xml");
dir.remove(tempFolder + "tags.xml");
// Save Tag Emblems (in case they are loaded on a computer that do not have those icons):
QString tempIconFile = tempFolder + "icon.png";
for (Tag::List::iterator it = tags.begin(); it != tags.end(); ++it) {
State::List states = (*it)->states();
for (State::List::iterator it2 = states.begin(); it2 != states.end(); ++it2) {
State *state = (*it2);
QPixmap icon = kapp->iconLoader()->loadIcon(state->emblem(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
if (!icon.isNull()) {
icon.save(tempIconFile, "PNG");
QString iconFileName = state->emblem().replace('/', '_');
tar.addLocalFile(tempIconFile, "tag-emblems/" + iconFileName);
}
}
}
dir.remove(tempIconFile);
// Finish Tar.Gz Exportation:
tar.close();
// Computing the File Preview:
Basket *previewBasket = basket; // FIXME: Use the first non-empty basket!
QPixmap previewPixmap(previewBasket->visibleWidth(), previewBasket->visibleHeight());
QPainter painter(&previewPixmap);
// Save old state, and make the look clean ("smile, you are filmed!"):
NoteSelection *selection = previewBasket->selectedNotes();
previewBasket->unselectAll();
Note *focusedNote = previewBasket->focusedNote();
previewBasket->setFocusedNote(0);
previewBasket->doHoverEffects(0, Note::None);
// Take the screenshot:
previewBasket->drawContents(&painter, 0, 0, previewPixmap.width(), previewPixmap.height());
// Go back to the old look:
previewBasket->selectSelection(selection);
previewBasket->setFocusedNote(focusedNote);
previewBasket->doHoverEffects();
// End and save our splandid painting:
painter.end();
QImage previewImage = previewPixmap.convertToImage();
const int PREVIEW_SIZE = 256;
previewImage = previewImage.scale(PREVIEW_SIZE, PREVIEW_SIZE, QImage::ScaleMin);
previewImage.save(tempFolder + "preview.png", "PNG");
// Finaly Save to the Real Destination file:
QFile file(destination);
if (file.open(IO_WriteOnly)) {
ulong previewSize = QFile(tempFolder + "preview.png").size();
ulong archiveSize = QFile(tempDestination).size();
QTextStream stream(&file);
stream.setEncoding(QTextStream::Latin1);
stream << "BasKetNP:archive\n"
<< "version:0.6.1\n"
// << "read-compatible:0.6.1\n"
// << "write-compatible:0.6.1\n"
<< "preview*:" << previewSize << "\n";
// Copy the Preview File:
const Q_ULONG BUFFER_SIZE = 1024;
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
QFile previewFile(tempFolder + "preview.png");
if (previewFile.open(IO_ReadOnly)) {
while ((sizeRead = previewFile.readBlock(buffer, BUFFER_SIZE)) > 0)
file.writeBlock(buffer, sizeRead);
}
stream << "archive*:" << archiveSize << "\n";
// Copy the Archive File:
QFile archiveFile(tempDestination);
if (archiveFile.open(IO_ReadOnly)) {
while ((sizeRead = archiveFile.readBlock(buffer, BUFFER_SIZE)) > 0)
file.writeBlock(buffer, sizeRead);
}
// Clean Up:
delete buffer;
buffer = 0;
file.close();
}
progress->advance(1); // Finishing finished
std::cout << "Finishing finished" << std::endl;
// Clean Up Everything:
dir.remove(tempFolder + "preview.png");
dir.remove(tempDestination);
dir.rmdir(tempFolder);
}
void Archive::saveBasketToArchive(Basket *basket, bool recursive, KTar *tar, QStringList &backgrounds, const QString &tempFolder, KProgress *progress)
{
// Basket need to be loaded for tags exportation.
// We load it NOW so that the progress bar really reflect the state of the exportation:
if (!basket->isLoaded()) {
basket->load();
}
QDir dir;
// Save basket data:
tar->addLocalDirectory(basket->fullPath(), "baskets/" + basket->folderName());
tar->addLocalFile(basket->fullPath() + ".basket", "baskets/" + basket->folderName() + ".basket"); // The hidden files were not added
// Save basket icon:
QString tempIconFile = tempFolder + "icon.png";
if (!basket->icon().isEmpty() && basket->icon() != "basket") {
QPixmap icon = kapp->iconLoader()->loadIcon(basket->icon(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
if (!icon.isNull()) {
icon.save(tempIconFile, "PNG");
QString iconFileName = basket->icon().replace('/', '_');
tar->addLocalFile(tempIconFile, "basket-icons/" + iconFileName);
}
}
// Save basket backgorund image:
QString imageName = basket->backgroundImageName();
if (!basket->backgroundImageName().isEmpty() && !backgrounds.contains(imageName)) {
QString backgroundPath = Global::backgroundManager->pathForImageName(imageName);
if (!backgroundPath.isEmpty()) {
// Save the background image:
tar->addLocalFile(backgroundPath, "backgrounds/" + imageName);
// Save the preview image:
QString previewPath = Global::backgroundManager->previewPathForImageName(imageName);
if (!previewPath.isEmpty())
tar->addLocalFile(previewPath, "backgrounds/previews/" + imageName);
// Save the configuration file:
QString configPath = backgroundPath + ".config";
if (dir.exists(configPath))
tar->addLocalFile(configPath, "backgrounds/" + imageName + ".config");
}
backgrounds.append(imageName);
}
progress->advance(1); // Basket exportation finished
std::cout << basket->basketName() << " finished" << std::endl;
// Recursively save child baskets:
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
if (recursive && item->firstChild()) {
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
saveBasketToArchive(child->basket(), recursive, tar, backgrounds, tempFolder, progress);
}
}
}
void Archive::listUsedTags(Basket *basket, bool recursive, QValueList<Tag*> &list)
{
basket->listUsedTags(list);
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
if (recursive && item->firstChild()) {
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
listUsedTags(child->basket(), recursive, list);
}
}
}
void Archive::open(const QString &path)
{
// Create the temporar folder:
QString tempFolder = Global::savesFolder() + "temp-archive/";
QDir dir;
dir.mkdir(tempFolder);
const Q_ULONG BUFFER_SIZE = 1024;
QFile file(path);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::Latin1);
QString line = stream.readLine();
if (line != "BasKetNP:archive") {
KMessageBox::error(0, i18n("This file is not a basket archive."), i18n("Basket Archive Error"));
file.close();
Tools::deleteRecursively(tempFolder);
return;
}
QString version;
QStringList readCompatibleVersions;
QStringList writeCompatibleVersions;
while (!stream.atEnd()) {
// Get Key/Value Pair From the Line to Read:
line = stream.readLine();
int index = line.find(':');
QString key;
QString value;
if (index >= 0) {
key = line.left(index);
value = line.right(line.length() - index - 1);
} else {
key = line;
value = "";
}
if (key == "version") {
version = value;
} else if (key == "read-compatible") {
readCompatibleVersions = QStringList::split(value, ";");
} else if (key == "write-compatible") {
writeCompatibleVersions = QStringList::split(value, ";");
} else if (key == "preview*") {
bool ok;
ulong size = value.toULong(&ok);
if (!ok) {
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
file.close();
Tools::deleteRecursively(tempFolder);
return;
}
// Get the preview file:
//FIXME: We do not need the preview for now
// QFile previewFile(tempFolder + "preview.png");
// if (previewFile.open(IO_WriteOnly)) {
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
// previewFile.writeBlock(buffer, sizeRead);
size -= sizeRead;
}
// previewFile.close();
delete buffer;
// }
} else if (key == "archive*") {
if (version != "0.6.1" && readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
KMessageBox::information(
0,
i18n("This file was created with a recent version of %1. "
"It can be opened but not every information will be available to you. "
"For instance, some notes may be missing because they are of a type only available in new versions. "
"When saving the file back, consider to save it to another file, to preserve the original one.")
.arg(kapp->aboutData()->programName()),
i18n("Basket Archive Error")
);
}
if (version != "0.6.1" && !readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
KMessageBox::error(
0,
i18n("This file was created with a recent version of %1. Please upgrade to a newer version to be able to open that file.")
.arg(kapp->aboutData()->programName()),
i18n("Basket Archive Error")
);
file.close();
Tools::deleteRecursively(tempFolder);
return;
}
bool ok;
ulong size = value.toULong(&ok);
if (!ok) {
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
file.close();
Tools::deleteRecursively(tempFolder);
return;
}
Global::mainWindow()->raise();
// Get the archive file:
QString tempArchive = tempFolder + "temp-archive.tar.gz";
QFile archiveFile(tempArchive);
if (archiveFile.open(IO_WriteOnly)) {
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
archiveFile.writeBlock(buffer, sizeRead);
size -= sizeRead;
}
archiveFile.close();
delete buffer;
// Extract the Archive:
QString extractionFolder = tempFolder + "extraction/";
QDir dir;
dir.mkdir(extractionFolder);
KTar tar(tempArchive, "application/x-gzip");
tar.open(IO_ReadOnly);
tar.directory()->copyTo(extractionFolder);
tar.close();
// Import the Tags:
importTagEmblems(extractionFolder); // Import and rename tag emblems BEFORE loading them!
QMap<QString, QString> mergedStates = Tag::loadTags(extractionFolder + "tags.xml");
QMap<QString, QString>::Iterator it;
if (mergedStates.count() > 0) {
Tag::saveTags();
}
// Import the Background Images:
importArchivedBackgroundImages(extractionFolder);
// Import the Baskets:
renameBasketFolders(extractionFolder, mergedStates);
}
} else if (key.endsWith("*")) {
// We do not know what it is, but we should read the embedded-file in order to discard it:
bool ok;
ulong size = value.toULong(&ok);
if (!ok) {
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
file.close();
Tools::deleteRecursively(tempFolder);
return;
}
// Get the archive file:
char *buffer = new char[BUFFER_SIZE];
Q_LONG sizeRead;
while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
size -= sizeRead;
}
delete buffer;
} else {
// We do not know what it is, and we do not care.
}
// Analyse the Value, if Understood:
}
file.close();
}
Tools::deleteRecursively(tempFolder);
}
/**
* When opening a basket archive that come from another computer,
* it can contains tags that use icons (emblems) that are not present on that computer.
* Fortunately, basket archives contains a copy of every used icons.
* This method check for every emblems and import the missing ones.
* It also modify the tags.xml copy for the emblems to point to the absolute path of the impported icons.
*/
void Archive::importTagEmblems(const QString &extractionFolder)
{
QDomDocument *document = XMLWork::openFile("basketTags", extractionFolder + "tags.xml");
if (document == 0)
return;
QDomElement docElem = document->documentElement();
QDir dir;
dir.mkdir(Global::savesFolder() + "tag-emblems/");
FormatImporter copier; // Only used to copy files synchronously
QDomNode node = docElem.firstChild();
while (!node.isNull()) {
QDomElement element = node.toElement();
if ( (!element.isNull()) && element.tagName() == "tag" ) {
QDomNode subNode = element.firstChild();
while (!subNode.isNull()) {
QDomElement subElement = subNode.toElement();
if ( (!subElement.isNull()) && subElement.tagName() == "state" ) {
QString emblemName = XMLWork::getElementText(subElement, "emblem");
if (!emblemName.isEmpty()) {
QPixmap emblem = kapp->iconLoader()->loadIcon(emblemName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
// The icon does not exists on that computer, import it:
if (emblem.isNull()) {
// Of the emblem path was eg. "/home/seb/emblem.png", it was exported as "tag-emblems/_home_seb_emblem.png".
// So we need to copy that image to "~/.kde/share/apps/basket/tag-emblems/emblem.png":
int slashIndex = emblemName.findRev("/");
QString emblemFileName = (slashIndex < 0 ? emblemName : emblemName.right(slashIndex - 2));
QString source = extractionFolder + "tag-emblems/" + emblemName.replace('/', '_');
QString destination = Global::savesFolder() + "tag-emblems/" + emblemFileName;
if (!dir.exists(destination))
copier.copyFolder(source, destination);
// Replace the emblem path in the tags.xml copy:
QDomElement emblemElement = XMLWork::getElement(subElement, "emblem");
subElement.removeChild(emblemElement);
XMLWork::addElement(*document, subElement, "emblem", destination);
}
}
}
subNode = subNode.nextSibling();
}
}
node = node.nextSibling();
}
Basket::safelySaveToFile(extractionFolder + "tags.xml", document->toString());
}
void Archive::importArchivedBackgroundImages(const QString &extractionFolder)
{
FormatImporter copier; // Only used to copy files synchronously
QString destFolder = KGlobal::dirs()->saveLocation("data", "basket/backgrounds/");
QDir dir(extractionFolder + "backgrounds/", /*nameFilder=*/"*.png", /*sortSpec=*/QDir::Name | QDir::IgnoreCase, /*filterSpec=*/QDir::Files | QDir::NoSymLinks);
QStringList files = dir.entryList();
for (QStringList::Iterator it = files.begin(); it != files.end(); ++it) {
QString image = *it;
if (!Global::backgroundManager->exists(image)) {
// Copy images:
QString imageSource = extractionFolder + "backgrounds/" + image;
QString imageDest = destFolder + image;
copier.copyFolder(imageSource, imageDest);
// Copy configuration file:
QString configSource = extractionFolder + "backgrounds/" + image + ".config";
QString configDest = destFolder + image;
if (dir.exists(configSource))
copier.copyFolder(configSource, configDest);
// Copy preview:
QString previewSource = extractionFolder + "backgrounds/previews/" + image;
QString previewDest = destFolder + "previews/" + image;
if (dir.exists(previewSource)) {
dir.mkdir(destFolder + "previews/"); // Make sure the folder exists!
copier.copyFolder(previewSource, previewDest);
}
// Append image to database:
Global::backgroundManager->addImage(imageDest);
}
}
}
void Archive::renameBasketFolders(const QString &extractionFolder, QMap<QString, QString> &mergedStates)
{
QDomDocument *doc = XMLWork::openFile("basketTree", extractionFolder + "baskets/baskets.xml");
if (doc != 0) {
QMap<QString, QString> folderMap;
QDomElement docElem = doc->documentElement();
QDomNode node = docElem.firstChild();
renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
loadExtractedBaskets(extractionFolder, node, folderMap, 0);
}
}
void Archive::renameBasketFolder(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, QMap<QString, QString> &mergedStates)
{
QDomNode n = basketNode;
while ( ! n.isNull() ) {
QDomElement element = n.toElement();
if ( (!element.isNull()) && element.tagName() == "basket" ) {
QString folderName = element.attribute("folderName");
if (!folderName.isEmpty()) {
// Find a folder name:
QString newFolderName = BasketFactory::newFolderName();
folderMap[folderName] = newFolderName;
// Reserve the folder name:
QDir dir;
dir.mkdir(Global::basketsFolder() + newFolderName);
// Rename the merged tag ids:
// if (mergedStates.count() > 0) {
renameMergedStatesAndBasketIcon(extractionFolder + "baskets/" + folderName + ".basket", mergedStates, extractionFolder);
// }
// Child baskets:
QDomNode node = element.firstChild();
renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
}
}
n = n.nextSibling();
}
}
void Archive::renameMergedStatesAndBasketIcon(const QString &fullPath, QMap<QString, QString> &mergedStates, const QString &extractionFolder)
{
QDomDocument *doc = XMLWork::openFile("basket", fullPath);
if (doc == 0)
return;
QDomElement docElem = doc->documentElement();
QDomElement properties = XMLWork::getElement(docElem, "properties");
importBasketIcon(properties, extractionFolder);
QDomElement notes = XMLWork::getElement(docElem, "notes");
if (mergedStates.count() > 0)
renameMergedStates(notes, mergedStates);
Basket::safelySaveToFile(fullPath, /*"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + */doc->toString());
}
void Archive::importBasketIcon(QDomElement properties, const QString &extractionFolder)
{
QString iconName = XMLWork::getElementText(properties, "icon");
if (!iconName.isEmpty() && iconName != "basket") {
QPixmap icon = kapp->iconLoader()->loadIcon(iconName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
// The icon does not exists on that computer, import it:
if (icon.isNull()) {
QDir dir;
dir.mkdir(Global::savesFolder() + "basket-icons/");
FormatImporter copier; // Only used to copy files synchronously
// Of the icon path was eg. "/home/seb/icon.png", it was exported as "basket-icons/_home_seb_icon.png".
// So we need to copy that image to "~/.kde/share/apps/basket/basket-icons/icon.png":
int slashIndex = iconName.findRev("/");
QString iconFileName = (slashIndex < 0 ? iconName : iconName.right(slashIndex - 2));
QString source = extractionFolder + "basket-icons/" + iconName.replace('/', '_');
QString destination = Global::savesFolder() + "basket-icons/" + iconFileName;
if (!dir.exists(destination))
copier.copyFolder(source, destination);
// Replace the emblem path in the tags.xml copy:
QDomElement iconElement = XMLWork::getElement(properties, "icon");
properties.removeChild(iconElement);
QDomDocument document = properties.ownerDocument();
XMLWork::addElement(document, properties, "icon", destination);
}
}
}
void Archive::renameMergedStates(QDomNode notes, QMap<QString, QString> &mergedStates)
{
QDomNode n = notes.firstChild();
while ( ! n.isNull() ) {
QDomElement element = n.toElement();
if (!element.isNull()) {
if (element.tagName() == "group" ) {
renameMergedStates(n, mergedStates);
} else if (element.tagName() == "note") {
QString tags = XMLWork::getElementText(element, "tags");
if (!tags.isEmpty()) {
QStringList tagNames = QStringList::split(";", tags);
for (QStringList::Iterator it = tagNames.begin(); it != tagNames.end(); ++it) {
QString &tag = *it;
if (mergedStates.contains(tag)) {
tag = mergedStates[tag];
}
}
QString newTags = tagNames.join(";");
QDomElement tagsElement = XMLWork::getElement(element, "tags");
element.removeChild(tagsElement);
QDomDocument document = element.ownerDocument();
XMLWork::addElement(document, element, "tags", newTags);
}
}
}
n = n.nextSibling();
}
}
void Archive::loadExtractedBaskets(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, Basket *parent)
{
bool basketSetAsCurrent = (parent != 0);
QDomNode n = basketNode;
while ( ! n.isNull() ) {
QDomElement element = n.toElement();
if ( (!element.isNull()) && element.tagName() == "basket" ) {
QString folderName = element.attribute("folderName");
if (!folderName.isEmpty()) {
// Move the basket folder to its destination, while renaming it uniquely:
QString newFolderName = folderMap[folderName];
FormatImporter copier;
// The folder has been "reserved" by creating it. Avoid asking the user to override:
QDir dir;
dir.rmdir(Global::basketsFolder() + newFolderName);
copier.moveFolder(extractionFolder + "baskets/" + folderName, Global::basketsFolder() + newFolderName);
// Append and load the basket in the tree:
Basket *basket = Global::bnpView->loadBasket(newFolderName);
BasketListViewItem *basketItem = Global::bnpView->appendBasket(basket, (basket && parent ? Global::bnpView->listViewItemForBasket(parent) : 0));
basketItem->setOpen(!XMLWork::trueOrFalse(element.attribute("folded", "false"), false));
QDomElement properties = XMLWork::getElement(element, "properties");
importBasketIcon(properties, extractionFolder); // Rename the icon fileName if necessary
basket->loadProperties(properties);
// Open the first basket of the archive:
if (!basketSetAsCurrent) {
Global::bnpView->setCurrentBasket(basket);
basketSetAsCurrent = true;
}
QDomNode node = element.firstChild();
loadExtractedBaskets(extractionFolder, node, folderMap, basket);
}
}
n = n.nextSibling();
}
}

@ -0,0 +1,59 @@
/***************************************************************************
* Copyright (C) 2006 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef ARCHIVE_H
#define ARCHIVE_H
#include <qvaluelist.h>
#include <qmap.h>
class Basket;
class Tag;
class QString;
class QStringList;
class QDomNode;
class KTar;
class KProgress;
/**
* @author Sébastien Laoût <slaout@linux62.org>
*/
class Archive
{
public:
static void save(Basket *basket, bool withSubBaskets, const QString &destination);
static void open(const QString &path);
private:
// Convenient Methods for Saving:
static void saveBasketToArchive(Basket *basket, bool recursive, KTar *tar, QStringList &backgrounds, const QString &tempFolder, KProgress *progress);
static void listUsedTags(Basket *basket, bool recursive, QValueList<Tag*> &list);
// Convenient Methods for Loading:
static void renameBasketFolders(const QString &extractionFolder, QMap<QString, QString> &mergedStates);
static void renameBasketFolder(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, QMap<QString, QString> &mergedStates);
static void renameMergedStatesAndBasketIcon(const QString &fullPath, QMap<QString, QString> &mergedStates, const QString &extractionFolder);
static void renameMergedStates(QDomNode notes, QMap<QString, QString> &mergedStates);
static void importBasketIcon(QDomElement properties, const QString &extractionFolder);
static void loadExtractedBaskets(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, Basket *parent);
static void importTagEmblems(const QString &extractionFolder);
static void importArchivedBackgroundImages(const QString &extractionFolder);
};
#endif

@ -0,0 +1,394 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kurl.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <qpainter.h>
#include <qdir.h>
#include <qimage.h>
#include <iostream>
#include "backgroundmanager.h"
/** class BackgroundEntry: */
BackgroundEntry::BackgroundEntry(const QString &location)
{
this->location = location;
name = KURL(location).fileName();
tiled = false;
pixmap = 0;
preview = 0;
customersCount = 0;
}
BackgroundEntry::~BackgroundEntry()
{
delete pixmap;
delete preview;
}
/** class OpaqueBackgroundEntry: */
OpaqueBackgroundEntry::OpaqueBackgroundEntry(const QString &name, const QColor &color)
{
this->name = name;
this->color = color;
pixmap = 0;
customersCount = 0;
}
OpaqueBackgroundEntry::~OpaqueBackgroundEntry()
{
delete pixmap;
}
/** class BackgroundManager: */
BackgroundManager::BackgroundManager()
{
/// std::cout << "BackgroundManager: Found the following background images in ";
QStringList directories = KGlobal::dirs()->resourceDirs("data"); // eg. { "/home/seb/.kde/share/apps/", "/usr/share/apps/" }
// For each folder:
for (QStringList::Iterator it = directories.begin(); it != directories.end(); ++it) {
// For each file in those directories:
QDir dir(*it + "basket/backgrounds/", /*nameFilder=*/"*.png", /*sortSpec=*/QDir::Name | QDir::IgnoreCase, /*filterSpec=*/QDir::Files | QDir::NoSymLinks);
/// std::cout << *it + "basket/backgrounds/ ";
QStringList files = dir.entryList();
for (QStringList::Iterator it2 = files.begin(); it2 != files.end(); ++it2) // TODO: If an image name is present in two folders?
addImage(*it + "basket/backgrounds/" + *it2);
}
/// std::cout << ":" << std::endl;
/// for (BackgroundsList::Iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
/// std::cout << "* " << (*it)->location << " [ref: " << (*it)->name << "]" << std::endl;
connect( &m_garbageTimer, SIGNAL(timeout()), this, SLOT(doGarbage()) );
}
BackgroundManager::~BackgroundManager()
{
}
void BackgroundManager::addImage(const QString &fullPath)
{
m_backgroundsList.append(new BackgroundEntry(fullPath));
}
BackgroundEntry* BackgroundManager::backgroundEntryFor(const QString &image)
{
for (BackgroundsList::Iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
if ((*it)->name == image)
return *it;
return 0;
}
OpaqueBackgroundEntry* BackgroundManager::opaqueBackgroundEntryFor(const QString &image, const QColor &color)
{
for (OpaqueBackgroundsList::Iterator it = m_opaqueBackgroundsList.begin(); it != m_opaqueBackgroundsList.end(); ++it)
if ((*it)->name == image && (*it)->color == color)
return *it;
return 0;
}
bool BackgroundManager::subscribe(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (entry) {
// If it's the first time something subscribe to this image:
if (!entry->pixmap) {
// Try to load the pixmap:
entry->pixmap = new QPixmap(entry->location);
// Try to figure out if it's a tiled background image or not (default to NO):
KSimpleConfig config(entry->location + ".config", /*readOnly=*/true);
config.setGroup("BasKet Background Image Configuration");
entry->tiled = config.readBoolEntry("tiled", false);
}
// Return if the image loading has failed:
if (entry->pixmap->isNull()) {
/// std::cout << "BackgroundManager: Failed to load " << entry->location << std::endl;
return false;
}
// Success: effectively subscribe:
++entry->customersCount;
return true;
} else {
// Don't exist: subscription failed:
/// std::cout << "BackgroundManager: Requested unexisting image: " << image << std::endl;
return false;
}
}
bool BackgroundManager::subscribe(const QString &image, const QColor &color)
{
BackgroundEntry *backgroundEntry = backgroundEntryFor(image);
// First, if the image doesn't exist, isn't subscribed, or failed to load then we don't go further:
if (!backgroundEntry || !backgroundEntry->pixmap || backgroundEntry->pixmap->isNull()) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: (" << image << "," << color.name() << ")..." << std::endl;
return false;
}
OpaqueBackgroundEntry *opaqueBackgroundEntry = opaqueBackgroundEntryFor(image, color);
// If this couple is requested for the first time or it haven't been subscribed for a long time enough, create it:
if (!opaqueBackgroundEntry) {
/// std::cout << "BackgroundManager: Computing (" << image << "," << color.name() << ")..." << std::endl;
opaqueBackgroundEntry = new OpaqueBackgroundEntry(image, color);
opaqueBackgroundEntry->pixmap = new QPixmap(backgroundEntry->pixmap->size());
opaqueBackgroundEntry->pixmap->fill(color);
QPainter painter(opaqueBackgroundEntry->pixmap);
painter.drawPixmap(0, 0, *(backgroundEntry->pixmap));
painter.end();
m_opaqueBackgroundsList.append(opaqueBackgroundEntry);
}
// We are now sure the entry exist, do the subscription:
++opaqueBackgroundEntry->customersCount;
return true;
}
void BackgroundManager::unsubscribe(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (!entry) {
/// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed image: " << image << std::endl;
return;
}
--entry->customersCount;
if (entry->customersCount <= 0)
requestDelayedGarbage();
}
void BackgroundManager::unsubscribe(const QString &image, const QColor &color)
{
OpaqueBackgroundEntry *entry = opaqueBackgroundEntryFor(image, color);
if (!entry) {
/// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
return;
}
--entry->customersCount;
if (entry->customersCount <= 0)
requestDelayedGarbage();
}
QPixmap* BackgroundManager::pixmap(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (!entry || !entry->pixmap || entry->pixmap->isNull()) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
return 0;
}
return entry->pixmap;
}
QPixmap* BackgroundManager::opaquePixmap(const QString &image, const QColor &color)
{
OpaqueBackgroundEntry *entry = opaqueBackgroundEntryFor(image, color);
if (!entry || !entry->pixmap || entry->pixmap->isNull()) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
return 0;
}
return entry->pixmap;
}
bool BackgroundManager::tiled(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (!entry || !entry->pixmap || entry->pixmap->isNull()) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
return false;
}
return entry->tiled;
}
bool BackgroundManager::exists(const QString &image)
{
for (BackgroundsList::iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
if ((*it)->name == image)
return true;
return false;
}
QStringList BackgroundManager::imageNames()
{
QStringList list;
for (BackgroundsList::iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
list.append((*it)->name);
return list;
}
QPixmap* BackgroundManager::preview(const QString &image)
{
static const int MAX_WIDTH = 100;
static const int MAX_HEIGHT = 75;
static const QColor PREVIEW_BG = Qt::white;
BackgroundEntry *entry = backgroundEntryFor(image);
if (!entry) {
/// std::cout << "BackgroundManager: Requested the preview of an unexisting image: " << image << std::endl;
return false;
}
// The easiest way: already computed:
if (entry->preview)
return entry->preview;
// Then, try to load the preview from file:
QString previewPath = KGlobal::dirs()->findResource("data", "basket/backgrounds/previews/" + entry->name);
QPixmap *previewPixmap = new QPixmap(previewPath);
// Success:
if (!previewPixmap->isNull()) {
/// std::cout << "BackgroundManager: Loaded image preview for " << entry->location << " from file " << previewPath << std::endl;
entry->preview = previewPixmap;
return entry->preview;
}
// We failed? Then construct it:
// Note: if a preview is requested, it's because the user is currently choosing an image.
// Since we need that image to create the preview, we keep the image in memory.
// Then, it will already be loaded when user press [OK] in the background image chooser.
// BUT we also delay a garbage because we don't want EVERY images to be loaded if the user use only a few of them, of course:
// Already used? Good: we don't have to load it...
if (!entry->pixmap) {
// Note: it's a code duplication from BackgroundManager::subscribe(const QString &image),
// Because, as we are loading the pixmap we ALSO need to know if it's a tile or not, in case that image will soon be used (and not destroyed by the garbager):
entry->pixmap = new QPixmap(entry->location);
// Try to figure out if it's a tiled background image or not (default to NO):
KSimpleConfig config(entry->location + ".config", /*readOnly=*/true);
config.setGroup("BasKet Background Image Configuration");
entry->tiled = config.readBoolEntry("tiled", false);
}
// The image cannot be loaded, we failed:
if (entry->pixmap->isNull())
return 0;
// Good that we are still alive: entry->pixmap contains the pixmap to rescale down for the preview:
// Compute new size:
int width = entry->pixmap->width();
int height = entry->pixmap->height();
if (width > MAX_WIDTH) {
height = height * MAX_WIDTH / width;
width = MAX_WIDTH;
}
if (height > MAX_HEIGHT) {
width = width * MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
// And create the resulting pixmap:
QPixmap *result = new QPixmap(width, height);
result->fill(PREVIEW_BG);
QImage imageToScale = entry->pixmap->convertToImage();
QPixmap pmScaled;
pmScaled.convertFromImage(imageToScale.smoothScale(width, height));
QPainter painter(result);
painter.drawPixmap(0, 0, pmScaled);
painter.end();
// Saving it to file for later:
QString folder = KGlobal::dirs()->saveLocation("data", "basket/backgrounds/previews/");
result->save(folder + entry->name, "PNG");
// Ouf! That's done:
entry->preview = result;
requestDelayedGarbage();
return entry->preview;
}
QString BackgroundManager::pathForImageName(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (entry == 0)
return "";
else
return entry->location;
}
QString BackgroundManager::previewPathForImageName(const QString &image)
{
BackgroundEntry *entry = backgroundEntryFor(image);
if (entry == 0)
return "";
else {
QString previewPath = KGlobal::dirs()->findResource("data", "basket/backgrounds/previews/" + entry->name);
QDir dir;
if (!dir.exists(previewPath))
return "";
else
return previewPath;
}
}
void BackgroundManager::requestDelayedGarbage()
{
static const int DELAY = 60/*seconds*/;
if (!m_garbageTimer.isActive())
m_garbageTimer.start(DELAY * 1000/*ms*/, /*singleShot=*/true);
}
void BackgroundManager::doGarbage()
{
/// std::cout << "BackgroundManager: Doing garbage..." << std::endl;
/// std::cout << "BackgroundManager: Images:" << std::endl;
for (BackgroundsList::Iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it) {
BackgroundEntry *entry = *it;
/// std::cout << "* " << entry->name << ": used " << entry->customersCount << " times";
if (entry->customersCount <= 0 && entry->pixmap) {
/// std::cout << " [Deleted cached pixmap]";
delete entry->pixmap;
entry->pixmap = 0;
}
/// std::cout << std::endl;
}
/// std::cout << "BackgroundManager: Opaque Cached Images:" << std::endl;
for (OpaqueBackgroundsList::Iterator it = m_opaqueBackgroundsList.begin(); it != m_opaqueBackgroundsList.end(); ) {
OpaqueBackgroundEntry *entry = *it;
/// std::cout << "* " << entry->name << "," << entry->color.name() << ": used " << entry->customersCount << " times";
if (entry->customersCount <= 0) {
/// std::cout << " [Deleted entry]";
delete entry->pixmap;
entry->pixmap = 0;
it = m_opaqueBackgroundsList.remove(it);
} else
++it;
/// std::cout << std::endl;
}
}
#include "backgroundmanager.moc"

@ -0,0 +1,132 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BACKGROUNDMANAGER_H
#define BACKGROUNDMANAGER_H
#include <qobject.h>
#include <qvaluelist.h>
#include <qstring.h>
#include <qpixmap.h>
#include <qcolor.h>
#include <qtimer.h>
/** A node in the list of background images of BackgroundManager.
* It can only be used by BackgroundManager because it is an internal structure of this manager.
* @author S<EFBFBD>astien Laot
*/
class BackgroundEntry
{
friend class BackgroundManager;
protected:
BackgroundEntry(const QString &location);
~BackgroundEntry();
QString name;
QString location;
bool tiled; /// << Only valid after some object subscribed to this image! Because it's only read at this time.
QPixmap *pixmap; /// << Only valid (non-null) after some object subscribed to this image! Because it's only read at this time.
QPixmap *preview; /// << Only valid (non-null) after some object requested the preview.
int customersCount;
};
/** A node in the list of opaque background images (with a background color applyed to an image) of BackgroundManager.
* It can only be used by BackgroundManager because it is an internal structure of this manager.
* @author S<EFBFBD>astien Laot
*/
class OpaqueBackgroundEntry
{
friend class BackgroundManager;
protected:
OpaqueBackgroundEntry(const QString &name, const QColor &color);
~OpaqueBackgroundEntry();
QString name;
QColor color;
QPixmap *pixmap;
int customersCount;
};
/** Manage the list of background images.
* BASIC FUNCTIONNING OF A BACKGROUND CHOOSER:
* It get all image names with imageNames() to put them in eg. a QComboBox and then,
* when it's time to get the preview of an image it call preview() with the image name to get it.
* Preview are only computed on demand and then cached to fast the next demands (only the pointer will have to be returned).
* Previews are scalled to fit in a rectangle of 100 by 75 pixels, and with a white background color.
* They are also saved to files, so that the scalling/opaquification has not to be done later (they will be directly loaded from file).
* Previews are saved in Global::backgroundsFolder()+"previews/", so that emptying the folder is sufficient to remove them.
* BASIC FUNCTIONNING OF AN IMAGE REQUESTER:
* When eg. a basket is assigned an image name, it register it with subscribe().
* The full pixmap is then loaded from file and cached (if it was not already loaded) and the "tiled" property is read from the image configuration file.
* If this object want to have the pixmap applyed on a background color (for no transparency => really faster drawing),
* it should register for the couple (imageName,color) with suscribe(): the pixmap will be created in the cache.
* Then, the object can get the subscribed images with pixmap() or opaquePixmap() and know if it's tiled with tiled().
* When the user removed the object background image (or when the object/basket/... is removed), the object should call unsubscribe() for
* EVERY subscribed image and image couples. Usage count is decreased for those images and a garbage collector will remove the cached images
* if nothing is subscribed to them (to free memory).
* @author S<EFBFBD>astien Laot
*/
class BackgroundManager : private QObject
{
Q_OBJECT
private:
/// LIST OF IMAGES:
typedef QValueList<BackgroundEntry*> BackgroundsList;
typedef QValueList<OpaqueBackgroundEntry*> OpaqueBackgroundsList;
public:
/// CONTRUCTOR AND DESTRUCTOR:
BackgroundManager();
~BackgroundManager();
/// SUBSCRIPTION TO IMAGES:
bool subscribe(const QString &image); /// << @Return true if the loading is a success. In the counter-case, calling methods below is unsafe with this @p image name.
bool subscribe(const QString &image, const QColor &color); /// << Idem.
void unsubscribe(const QString &image);
void unsubscribe(const QString &image, const QColor &color);
/// GETTING THE IMAGES AND PROPERTIES:
QPixmap* pixmap(const QString &image);
QPixmap* opaquePixmap(const QString &image, const QColor &color);
bool tiled(const QString &image);
/// LIST OF IMAGES AND PREVIEWS:
bool exists(const QString &image);
QStringList imageNames();
QPixmap* preview(const QString &image);
/// USED FOR EXPORTATION:
QString pathForImageName(const QString &image); /// << It is STRONGLY advised to not use those two methods unless it's to copy (export) the images or something like that...
QString previewPathForImageName(const QString &image);
/// USED FOR IMPORTATION:
void addImage(const QString &fullPath);
private:
BackgroundEntry* backgroundEntryFor(const QString &image);
OpaqueBackgroundEntry* opaqueBackgroundEntryFor(const QString &image, const QColor &color);
private:
BackgroundsList m_backgroundsList;
OpaqueBackgroundsList m_opaqueBackgroundsList;
QTimer m_garbageTimer;
private slots:
void requestDelayedGarbage();
void doGarbage();
};
#endif // BACKGROUNDMANAGER_H

@ -0,0 +1,414 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "backup.h"
#include "global.h"
#include "variouswidgets.h"
#include "settings.h"
#include "tools.h"
#include "formatimporter.h" // To move a folder
#include <qhbox.h>
#include <qvbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <klocale.h>
#include <qdir.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <qgroupbox.h>
#include <kdirselectdialog.h>
#include <krun.h>
#include <kconfig.h>
#include <ktar.h>
#include <kfiledialog.h>
#include <kprogress.h>
#include <kmessagebox.h>
#include <cstdlib>
#include <unistd.h> // usleep()
/**
* Backups are wrapped in a .tar.gz, inside that folder name.
* An archive is not a backup or is corrupted if data are not in that folder!
*/
const QString backupMagicFolder = "BasKet-Note-Pads_Backup";
/** class BackupDialog: */
BackupDialog::BackupDialog(QWidget *parent, const char *name)
: KDialogBase(parent, name, /*modal=*/true, i18n("Backup & Restore"),
KDialogBase::Close, KDialogBase::Close, /*separator=*/false)
{
QVBox *page = makeVBoxMainWidget();
// page->setSpacing(spacingHint());
QString savesFolder = Global::savesFolder();
savesFolder = savesFolder.left(savesFolder.length() - 1); // savesFolder ends with "/"
QGroupBox *folderGroup = new QGroupBox(1, Qt::Horizontal, i18n("Save Folder"), page);
new QLabel("<qt><nobr>" + i18n("Your baskets are currently stored in that folder:<br><b>%1</b>").arg(savesFolder), folderGroup);
QWidget *folderWidget = new QWidget(folderGroup);
QHBoxLayout *folderLayout = new QHBoxLayout(folderWidget, 0, spacingHint());
QPushButton *moveFolder = new QPushButton(i18n("&Move to Another Folder..."), folderWidget);
QPushButton *useFolder = new QPushButton(i18n("&Use Another Existing Folder..."), folderWidget);
HelpLabel *helpLabel = new HelpLabel(i18n("Why to do that?"), i18n(
"<p>You can move the folder where %1 store your baskets to:</p><ul>"
"<li>Store your baskets in a visible place in your home folder, like ~/Notes or ~/Baskets, so you can manually backup them when you want.</li>"
"<li>Store your baskets on a server to share them between two computers.<br>"
"In this case, mount the shared-folder to the local file system and ask %2 to use that mount point.<br>"
"Warning: you should not run %3 at the same time on both computers, or you risk to loss data while the two applications are desynced.</li>"
"</ul><p>Please remember that you should not change the content of that folder manually (eg. adding a file in a basket folder will not add that file to the basket).</p>")
.arg(kapp->aboutData()->programName())
.arg(kapp->aboutData()->programName())
.arg(kapp->aboutData()->programName()),
folderWidget);
folderLayout->addWidget(moveFolder);
folderLayout->addWidget(useFolder);
folderLayout->addWidget(helpLabel);
folderLayout->addStretch();
connect( moveFolder, SIGNAL(clicked()), this, SLOT(moveToAnotherFolder()) );
connect( useFolder, SIGNAL(clicked()), this, SLOT(useAnotherExistingFolder()) );
QGroupBox *backupGroup = new QGroupBox(1, Qt::Horizontal, i18n("Backups"), page);
QWidget *backupWidget = new QWidget(backupGroup);
QHBoxLayout *backupLayout = new QHBoxLayout(backupWidget, 0, spacingHint());
QPushButton *backupButton = new QPushButton(i18n("&Backup..."), backupWidget);
QPushButton *restoreButton = new QPushButton(i18n("&Restore a Backup..."), backupWidget);
m_lastBackup = new QLabel("", backupWidget);
backupLayout->addWidget(backupButton);
backupLayout->addWidget(restoreButton);
backupLayout->addWidget(m_lastBackup);
backupLayout->addStretch();
connect( backupButton, SIGNAL(clicked()), this, SLOT(backup()) );
connect( restoreButton, SIGNAL(clicked()), this, SLOT(restore()) );
populateLastBackup();
(new QWidget(page))->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
BackupDialog::~BackupDialog()
{
}
void BackupDialog::populateLastBackup()
{
QString lastBackupText = i18n("Last backup: never");
if (Settings::lastBackup().isValid())
lastBackupText = i18n("Last backup: %1").arg(Settings::lastBackup().toString(Qt::LocalDate));
m_lastBackup->setText(lastBackupText);
}
void BackupDialog::moveToAnotherFolder()
{
KURL selectedURL = KDirSelectDialog::selectDirectory(
/*startDir=*/Global::savesFolder(), /*localOnly=*/true, /*parent=*/0,
/*caption=*/i18n("Choose a Folder Where to Move Baskets"));
if (!selectedURL.isEmpty()) {
QString folder = selectedURL.path();
QDir dir(folder);
// The folder should not exists, or be empty (because KDirSelectDialog will likely create it anyway):
if (dir.exists()) {
// Get the content of the folder:
QStringList content = dir.entryList();
if (content.count() > 2) { // "." and ".."
int result = KMessageBox::questionYesNo(
0,
"<qt>" + i18n("The folder <b>%1</b> is not empty. Do you want to override it?").arg(folder),
i18n("Override Folder?"),
KGuiItem(i18n("&Override"), "filesave")
);
if (result == KMessageBox::No)
return;
}
Tools::deleteRecursively(folder);
}
FormatImporter copier;
copier.moveFolder(Global::savesFolder(), folder);
Backup::setFolderAndRestart(folder, i18n("Your baskets have been successfuly moved to <b>%1</b>. %2 is going to be restarted to take this change into account."));
}
}
void BackupDialog::useAnotherExistingFolder()
{
KURL selectedURL = KDirSelectDialog::selectDirectory(
/*startDir=*/Global::savesFolder(), /*localOnly=*/true, /*parent=*/0,
/*caption=*/i18n("Choose an Existing Folder to Store Baskets"));
if (!selectedURL.isEmpty()) {
Backup::setFolderAndRestart(selectedURL.path(), i18n("Your basket save folder has been successfuly changed to <b>%1</b>. %2 is going to be restarted to take this change into account."));
}
}
void BackupDialog::backup()
{
QDir dir;
// Compute a default file name & path (eg. "Baskets_2007-01-31.tar.gz"):
KConfig *config = KGlobal::config();
config->setGroup("Backups");
QString folder = config->readEntry("lastFolder", QDir::homeDirPath()) + "/";
QString fileName = i18n("Backup filename (without extension), %1 is the date", "Baskets_%1")
.arg(QDate::currentDate().toString(Qt::ISODate));
QString url = folder + fileName;
// Ask a file name & path to the user:
QString filter = "*.tar.gz|" + i18n("Tar Archives Compressed by Gzip") + "\n*|" + i18n("All Files");
QString destination = url;
for (bool askAgain = true; askAgain; ) {
// Ask:
destination = KFileDialog::getSaveFileName(destination, filter, 0, i18n("Backup Baskets"));
// User canceled?
if (destination.isEmpty())
return;
// File already existing? Ask for overriding:
if (dir.exists(destination)) {
int result = KMessageBox::questionYesNoCancel(
0,
"<qt>" + i18n("The file <b>%1</b> already exists. Do you really want to override it?")
.arg(KURL(destination).fileName()),
i18n("Override File?"),
KGuiItem(i18n("&Override"), "filesave")
);
if (result == KMessageBox::Cancel)
return;
else if (result == KMessageBox::Yes)
askAgain = false;
} else
askAgain = false;
}
KProgressDialog dialog(0, 0, i18n("Backup Baskets"), i18n("Backing up baskets. Please wait..."), /*modal=*/true);
dialog.setAllowCancel(false);
dialog.setAutoClose(true);
dialog.show();
KProgress *progress = dialog.progressBar();
progress->setTotalSteps(0/*Busy/Undefined*/);
progress->setProgress(0);
progress->setPercentageVisible(false);
BackupThread thread(destination, Global::savesFolder());
thread.start();
while (thread.running()) {
progress->advance(1); // Or else, the animation is not played!
kapp->processEvents();
usleep(300); // Not too long because if the backup process is finished, we wait for nothing
}
Settings::setLastBackup(QDate::currentDate());
Settings::saveConfig();
populateLastBackup();
}
void BackupDialog::restore()
{
// Get last backup folder:
KConfig *config = KGlobal::config();
config->setGroup("Backups");
QString folder = config->readEntry("lastFolder", QDir::homeDirPath()) + "/";
// Ask a file name to the user:
QString filter = "*.tar.gz|" + i18n("Tar Archives Compressed by Gzip") + "\n*|" + i18n("All Files");
QString path = KFileDialog::getOpenFileName(folder, filter, this, i18n("Open Basket Archive"));
if (path.isEmpty()) // User has canceled
return;
// Before replacing the basket data folder with the backup content, we safely backup the current baskets to the home folder.
// So if the backup is corrupted or something goes wrong while restoring (power cut...) the user will be able to restore the old working data:
QString safetyPath = Backup::newSafetyFolder();
FormatImporter copier;
copier.moveFolder(Global::savesFolder(), safetyPath);
// Add the README file for user to cancel a bad restoration:
QString readmePath = safetyPath + i18n("README.txt");
QFile file(readmePath);
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream << i18n("This is a safety copy of your baskets like they were before you started to restore the backup %1.").arg(KURL(path).fileName()) + "\n\n"
<< i18n("If the restoration was a success and you restored what you wanted to restore, you can remove this folder.") + "\n\n"
<< i18n("If something went wrong during the restoration process, you can re-use this folder to store your baskets and nothing will be lost.") + "\n\n"
<< i18n("Choose \"Basket\" -> \"Backup & Restore...\" -> \"Use Another Existing Folder...\" and select that folder.") + "\n";
file.close();
}
QString message =
"<p><nobr>" + i18n("Restoring <b>%1</b>. Please wait...").arg(KURL(path).fileName()) + "</nobr></p><p>" +
i18n("If something goes wrong during the restoration process, read the file <b>%1</b>.").arg(readmePath);
KProgressDialog *dialog = new KProgressDialog(0, 0, i18n("Restore Baskets"), message, /*modal=*/true);
dialog->setAllowCancel(false);
dialog->setAutoClose(true);
dialog->show();
KProgress *progress = dialog->progressBar();
progress->setTotalSteps(0/*Busy/Undefined*/);
progress->setProgress(0);
progress->setPercentageVisible(false);
// Uncompress:
RestoreThread thread(path, Global::savesFolder());
thread.start();
while (thread.running()) {
progress->advance(1); // Or else, the animation is not played!
kapp->processEvents();
usleep(300); // Not too long because if the restore process is finished, we wait for nothing
}
dialog->hide(); // The restore is finished, do not continue to show it while telling the user the application is going to be restarted
delete dialog; // If we only hidden it, it reappeared just after having restored a small backup... Very strange.
dialog = 0; // This was annoying since it is modal and the "BasKet Note Pads is going to be restarted" message was not reachable.
//kapp->processEvents();
// Check for errors:
if (!thread.success()) {
// Restore the old baskets:
QDir dir;
dir.remove(readmePath);
copier.moveFolder(safetyPath, Global::savesFolder());
// Tell the user:
KMessageBox::error(0, i18n("This archive is either not a backup of baskets or is corrupted. It cannot be imported. Your old baskets have been preserved instead."), i18n("Restore Error"));
return;
}
// Note: The safety backup is not removed now because the code can has been wrong, somehow, or the user perhapse restored an older backup by error...
// The restore process will not be called very often (it is possible it will only be called once or twice arround the world during the next years).
// So it is rare enough to force the user to remove the safety folder, but keep him in control and let him safely recover from restoration errors.
Backup::setFolderAndRestart(Global::savesFolder()/*No change*/, i18n("Your backup has been successfuly restored to <b>%1</b>. %2 is going to be restarted to take this change into account."));
}
/** class Backup: */
QString Backup::binaryPath = "";
#include <iostream>
void Backup::figureOutBinaryPath(const char *argv0, QApplication &app)
{
/*
The application can be launched by two ways:
- Globaly (app.applicationFilePath() is good)
- In KDevelop or with an absolute path (app.applicationFilePath() is wrong)
This function is called at the very start of main() so that the current directory has not been changed yet.
Command line (argv[0]) QDir(argv[0]).canonicalPath() app.applicationFilePath()
====================== ============================================= =========================
"basket" "" "/opt/kde3/bin/basket"
"./src/.libs/basket" "/home/seb/prog/basket/debug/src/.lib/basket" "/opt/kde3/bin/basket"
*/
binaryPath = QDir(argv0).canonicalPath();
if (binaryPath.isEmpty())
binaryPath = app.applicationFilePath();
}
void Backup::setFolderAndRestart(const QString &folder, const QString &message)
{
// Set the folder:
Settings::setDataFolder(folder);
Settings::saveConfig();
// Rassure the user that the application main window disapearition is not a crash, but a normal restart.
// This is important for users to trust the application in such a critical phase and understands what's happening:
KMessageBox::information(
0,
"<qt>" + message.arg(
(folder.endsWith("/") ? folder.left(folder.length() - 1) : folder),
kapp->aboutData()->programName()),
i18n("Restart")
);
// Restart the application:
KRun::runCommand(binaryPath, kapp->aboutData()->programName(), kapp->iconName());
exit(0);
}
QString Backup::newSafetyFolder()
{
QDir dir;
QString fullPath;
fullPath = QDir::homeDirPath() + "/" + i18n("Safety folder name before restoring a basket data archive", "Baskets Before Restoration") + "/";
if (!dir.exists(fullPath))
return fullPath;
for (int i = 2; ; ++i) {
fullPath = QDir::homeDirPath() + "/" + i18n("Safety folder name before restoring a basket data archive", "Baskets Before Restoration (%1)").arg(i) + "/";
if (!dir.exists(fullPath))
return fullPath;
}
return "";
}
/** class BackupThread: */
BackupThread::BackupThread(const QString &tarFile, const QString &folderToBackup)
: m_tarFile(tarFile), m_folderToBackup(folderToBackup)
{
}
void BackupThread::run()
{
KTar tar(m_tarFile, "application/x-gzip");
tar.open(IO_WriteOnly);
tar.addLocalDirectory(m_folderToBackup, backupMagicFolder);
// KArchive does not add hidden files. Basket description files (".basket") are hidden, we add them manually:
QDir dir(m_folderToBackup + "baskets/");
QStringList baskets = dir.entryList(QDir::Dirs);
for (QStringList::Iterator it = baskets.begin(); it != baskets.end(); ++it) {
tar.addLocalFile(
m_folderToBackup + "baskets/" + *it + "/.basket",
backupMagicFolder + "/baskets/" + *it + "/.basket"
);
}
// We finished:
tar.close();
}
/** class RestoreThread: */
RestoreThread::RestoreThread(const QString &tarFile, const QString &destFolder)
: m_tarFile(tarFile), m_destFolder(destFolder)
{
}
void RestoreThread::run()
{
m_success = false;
KTar tar(m_tarFile, "application/x-gzip");
tar.open(IO_ReadOnly);
if (tar.isOpened()) {
const KArchiveDirectory *directory = tar.directory();
if (directory->entries().contains(backupMagicFolder)) {
const KArchiveEntry *entry = directory->entry(backupMagicFolder);
if (entry->isDirectory()) {
((const KArchiveDirectory*) entry)->copyTo(m_destFolder);
m_success = true;
}
}
tar.close();
}
}
#include "backup.moc"

@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BACKUP_H
#define BACKUP_H
#include <kdialogbase.h>
#include <qapplication.h>
#include <qthread.h>
/**
* @author Sébastien Laoût
*/
class BackupDialog : public KDialogBase
{
Q_OBJECT
public:
BackupDialog(QWidget *parent = 0, const char *name = 0);
~BackupDialog();
private slots:
void moveToAnotherFolder();
void useAnotherExistingFolder();
void backup();
void restore();
void populateLastBackup();
private:
QLabel *m_lastBackup;
};
/**
* @author Sébastien Laoût <slaout@linux62.org>
*/
class Backup
{
public:
static void figureOutBinaryPath(const char *argv0, QApplication &app);
static void setFolderAndRestart(const QString &folder, const QString &message);
static QString newSafetyFolder();
private:
static QString binaryPath;
};
class BackupThread : public QThread
{
public:
BackupThread(const QString &tarFile, const QString &folderToBackup);
protected:
virtual void run();
private:
QString m_tarFile;
QString m_folderToBackup;
};
class RestoreThread : public QThread
{
public:
RestoreThread(const QString &tarFile, const QString &destFolder);
inline bool success() { return m_success; }
protected:
virtual void run();
private:
QString m_tarFile;
QString m_destFolder;
bool m_success;
};
#endif // BACKUP_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
[Desktop Entry]
Encoding=UTF-8
Type=Application
Exec=basket %f
MimeType=application/x-basket-archive;application/x-basket-template
Icon=basket
Name=BasKet Note Pads
Name[de]=BasKet Notizblätter
Name[es]=Blocs de notas BasKet
Name[fr]=Blocs notes BasKet
Name[it]=Blocco appunti BasKet
Name[ja]=BasKet メモパッド
Name[nb]=Kurvnotat
Name[nn]=Korgnotat
Name[pt]=Bloco de Notas BasKet
Name[ru]=Альбом заметок BasKet
Name[xx]=xxBasKet Note Padsxx
Name[tr]=BasKet
Comment=Taking care of your ideas.
Comment[de]=Bewahren Sie Ihre Ideen.
Comment[es]=Cuidando de sus ideas.
Comment[fr]=Prendre soin de vos idées.
Comment[it]=Ci prendiamo cura delle tue idee
Comment[nb]=Ta vare på tankene dine.
Comment[nn]=Ta vare på tankane dine.
Comment[ja]=あなたのアイデアのお世話をします。
Comment[pt]=Cuidando das suas ideias.
Comment[ru]=Заботимся о ваших идеях.
Comment[xx]=xxTaking care of your ideas.xx
Comment[tr]=Not Tutma Aracı
Categories=KDE;Application;Utility;TextEditor;

@ -0,0 +1,835 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKET_H
#define BASKET_H
#include <qscrollview.h>
#include <qtooltip.h>
#include <qvaluelist.h>
#include <qtimer.h>
#include <qimage.h>
#include <qdatetime.h>
#include <qclipboard.h>
#include <kshortcut.h>
#include <kdirwatch.h>
#include <kaction.h>
#include <kio/job.h>
#include <kdialogbase.h>
#include "filter.h"
#include "note.h" // For Note::Zone
#include "config.h"
class QVBoxLayout;
class QDomDocument;
class QDomElement;
class Basket;
class Note;
class NoteEditor;
class Tag;
#ifdef HAVE_LIBGPGME
class KGpgMe;
#endif
/** Provide a dialog to avert the user the disk is full.
* This dialog is modal and is shown until the user has made space on the disk.
* @author S<EFBFBD>astien Laot
*/
class DiskErrorDialog : public KDialogBase
{
Q_OBJECT
public:
DiskErrorDialog(const QString &titleMessage, const QString &message, QWidget *parent = 0);
~DiskErrorDialog();
protected:
void closeEvent(QCloseEvent *event);
void keyPressEvent(QKeyEvent*);
};
/** A list of flags to set how notes are inserted/plugged in the basket
* Declare a varible with the type PlugOptions::Flags and assign a value like PlugOptions::DoSelection...
* @author S<EFBFBD>astien Laot
*/
namespace PlugOptions
{
enum Flags {
SelectOnlyNewNotes = 0x01, /// << Unselect every notes in the basket and select the newly inserted ones
DoTagsInheriting = 0x02 /// << The new notes inherit the tags of the sibbling note
};
// TODO: FocusLastInsertedNote (last visible!), EnsureVisibleAddedNotes, PopupFeebackBaloon (if not called by hand), AnimateNewPosition, FeedbackUnmatched
// TODO: moveNoteInTree(bool animate);
}
/** This represent a hierarchy of the selected classes.
* If this is null, then there is no selected note.
*/
class NoteSelection
{
public:
NoteSelection() : note(0), parent(0), firstChild(0), next(0), fullPath() {}
NoteSelection(Note *n) : note(n), parent(0), firstChild(0), next(0), fullPath() {}
Note *note;
NoteSelection *parent;
NoteSelection *firstChild;
NoteSelection *next;
QString fullPath; // Needeed for 'Cut' code to store temporary path of the cutted note.
NoteSelection* firstStacked();
NoteSelection* nextStacked();
void append(NoteSelection *node);
int count();
QValueList<Note*> parentGroups();
};
/** This store all needed information when exporting to HTML
*/
class HtmlExportData
{
public:
QString iconsFolderPath;
QString iconsFolderName;
QString imagesFolderPath;
QString imagesFolderName;
QString dataFolderPath;
QString dataFolderName;
bool formatForImpression;
bool embedLinkedFiles;
bool embedLinkedFolders;
};
/** This class handle Basket and add a FilterWidget on top of it.
* @author S<EFBFBD>astien Laot
*/
class DecoratedBasket : public QWidget
{
Q_OBJECT
public:
DecoratedBasket(QWidget *parent, const QString &folderName, const char *name = 0, WFlags fl = 0);
~DecoratedBasket();
void setFilterBarPosition(bool onTop);
void resetFilter();
void setFilterBarShown(bool show, bool switchFocus = true);
bool isFilterBarShown() { return m_filter->isShown(); }
const FilterData& filterData() { return m_filter->filterData(); }
FilterBar* filterBar() { return m_filter; }
Basket* basket() { return m_basket; }
private:
QVBoxLayout *m_layout;
FilterBar *m_filter;
Basket *m_basket;
};
class TransparentWidget : public QWidget
{
Q_OBJECT
public:
TransparentWidget(Basket *basket);
void setPosition(int x, int y);
//void reparent(QWidget *parent, WFlags f, const QPoint &p, bool showIt = FALSE);
protected:
void paintEvent(QPaintEvent*);
void mouseMoveEvent(QMouseEvent *event);
bool eventFilter(QObject *object, QEvent *event);
private:
Basket *m_basket;
int m_x;
int m_y;
};
/**
* @author S<EFBFBD>astien Laot
*/
class Basket : public QScrollView, public QToolTip
{
/// CONSTRUCTOR AND DESTRUCTOR:
Q_OBJECT
public:
enum EncryptionTypes {
NoEncryption = 0,
PasswordEncryption = 1,
PrivateKeyEncryption = 2
};
public:
Basket(QWidget *parent, const QString &folderName);
~Basket();
/// USER INTERACTION:
private:
bool m_noActionOnMouseRelease;
bool m_ignoreCloseEditorOnNextMouseRelease;
QPoint m_pressPos;
bool m_canDrag;
public:
void viewportResizeEvent(QResizeEvent *);
void drawContents(QPainter *painter, int clipX, int clipY, int clipWidth, int clipHeight);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
void contentsMouseMoveEvent(QMouseEvent *event);
void contentsMousePressEvent(QMouseEvent *event);
void contentsMouseReleaseEvent(QMouseEvent *event);
void contentsMouseDoubleClickEvent(QMouseEvent *event);
void contentsContextMenuEvent(QContextMenuEvent *event);
void updateNote(Note *note);
void clickedToInsert(QMouseEvent *event, Note *clicked = 0, int zone = 0);
private slots:
void setFocusIfNotInPopupMenu();
/// LAYOUT:
private:
Note *m_firstNote;
int m_columnsCount;
bool m_mindMap;
Note *m_resizingNote;
int m_pickedResizer;
Note *m_movingNote;
QPoint m_pickedHandle;
public:
int tmpWidth;
int tmpHeight;
public:
void unsetNotesWidth();
void relayoutNotes(bool animate);
Note* noteAt(int x, int y);
inline Note* firstNote() { return m_firstNote; }
inline int columnsCount() { return m_columnsCount; }
inline bool isColumnsLayout() { return m_columnsCount > 0; }
inline bool isFreeLayout() { return m_columnsCount <= 0; }
inline bool isMindMap() { return isFreeLayout() && m_mindMap; }
Note* resizingNote() { return m_resizingNote; }
void deleteNotes();
Note* lastNote();
void setDisposition(int disposition, int columnCount);
void equalizeColumnSizes();
/// NOTES INSERTION AND REMOVAL:
public:
/// The following methods assume that the note(s) to insert already all have 'this' as the parent basket:
void prependNoteIn( Note *note, Note *in); /// << Add @p note (and the next linked notes) as the first note(s) of the group @p in.
void appendNoteIn( Note *note, Note *in); /// << Add @p note (and the next linked notes) as the last note(s) of the group @p in.
void appendNoteAfter( Note *note, Note *after); /// << Add @p note (and the next linked notes) just after (just below) the note @p after.
void appendNoteBefore(Note *note, Note *before); /// << Add @p note (and the next linked notes) just before (just above) the note @p before.
void groupNoteAfter( Note *note, Note *with); /// << Add a group at @p with place, move @p with in it, and add @p note (and the next linked notes) just after the group.
void groupNoteBefore( Note *note, Note *with); /// << Add a group at @p with place, move @p with in it, and add @p note (and the next linked notes) just before the group.
void unplugNote( Note *note); /// << Unplug @p note (and its child notes) from the basket (and also decrease counts...).
/// << After that, you should delete the notes yourself. Do not call prepend/append/group... functions two times: unplug and ok
void ungroupNote( Note *group); /// << Unplug @p group but put child notes at its place.
/// And this one do almost all the above methods depending on the context:
void insertNote(Note *note, Note *clicked, int zone, const QPoint &pos = QPoint(), bool animateNewPosition = false);
void insertCreatedNote(Note *note);
/// And working with selections:
void unplugSelection(NoteSelection *selection);
void insertSelection(NoteSelection *selection, Note *after);
void selectSelection(NoteSelection *selection);
private:
void preparePlug(Note *note);
private:
Note *m_clickedToInsert;
int m_zoneToInsert;
QPoint m_posToInsert;
Note *m_savedClickedToInsert;
int m_savedZoneToInsert;
QPoint m_savedPosToInsert;
bool m_isInsertPopupMenu;
public:
void saveInsertionData();
void restoreInsertionData();
void resetInsertionData();
public slots:
void insertEmptyNote(int type);
void insertWizard(int type);
void insertColor(const QColor &color);
void insertImage(const QPixmap &image);
void pasteNote(QClipboard::Mode mode = QClipboard::Clipboard);
void delayedCancelInsertPopupMenu();
void setInsertPopupMenu() { m_isInsertPopupMenu = true; }
void cancelInsertPopupMenu() { m_isInsertPopupMenu = false; }
private slots:
void hideInsertPopupMenu();
void timeoutHideInsertPopupMenu();
/// TOOL TIPS:
protected:
void maybeTip(const QPoint &pos);
/// ANIMATIONS:
private:
QValueList<Note*> m_animatedNotes;
QTimer m_animationTimer;
int m_deltaY;
QTime m_lastFrameTime;
static const int FRAME_DELAY;
private slots:
void animateObjects();
public slots:
void animateLoad();
public:
void addAnimatedNote(Note *note);
/// LOAD AND SAVE:
private:
bool m_loaded;
bool m_loadingLaunched;
bool m_locked;
bool m_shouldConvertPlainTextNotes;
QFrame* m_decryptBox;
QPushButton* m_button;
int m_encryptionType;
QString m_encryptionKey;
#ifdef HAVE_LIBGPGME
KGpgMe* m_gpg;
#endif
QTimer m_inactivityAutoLockTimer;
void enableActions();
private slots:
void loadNotes(const QDomElement &notes, Note *parent);
void saveNotes(QDomDocument &document, QDomElement &element, Note *parent);
void unlock();
protected slots:
void inactivityAutoLockTimeout();
public slots:
void load();
void loadProperties(const QDomElement &properties);
void saveProperties(QDomDocument &document, QDomElement &properties);
bool save();
public:
bool isEncrypted();
bool isFileEncrypted();
bool isLocked() { return m_locked; };
void lock();
bool isLoaded() { return m_loaded; };
bool loadingLaunched() { return m_loadingLaunched; };
bool loadFromFile(const QString &fullPath, QString* string, bool isLocalEncoding = false);
bool loadFromFile(const QString &fullPath, QByteArray* array);
bool saveToFile(const QString& fullPath, const QByteArray& array);
bool saveToFile(const QString& fullPath, const QByteArray& array, Q_ULONG length);
bool saveToFile(const QString& fullPath, const QString& string, bool isLocalEncoding = false);
static bool safelySaveToFile(const QString& fullPath, const QByteArray& array);
static bool safelySaveToFile(const QString& fullPath, const QByteArray& array, Q_ULONG length);
static bool safelySaveToFile(const QString& fullPath, const QString& string, bool isLocalEncoding = false);
bool setProtection(int type, QString key);
int encryptionType() { return m_encryptionType; };
QString encryptionKey(){ return m_encryptionKey; };
bool saveAgain();
/// BACKGROUND:
private:
QColor m_backgroundColorSetting;
QString m_backgroundImageName;
QPixmap *m_backgroundPixmap;
QPixmap *m_opaqueBackgroundPixmap;
QPixmap *m_selectedBackgroundPixmap;
bool m_backgroundTiled;
QColor m_textColorSetting;
public:
inline bool hasBackgroundImage() { return m_backgroundPixmap != 0; }
inline const QPixmap* backgroundPixmap() { return m_backgroundPixmap; }
inline bool isTiledBackground() { return m_backgroundTiled; }
inline QString backgroundImageName() { return m_backgroundImageName; }
inline QColor backgroundColorSetting() { return m_backgroundColorSetting; }
inline QColor textColorSetting() { return m_textColorSetting; }
QColor backgroundColor();
QColor textColor();
void setAppearance(const QString &icon, const QString &name, const QString &backgroundImage, const QColor &backgroundColor, const QColor &textColor);
void blendBackground(QPainter &painter, const QRect &rect, int xPainter = -1, int yPainter = -1, bool opaque = false, QPixmap *bg = 0);
void unbufferizeAll();
void subscribeBackgroundImages();
void unsubscribeBackgroundImages();
/// KEYBOARD SHORTCUT:
public: // Temporar: for deletion purpose
KAction *m_action;
private:
int m_shortcutAction;
private slots:
void activatedShortcut();
public:
KShortcut shortcut() { return m_action->shortcut(); }
int shortcutAction() { return m_shortcutAction; }
void setShortcut(KShortcut shortcut, int action);
/// USER INTERACTION:
private:
Note *m_hoveredNote;
int m_hoveredZone;
bool m_lockedHovering;
bool m_underMouse;
QRect m_inserterRect;
bool m_inserterShown;
bool m_inserterSplit;
bool m_inserterTop;
bool m_inserterGroup;
void placeInserter(Note *note, int zone);
void removeInserter();
public:
// bool inserterShown() { return m_inserterShown; }
bool inserterSplit() { return m_inserterSplit; }
bool inserterGroup() { return m_inserterGroup; }
public slots:
void doHoverEffects(Note *note, Note::Zone zone, const QPoint &pos = QPoint(0, 0)); /// << @p pos is optionnal and only used to show the link target in the statusbar
void doHoverEffects(const QPoint &pos);
void doHoverEffects(); // The same, but using the current cursor position
void mouseEnteredEditorWidget();
public:
void popupTagsMenu(Note *note);
void popupEmblemMenu(Note *note, int emblemNumber);
void addTagToSelectedNotes(Tag *tag);
void removeTagFromSelectedNotes(Tag *tag);
void removeAllTagsFromSelectedNotes();
void addStateToSelectedNotes(State *state);
void changeStateOfSelectedNotes(State *state);
bool selectedNotesHaveTags();
const QRect& inserterRect() { return m_inserterRect; }
bool inserterShown() { return m_inserterShown; }
void drawInserter(QPainter &painter, int xPainter, int yPainter);
DecoratedBasket* decoration();
State *stateForTagFromSelectedNotes(Tag *tag);
public slots:
void activatedTagShortcut(Tag *tag);
void recomputeAllStyles();
void removedStates(const QValueList<State*> &deletedStates);
private slots:
void toggledTagInMenu(int id);
void toggledStateInMenu(int id);
void unlockHovering();
void disableNextClick();
void contentsMoved();
public:
Note *m_tagPopupNote;
private:
Tag *m_tagPopup;
QTime m_lastDisableClick;
/// SELECTION:
private:
bool m_isSelecting;
bool m_selectionStarted;
bool m_selectionInvert;
QPoint m_selectionBeginPoint;
QPoint m_selectionEndPoint;
QRect m_selectionRect;
QTimer m_autoScrollSelectionTimer;
void stopAutoScrollSelection();
private slots:
void doAutoScrollSelection();
public:
inline bool isSelecting() { return m_isSelecting; }
inline const QRect& selectionRect() { return m_selectionRect; }
void selectNotesIn(const QRect &rect, bool invertSelection, bool unselectOthers = true);
void resetWasInLastSelectionRect();
void selectAll();
void unselectAll();
void invertSelection();
void unselectAllBut(Note *toSelect);
void invertSelectionOf(Note *toSelect);
QColor selectionRectInsideColor();
Note* theSelectedNote();
NoteSelection* selectedNotes();
/// BLANK SPACES DRAWING:
private:
QValueList<QRect> m_blankAreas;
void recomputeBlankRects();
QWidget *m_cornerWidget;
/// COMMUNICATION WITH ITS CONTAINER:
signals:
void postMessage(const QString &message); /// << Post a temporar message in the statusBar.
void setStatusBarText(const QString &message); /// << Set the permanent statusBar text or reset it if message isEmpty().
void resetStatusBarText(); /// << Equivalent to setStatusBarText("").
void propertiesChanged(Basket *basket);
void countsChanged(Basket *basket);
public slots:
void linkLookChanged();
void signalCountsChanged();
private:
QTimer m_timerCountsChanged;
private slots:
void countsChangedTimeOut();
/// NOTES COUNTING:
public:
void addSelectedNote() { ++m_countSelecteds; signalCountsChanged(); }
void removeSelectedNote() { --m_countSelecteds; signalCountsChanged(); }
void resetSelectedNote() { m_countSelecteds = 0; signalCountsChanged(); } // FIXME: Useful ???
int count() { return m_count; }
int countFounds() { return m_countFounds; }
int countSelecteds() { return m_countSelecteds; }
private:
int m_count;
int m_countFounds;
int m_countSelecteds;
/// PROPERTIES:
public:
QString basketName() { return m_basketName; }
QString icon() { return m_icon; }
QString folderName() { return m_folderName; }
QString fullPath();
QString fullPathForFileName(const QString &fileName); // Full path of an [existing or not] note in this basket
static QString fullPathForFolderName(const QString &folderName);
private:
QString m_basketName;
QString m_icon;
QString m_folderName;
/// ACTIONS ON SELECTED NOTES FROM THE INTERFACE:
public slots:
void noteEdit(Note *note = 0L, bool justAdded = false, const QPoint &clickedPoint = QPoint());
void showEditedNoteWhileFiltering();
void noteDelete();
void noteDeleteWithoutConfirmation(bool deleteFilesToo = true);
void noteCopy();
void noteCut();
void noteOpen(Note *note = 0L);
void noteOpenWith(Note *note = 0L);
void noteSaveAs();
void noteGroup();
void noteUngroup();
void noteMoveOnTop();
void noteMoveOnBottom();
void noteMoveNoteUp();
void noteMoveNoteDown();
void moveSelectionTo(Note *here, bool below);
public:
enum CopyMode { CopyToClipboard, CopyToSelection, CutToClipboard };
void doCopy(CopyMode copyMode);
bool selectionIsOneGroup();
Note* selectedGroup();
Note* firstSelected();
Note* lastSelected();
/// NOTES EDITION:
private:
NoteEditor *m_editor;
//QWidget *m_rightEditorBorder;
TransparentWidget *m_leftEditorBorder;
TransparentWidget *m_rightEditorBorder;
bool m_redirectEditActions;
int m_editorWidth;
int m_editorHeight;
QTimer m_inactivityAutoSaveTimer;
bool m_doNotCloseEditor;
int m_editParagraph;
int m_editIndex;
public:
bool isDuringEdit() { return m_editor; }
bool redirectEditActions() { return m_redirectEditActions; }
bool hasTextInEditor();
bool hasSelectedTextInEditor();
bool selectedAllTextInEditor();
Note* editedNote();
protected slots:
void selectionChangedInEditor();
void contentChangedInEditor();
void inactivityAutoSaveTimeout();
public slots:
void editorCursorPositionChanged();
private:
int m_editorX;
int m_editorY;
public slots:
void placeEditor(bool andEnsureVisible = false);
void placeEditorAndEnsureVisible();
bool closeEditor();
void closeEditorDelayed();
void updateEditorAppearance();
void editorPropertiesChanged();
void openBasket();
void closeBasket();
/// FILTERING:
public slots:
void newFilter(const FilterData &data, bool andEnsureVisible = true);
void cancelFilter();
void validateFilter();
void filterAgain(bool andEnsureVisible = true);
void filterAgainDelayed();
bool isFiltering();
/// DRAG AND DROP:
private:
bool m_isDuringDrag;
QValueList<Note*> m_draggedNotes;
public:
static void acceptDropEvent(QDropEvent *event, bool preCond = true);
void contentsDropEvent(QDropEvent *event);
void blindDrop(QDropEvent* event);
bool isDuringDrag() { return m_isDuringDrag; }
QValueList<Note*> draggedNotes() { return m_draggedNotes; }
protected:
void contentsDragEnterEvent(QDragEnterEvent*);
void contentsDragMoveEvent(QDragMoveEvent *event);
void contentsDragLeaveEvent(QDragLeaveEvent*);
public slots:
void slotCopyingDone2(KIO::Job *job);
public:
Note* noteForFullPath(const QString &path);
/// EXPORTATION:
public:
QValueList<State*> usedStates();
static QString saveGradientBackground(const QColor &color, const QFont &font, const QString &folder);
public:
void listUsedTags(QValueList<Tag*> &list);
/// MANAGE FOCUS:
private:
Note *m_focusedNote;
public:
void setFocusedNote(Note *note);
void focusANote();
void focusANonSelectedNoteAbove(bool inSameColumn);
void focusANonSelectedNoteBelow(bool inSameColumn);
void focusANonSelectedNoteBelowOrThenAbove();
void focusANonSelectedNoteAboveOrThenBelow();
Note* focusedNote() { return m_focusedNote; }
Note* firstNoteInStack();
Note* lastNoteInStack();
Note* firstNoteShownInStack();
Note* lastNoteShownInStack();
void selectRange(Note *start, Note *end, bool unselectOthers = true); /// FIXME: Not really a focus related method!
void ensureNoteVisible(Note *note);
virtual void keyPressEvent(QKeyEvent *event);
virtual void focusInEvent(QFocusEvent*);
virtual void focusOutEvent(QFocusEvent*);
QRect noteVisibleRect(Note *note); // clipped global (desktop as origin) rectangle
Note* firstNoteInGroup();
Note *noteOnHome();
Note *noteOnEnd();
enum NoteOn { LEFT_SIDE = 1, RIGHT_SIDE, TOP_SIDE, BOTTOM_SIDE };
Note* noteOn(NoteOn side);
/// REIMPLEMENTED:
public:
void deleteFiles();
bool convertTexts();
public:
void wheelEvent(QWheelEvent *event);
public:
Note *m_startOfShiftSelectionNote;
/// THE NEW FILE WATCHER:
private:
KDirWatch *m_watcher;
QTimer m_watcherTimer;
QValueList<QString> m_modifiedFiles;
public:
void addWatchedFile(const QString &fullPath);
void removeWatchedFile(const QString &fullPath);
private slots:
void watchedFileModified(const QString &fullPath);
void watchedFileDeleted(const QString &fullPath);
void updateModifiedNotes();
/// FROM OLD ARCHITECTURE **********************
public slots:
void showFrameInsertTo() {}
void resetInsertTo() {}
void computeInsertPlace(const QPoint &/*cursorPosition*/) { }
public:
friend class SystemTray;
/// SPEED OPTIMIZATION
private:
bool m_finishLoadOnFirstShow;
bool m_relayoutOnNextShow;
public:
void aboutToBeActivated();
};
#if 0
#include <qwidget.h>
#include <qscrollview.h>
#include <qclipboard.h>
#include <qptrlist.h>
#include <qtimer.h>
#include <kio/job.h>
#include <qcolor.h>
#include "filter.h"
class QFrame;
class QVBoxLayout;
class QCheckBox;
class QString;
class QColor;
class QPixmap;
class QAction;
class QStringList;
class QRect;
class QDomElement;
class KDirWatch;
class Basket;
class Note;
class NoteEditorBase;
/** Used to enqueue a file path when the Basket receive a file modification / creation / deletion
* It associate the file name with an event.
* All this queue will be treated later.
* TODO: rename to class WatcherEvent ?
* @author S<EFBFBD>astien Laot
*/
class FileEvent
{
public:
enum Event { Modified = 1, Created, Deleted, Renamed };
FileEvent(Event evt, const QString &path)
: event(evt), filePath(path)
{ }
public: // Because it must be fast and theire is no need to be private
Event event;
QString filePath;
};
/** Basket that contain some Notes.
* @author S<EFBFBD>astien Laot
*/
clas s Bas ket : public QScrollView
{
Q_OBJECT
public:
/** Construtor and destructor */
Bask et(QWidget *parent, const QString &folderName, const char *name = "", WFlags fl = 0);
public:
protected:
virtual void contentsContextMenuEvent(QContextMenuEvent *event);
virtual void contentsMousePressEvent(QMouseEvent *event); // For redirected event !!
virtual void showEvent(QShowEvent *);
/** Drag and drop functions */
virtual void dragEnterEvent(QDragEnterEvent*);
virtual void dragMoveEvent(QDragMoveEvent* event);
virtual void dragLeaveEvent(QDragLeaveEvent*);
public:
virtual void dropEvent(QDropEvent *event);
static void acceptDropEvent(QDropEvent *event, bool preCond = true);
bool canDragNote() { return !isEmpty(); }
void computeInsertPlace(const QPoint &cursorPosition);
Note* noteAtPosition(const QPoint &pos);
Note* duplicatedOf(Note *note);
void checkClipboard();
void processActionAsYouType(QKeyEvent *event);
void exportToHTML();
signals:
void nameChanged(Basket *basket, const QString &name);
void iconChanged(Basket *basket, const QString &icon);
void notesNumberChanged(Basket *basket);
public slots:
void linkLookChanged();
void showNotesToolTipChanged();
/** Notes manipulation */
void insertNote(Note *note);
void delNote(Note *note, bool askForMirroredFile = true);
void changeNotePlace(Note *note);
void pasteNote(QClipboard::Mode mode = QClipboard::Clipboard);
void recolorizeNotes();
void reloadMirroredFolder();
void showMirrorOnlyOnceInfo();
/** Selection of note(s) */
void selectAll();
void unselectAll();
void unselectAllBut(Note *toSelect);
void invertSelection();
void selectRange(Note *start, Note *end);
void clicked(Note *note, bool controlPressed, bool shiftPressed);
void setFocusedNote(Note *note);
void focusANote();
void ensureVisibleNote(Note *note);
QRect noteRect(Note *note); // clipped global (desktop as origin) rectangle
/** Travel the list to find the next shown note, or the previous if step == -1, or the next after 10 if step == 10... */
Note* nextShownNoteFrom(Note *note, int step);
/** Actions on (selected) notes */
void editNote(Note *note, bool editAnnotations = false);
void editNote();
void delNote();
void copyNote();
void cutNote();
void openNote();
void openNoteWith();
void saveNoteAs();
void moveOnTop();
void moveOnBottom();
void moveNoteUp();
void moveNoteDown();
public:
void dontCareOfCreation(const QString &path);
QString copyIcon(const QString &iconName, int size, const QString &destFolder);
QString copyFile(const QString &srcPath, const QString &destFolder, bool createIt = false);
protected slots:
void slotModifiedFile(const QString &path);
void slotCreatedFile(const QString &path);
void slotDeletedFile(const QString &path);
void slotUpdateNotes();
void placeEditor();
void closeEditor(bool save = true);
void clipboardChanged(bool selectionMode = false);
void selectionChanged();
private:
QTimer m_updateTimer;
QPtrList<FileEvent> m_updateQueue;
QStringList m_dontCare;
static const int c_updateTime;
private:
void load(); // Load is performed only once, during contructor
void loadNotes(const QDomElement &notes);
bool importLauncher(const QString &type, const QDomElement &content, const QString &runCommand,
const QString &annotations/*, bool checked*/);
void computeShownNotes();
private:
KDirWatch *m_watcher;
NoteEditorBase *m_editor;
QKeyEvent *m_stackedKeyEvent;
};
#endif // #if 0
#endif // BASKET_H

@ -0,0 +1,16 @@
Begin3
Title: BasKet Note Pads -- Taking care of your ideas.
Version: 1.0.3.1
Entered-date:
Description:
Keywords: KDE Qt Basket Note Pad Item Drop Paste Checklist Stack
Author: Sébastien Laoût <slaout@linux62.org>
Maintained-by: Sébastien Laoût <slaout@linux62.org>
Home-page: http://basket.kde.org/
Alternate-site:
Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
xxxxxx basket-1.0.3.1.tar.gz
xxx basket-1.0.3.1.lsm
Platform: Linux. Needs KDE
Copying-policy: GPL
End

@ -0,0 +1,37 @@
[Desktop Entry]
Encoding=UTF-8
Icon=run
Type=Service
ServiceTypes=KCModule
X-KDE-ModuleType=Library
X-KDE-Library=basket
X-KDE-FactoryName=basket_config_apps
X-KDE-HasReadOnlyMode=false
X-KDE-ParentApp=basket
X-KDE-ParentComponents=basket,kontact_basketplugin
X-KDE-CfgDlgHierarchy=Basket
X-KDE-Weight=30
Name=Applications
Name[de]=Anwendungen
Name[es]=Aplicaciones
Name[fr]=Applications
Name[it]=Applicazioni
Name[ja]=アプリケーション
Name[nb]=Programmer
Name[nn]=Program
Name[pt]=Aplicações
Name[ru]=Приложения
Name[tr]=Uygulamalar
Comment=Applications
Comment[de]=Anwendungen
Comment[es]=Aplicaciones
Comment[fr]=Applications
Comment[it]=Applicazioni
Comment[ja]=アプリケーション
Comment[nb]=Programmer
Comment[nn]=Program
Comment[pt]=Aplicações
Comment[ru]=Приложения
Comment[tr]=Uygulamalar

@ -0,0 +1,37 @@
[Desktop Entry]
Encoding=UTF-8
Icon=basket
Type=Service
ServiceTypes=KCModule
X-KDE-ModuleType=Library
X-KDE-Library=basket
X-KDE-FactoryName=basket_config_baskets
X-KDE-HasReadOnlyMode=false
X-KDE-ParentApp=basket
X-KDE-ParentComponents=basket,kontact_basketplugin
X-KDE-CfgDlgHierarchy=Basket
X-KDE-Weight=10
Name=Baskets
Name[de]=Körbe
Name[es]=Cestas
Name[fr]=Paniers
Name[it]=Canestri
Name[ja]=バスケット
Name[nb]=Kurver
Name[nn]=Korger
Name[pt]=Cestos
Name[ru]=Корзины
Name[tr]=Sepetler
Comment=Baskets
Comment[de]=Körbe
Comment[es]=Cestas
Comment[fr]=Paniers
Comment[it]=Canestri
Comment[ja]=バスケット
Comment[nb]=Kurver
Comment[nn]=Korger
Comment[pt]=Cestos
Comment[ru]=Корзины
Comment[tr]=Sepetler

@ -0,0 +1 @@
# Was there in 0.6.0 Beta versions. Should not be used anymore.

@ -0,0 +1,37 @@
[Desktop Entry]
Encoding=UTF-8
Icon=configure
Type=Service
ServiceTypes=KCModule
X-KDE-ModuleType=Library
X-KDE-Library=basket
X-KDE-FactoryName=basket_config_general
X-KDE-HasReadOnlyMode=false
X-KDE-ParentApp=basket
X-KDE-ParentComponents=basket,kontact_basketplugin
X-KDE-CfgDlgHierarchy=Basket
X-KDE-Weight=10
Name=General
Name[de]=Allgemein
Name[es]=General
Name[fr]=Général
Name[it]=Generale
Name[ja]=全般
Name[nb]=Generelt
Name[nn]=Generelt
Name[pt]=Geral
Name[ru]=Общие
Name[tr]=Genel
Comment=General
Comment[de]=Allgemein
Comment[es]=General
Comment[fr]=Général
Comment[it]=Generale
Comment[ja]=全般
Comment[nb]=Generelt
Comment[nn]=Generelt
Comment[pt]=Geral
Comment[ru]=Общие
Comment[de]=Genel

@ -0,0 +1,37 @@
[Desktop Entry]
Encoding=UTF-8
Icon=filenew
Type=Service
ServiceTypes=KCModule
X-KDE-ModuleType=Library
X-KDE-Library=basket
X-KDE-FactoryName=basket_config_new_notes
X-KDE-HasReadOnlyMode=false
X-KDE-ParentApp=basket
X-KDE-ParentComponents=basket,kontact_basketplugin
X-KDE-CfgDlgHierarchy=Basket
X-KDE-Weight=10
Name=New Notes
Name[de]=Neue Notizen
Name[es]=Notas nuevas
Name[fr]=Nouvelles notes
Name[it]=Nuove note
Name[ja]=新しいメモ
Name[nb]=Nye notat
Name[nn]=Nye notat
Name[pt]=Anotações novas
Name[ru]=Новые заметки
Name[tr]=Yeni Notlar
Comment=New Notes
Comment[de]=Neue Notizen
Comment[es]=Notas nuevas
Comment[fr]=Nouvelles notes
Comment[it]=Nuove note
Comment[ja]=新しいメモ
Comment[nb]=Nye notat
Comment[nn]=Nye notat
Comment[pt]=Anotações novas
Comment[ru]=Новые заметки
Comment[tr]=Yeni Notlar

@ -0,0 +1 @@
# Was there in 0.6.0 Beta versions. Should not be used anymore.

@ -0,0 +1,35 @@
[Desktop Entry]
Encoding=UTF-8
Icon=colorize
Type=Service
ServiceTypes=KCModule
X-KDE-ModuleType=Library
X-KDE-Library=basket
X-KDE-FactoryName=basket_config_notes_appearance
X-KDE-HasReadOnlyMode=false
X-KDE-ParentApp=basket
X-KDE-ParentComponents=basket,kontact_basketplugin
X-KDE-CfgDlgHierarchy=Basket
X-KDE-Weight=10
Name=Notes Appearance
Name[de]=Erscheinungsbild
Name[es]=Apariencia de las notas
Name[fr]=Apparence des notes
Name[it]=Aspetto delle note
Name[ja]=メモの外観
Name[nb]=Notatutseende
Name[nn]=Notatutsjånad
Name[ru]=Вид
Name[tr]=Not Görünümleri
Comment=Notes Appearance
Comment[de]=Erscheinungsbild der Notizen
Comment[es]=Apariencia de las notas
Comment[fr]=Apparence des notes
Comment[it]=Aspetto delle note
Comment[ja]=メモの外観
Comment[nb]=Notatutseende
Comment[nn]=Notatutsjånad
Comment[ru]=Вид
Comment[tr]=Not Görünümleri

@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKET_OPTIONS_H
#define BASKET_OPTIONS_H
#include <kcmdlineargs.h>
#include <klocale.h>
KCmdLineOptions basket_options[] =
{
{ "d", 0, 0 },
{ "debug", I18N_NOOP("Show the debug window"), 0 },
{ "f", 0, 0 },
{ "data-folder <folder>", I18N_NOOP("Custom folder where to load and save basket data and application data (useful for debugging purpose)"), 0 },
{ "h", 0, 0 },
{ "start-hidden", I18N_NOOP("Hide the main window in the system tray icon on startup"), 0 },
{ "k", 0, 0 },
{ "use-drkonquy", I18N_NOOP("When crashing, use the standard KDE report dialog instead of sending an email"), 0 },
{ "+[file]", I18N_NOOP("Open basket archive or template"), 0 },
KCmdLineLastOption
};
#endif // BASKET_OPTIONS_H

@ -0,0 +1,102 @@
/***************************************************************************
* Copyright (C) 2003 by Petri Damsten *
* petri.damsten@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "basket_part.h"
#include <kinstance.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <klocale.h>
#include <bnpview.h>
#include <aboutdata.h>
#include <kparts/genericfactory.h>
#include <kparts/statusbarextension.h>
#include "basketstatusbar.h"
typedef KParts::GenericFactory< BasketPart > BasketFactory;
K_EXPORT_COMPONENT_FACTORY( libbasketpart, BasketFactory )
BasketPart::BasketPart( QWidget *parentWidget, const char *,
QObject *parent, const char *name, const QStringList & )
: KParts::ReadWritePart(parent, name)
{
// we need an instance
setInstance( BasketFactory::instance() );
BasketStatusBar* bar = new BasketStatusBar(new KParts::StatusBarExtension(this));
// this should be your custom internal widget
m_view = new BNPView(parentWidget, "BNPViewPart", this, actionCollection(), bar);
connect(m_view, SIGNAL(setWindowCaption(const QString &)), this, SLOT(setCaption(const QString &)));
connect(m_view, SIGNAL(showPart()), this, SIGNAL(showPart()));
m_view->setFocusPolicy(QWidget::ClickFocus);
// notify the part that this is our internal widget
setWidget(m_view);
// set our XML-UI resource file
setXMLFile("basket_part.rc");
// we are read-write by default
setReadWrite(true);
// we are not modified since we haven't done anything yet
setModified(false);
}
BasketPart::~BasketPart()
{}
void BasketPart::setReadWrite(bool rw)
{
// TODO: notify your internal widget of the read-write state
ReadWritePart::setReadWrite(rw);
}
void BasketPart::setModified(bool modified)
{
// in any event, we want our parent to do it's thing
ReadWritePart::setModified(modified);
}
bool BasketPart::openFile()
{
// TODO
return false;
}
bool BasketPart::saveFile()
{
//TODO
return false;
}
KAboutData *BasketPart::createAboutData()
{
return new AboutData();
}
void BasketPart::setCaption(const QString &caption)
{
emit setWindowCaption(caption);
}
#include "basket_part.moc"

@ -0,0 +1,21 @@
[Desktop Entry]
Encoding=UTF-8
Name=basketPart
Name[br]=Perzhbasket
Name[ca]=Part per a basket
Name[el]=Τμήμαbasket
Name[es]=Componente de Basket
Name[et]=basket komponent
Name[it]=Componente basket
Name[ja]=basket パート
Name[nb]=kurvDel
Name[nn]=korgDel
Name[pt_BR]=Parte basket
Name[sv]=basket-del
Name[ta]=basketபாகம்
Name[tr]=basket Bileşeni
Name[ru]=Модуль basket
MimeType=application/x-basket;
ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
X-KDE-Library=libbasketpart
Type=Service

@ -0,0 +1,91 @@
/***************************************************************************
* Copyright (C) 2003 by Petri Damsten *
* petri.damsten@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef _BASKETPART_H_
#define _BASKETPART_H_
#include <kparts/part.h>
#include <kparts/factory.h>
class QWidget;
class QPainter;
class KURL;
class QMultiLineEdit;
class BNPView;
/**
* This is a "Part". It that does all the real work in a KPart
* application.
*
* @short Main Part
* @author Petri Damsten <petri.damsten@iki.fi>
* @version 0.1
*/
class BasketPart : public KParts::ReadWritePart
{
Q_OBJECT
public:
/**
* Default constructor
*/
BasketPart(QWidget *parentWidget, const char *widgetName,
QObject *parent, const char *name, const QStringList &);
/**
* Destructor
*/
virtual ~BasketPart();
/**
* This is a virtual function inherited from KParts::ReadWritePart.
* A shell will use this to inform this Part if it should act
* read-only
*/
virtual void setReadWrite(bool rw);
/**
* Reimplemented to disable and enable Save action
*/
virtual void setModified(bool modified);
static KAboutData *createAboutData();
signals:
void showPart();
protected:
/**
* This must be implemented by each part
*/
virtual bool openFile();
/**
* This must be implemented by each read-write part
*/
virtual bool saveFile();
protected slots:
void setCaption(const QString &caption);
private:
BNPView *m_view;
};
#endif // _BASKETPART_H_

@ -0,0 +1,229 @@
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui version="1.0.3.1" name="basket" >
<MenuBar noMerge="1" >
<Menu name="file" >
<text>&amp;Basket</text>
<Action name="basket_new_menu" />
<Separator/>
<Action name="basket_properties" />
<Menu icon="fileexport" >
<text>&amp;Export</text>
<Action name="basket_export_basket_archive" />
<Action name="basket_export_html" />
</Menu>
<Action name="basket_remove" />
<Separator/>
<Action name="basket_password" />
<Action name="basket_lock" />
<Separator/>
<Menu name="fileimport" icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
</Menu>
<Menu name="edit" >
<text>&amp;Edit</text>
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_paste" />
<Action name="edit_delete" />
<Separator/>
<Action name="edit_select_all" />
<Action name="edit_unselect_all" />
<Action name="edit_invert_selection" />
<Separator/>
<Action name="edit_filter" />
<Action name="edit_filter_all_baskets" />
<Action name="edit_filter_reset" />
</Menu>
<Menu name="go" >
<text>&amp;Go</text>
<Action name="go_basket_previous" />
<Action name="go_basket_next" />
<Action name="go_basket_fold" />
<Action name="go_basket_expand" />
</Menu>
<Menu name="note" >
<text>&amp;Note</text>
<Action name="note_edit" />
<Action name="note_open" />
<Action name="note_open_with" />
<Action name="note_save_to_file" />
<Separator/>
<Action name="note_group" />
<Action name="note_ungroup" />
<Separator/>
<Action name="note_move_top" />
<Action name="note_move_up" />
<Action name="note_move_down" />
<Action name="note_move_bottom" />
</Menu>
<Menu name="tags" >
<text>&amp;Tags</text>
</Menu>
<Menu name="insert" >
<text>&amp;Insert</text>
<Action name="insert_html" />
<Action name="insert_image" />
<Action name="insert_link" />
<Action name="insert_launcher" />
<Action name="insert_color" />
<Separator/>
<Action name="insert_screen_capture" />
<Action name="insert_screen_color" />
<Separator/>
<Action name="insert_from_file" />
<Action name="insert_kmenu" />
<Action name="insert_icon" />
</Menu>
<Menu name="settings" >
<text>&amp;Settings</text>
<Merge name="StandardToolBarMenuHandler" />
<Action name="options_show_statusbar" />
<Separator/>
<Action name="options_configure_keybinding" />
<Action name="options_configure_global_keybinding" />
<Action name="options_configure_toolbars" />
<Action name="options_configure_notifications" />
<Action name="options_configure" />
</Menu>
<Menu name="help" >
<text>&amp;Help</text>
<Action name="help_contents" />
<Action name="help_plugins_contents" />
<Action name="help_whats_this" />
<Action name="help_show_tip" />
<Separator/>
<Action name="help_welcome_baskets" />
<!-- <Action name="help_report_bug" />-->
<Action name="likeback_send_a_comment" />
<Separator/>
<Action name="help_about_app" />
<Action name="help_about_kde" />
</Menu>
</MenuBar>
<ToolBar newline="false" position="Top" noMerge="1" name="mainToolBar" fullWidth="true" >
<text>Main Toolbar</text>
<Action name="basket_properties" />
<Separator lineSeparator="true" name="separator_0" />
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_paste" />
<Action name="edit_delete" />
<Separator lineSeparator="true" name="separator_1" />
<Action name="note_group" />
</ToolBar>
<ToolBar newline="false" position="Top" noMerge="1" name="richTextEditToolBar" fullWidth="true" >
<text>Text Formating Toolbar</text>
<Action name="richtext_undo" />
<Action name="richtext_redo" />
<Separator lineSeparator="true" name="separator_1" />
<Action name="richtext_font" />
<Separator lineSeparator="false" name="separator_2" />
<Action name="richtext_font_size" />
<Separator lineSeparator="false" name="separator_3" />
<Action name="richtext_color" />
<Separator lineSeparator="true" name="separator_4" />
<Action name="richtext_bold" />
<Action name="richtext_italic" />
<Action name="richtext_underline" />
<!--
<Separator lineSeparator="true" name="separator_2" />
<Action name="richtext_super" />
<Action name="richtext_sub" />
-->
<Separator lineSeparator="true" name="separator_3" />
<Action name="richtext_left" />
<Action name="richtext_center" />
<Action name="richtext_right" />
<Action name="richtext_block" />
</ToolBar>
<Menu name="basket_popup" >
<Action name="basket_new_menu" />
<Separator/>
<Action name="basket_properties" />
<Menu icon="fileexport" >
<text>&amp;Export</text>
<Action name="basket_export_basket_archive" />
<Action name="basket_export_html" />
</Menu>
<Action name="basket_remove" />
<Separator/>
<Action name="basket_password" />
<Action name="basket_lock" />
<Separator/>
<Menu icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
</Menu>
<Menu name="tab_bar_popup" >
<Action name="basket_new" />
<Menu icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
</Menu>
<Menu noMerge="1" name="note_popup" >
<Action name="note_edit" />
<Action name="note_open" />
<Action name="note_open_with" />
<Action name="note_save_to_file" />
<Separator/>
<Action name="note_group" />
<Action name="note_ungroup" />
<Separator/>
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_delete" />
</Menu>
<Menu noMerge="1" name="insert_popup" >
<Action name="insert_html" />
<Action name="insert_image" />
<Action name="insert_link" />
<Action name="insert_launcher" />
<Action name="insert_color" />
<Separator/>
<Action name="insert_screen_capture" />
<Action name="insert_screen_color" />
<Separator/>
<Action name="insert_from_file" />
<Action name="insert_kmenu" />
<Action name="insert_icon" />
<Separator/>
<Action name="edit_paste" />
</Menu>
</kpartgui>

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 2003 by Petri Damsten *
* petri.damsten@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKETDCOPINTERFACE_H
#define BASKETDCOPINTERFACE_H
#include <dcopobject.h>
/**
@author Petri Damsten <petri.damsten@iki.fi>
*/
class BasketDcopInterface : virtual public DCOPObject
{
K_DCOP
k_dcop:
virtual ASYNC newBasket() = 0;
virtual void handleCommandLine() = 0;
};
#endif

@ -0,0 +1,159 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qdir.h>
#include <klocale.h>
#include <kmessagebox.h>
#include "basketfactory.h"
#include "global.h"
#include "basket.h"
#include "xmlwork.h"
#include "note.h" // For balanced column width computation
#include "bnpview.h"
/** BasketFactory */
// TODO: Don't create a basket with a name that already exists!
QString BasketFactory::newFolderName()
{
QString folderName;
QString fullPath;
QDir dir;
for (int i = 1; ; ++i) {
folderName = "basket" + QString::number(i) + "/";
fullPath = Global::basketsFolder() + folderName;
dir = QDir(fullPath);
if ( ! dir.exists() ) // OK : The folder do not yet exists :
break; // We've found one !
}
return folderName;
}
QString BasketFactory::unpackTemplate(const QString &templateName)
{
// Find a name for a new folder and create it:
QString folderName = newFolderName();
QString fullPath = Global::basketsFolder() + folderName;
QDir dir;
if (!dir.mkdir(fullPath)) {
KMessageBox::error(/*parent=*/0, i18n("Sorry, but the folder creation for this new basket has failed."), i18n("Basket Creation Failed"));
return "";
}
// Unpack the template file to that folder:
// TODO: REALLY unpack (this hand-creation is temporary, or it could be used in case the template can't be found)
QFile file(fullPath + "/.basket");
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
int nbColumns = (templateName == "mindmap" || templateName == "free" ? 0 : templateName.left(1).toInt());
Basket *currentBasket = Global::bnpView->currentBasket();
int columnWidth = (currentBasket && nbColumns > 0 ? (currentBasket->visibleWidth() - (nbColumns-1)*Note::RESIZER_WIDTH) / nbColumns : 0);
stream << QString( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE basket>\n"
"<basket>\n"
" <properties>\n"
" <disposition mindMap=\"%1\" columnCount=\"%2\" free=\"%3\" />\n"
" </properties>\n"
" <notes>\n" ).arg( (templateName == "mindmap" ? "true" : "false"),
QString::number(nbColumns),
(templateName == "free" || templateName == "mindmap" ? "true" : "false") );
if (nbColumns > 0)
for (int i = 0; i < nbColumns; ++i)
stream << QString(" <group width=\"%1\"></group>\n").arg(columnWidth);
stream << " </notes>\n"
"</basket>\n";
file.close();
return folderName;
} else {
KMessageBox::error(/*parent=*/0, i18n("Sorry, but the template copying for this new basket has failed."), i18n("Basket Creation Failed"));
return "";
}
}
void BasketFactory::newBasket(const QString &icon,
const QString &name,
const QString &backgroundImage,
const QColor &backgroundColor,
const QColor &textColor,
const QString &templateName,
Basket *parent)
{
// Unpack the templateName file to a new basket folder:
QString folderName = unpackTemplate(templateName);
if (folderName.isEmpty())
return;
// Read the properties, change those that should be customized and save the result:
QDomDocument *document = XMLWork::openFile("basket", Global::basketsFolder() + folderName + "/.basket");
if (!document) {
KMessageBox::error(/*parent=*/0, i18n("Sorry, but the template customization for this new basket has failed."), i18n("Basket Creation Failed"));
return;
}
QDomElement properties = XMLWork::getElement(document->documentElement(), "properties");
if (!icon.isEmpty()) {
QDomElement iconElement = XMLWork::getElement(properties, "icon");
if (!iconElement.tagName().isEmpty()) // If there is already an icon, remove it since we will add our own value below
iconElement.removeChild(iconElement.firstChild());
XMLWork::addElement(*document, properties, "icon", icon);
}
if (!name.isEmpty()) {
QDomElement nameElement = XMLWork::getElement(properties, "name");
if (!nameElement.tagName().isEmpty()) // If there is already a name, remove it since we will add our own value below
nameElement.removeChild(nameElement.firstChild());
XMLWork::addElement(*document, properties, "name", name);
}
if (backgroundColor.isValid()) {
QDomElement appearanceElement = XMLWork::getElement(properties, "appearance");
if (appearanceElement.tagName().isEmpty()) { // If there is not already an appearance tag, add it since we will access it below
appearanceElement = document->createElement("appearance");
properties.appendChild(appearanceElement);
}
appearanceElement.setAttribute("backgroundColor", backgroundColor.name());
}
if (!backgroundImage.isEmpty()) {
QDomElement appearanceElement = XMLWork::getElement(properties, "appearance");
if (appearanceElement.tagName().isEmpty()) { // If there is not already an appearance tag, add it since we will access it below
appearanceElement = document->createElement("appearance");
properties.appendChild(appearanceElement);
}
appearanceElement.setAttribute("backgroundImage", backgroundImage);
}
if (textColor.isValid()) {
QDomElement appearanceElement = XMLWork::getElement(properties, "appearance");
if (appearanceElement.tagName().isEmpty()) { // If there is not already an appearance tag, add it since we will access it below
appearanceElement = document->createElement("appearance");
properties.appendChild(appearanceElement);
}
appearanceElement.setAttribute("textColor", textColor.name());
}
// Load it in the parent basket (it will save the tree and switch to this new basket):
Global::bnpView->loadNewBasket(folderName, properties, parent);
}

@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKETFACTORY_H
#define BASKETFACTORY_H
class QString;
class Basket;
/** Methods to create various baskets (mkdir, init the properties and load it).
* @author Sébastien Laoût
*/
namespace BasketFactory
{
/** You should use this method to create a new basket: */
void newBasket(const QString &icon,
const QString &name,
const QString &backgroundImage,
const QColor &backgroundColor,
const QColor &textColor,
const QString &templateName,
Basket *parent);
/** Internal tool methods to process the method above: */
QString newFolderName();
QString unpackTemplate(const QString &templateName);
}
#endif // BASKETFACTORY_H

@ -0,0 +1,807 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "basketlistview.h"
#include <qregexp.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <qpainter.h>
#include <qbitmap.h>
#include <qpixmapcache.h>
#include <qtooltip.h>
#include <iostream>
#include <kdebug.h>
#include "global.h"
#include "bnpview.h"
#include "basket.h"
#include "tools.h"
#include "settings.h"
#include "notedrag.h"
/** class BasketListViewItem: */
BasketListViewItem::BasketListViewItem(QListView *parent, Basket *basket)
: QListViewItem(parent), m_basket(basket)
, m_isUnderDrag(false)
, m_isAbbreviated(false)
{
setDropEnabled(true);
}
BasketListViewItem::BasketListViewItem(QListViewItem *parent, Basket *basket)
: QListViewItem(parent), m_basket(basket)
, m_isUnderDrag(false)
, m_isAbbreviated(false)
{
setDropEnabled(true);
}
BasketListViewItem::BasketListViewItem(QListView *parent, QListViewItem *after, Basket *basket)
: QListViewItem(parent, after), m_basket(basket)
, m_isUnderDrag(false)
, m_isAbbreviated(false)
{
setDropEnabled(true);
}
BasketListViewItem::BasketListViewItem(QListViewItem *parent, QListViewItem *after, Basket *basket)
: QListViewItem(parent, after), m_basket(basket)
, m_isUnderDrag(false)
, m_isAbbreviated(false)
{
setDropEnabled(true);
}
BasketListViewItem::~BasketListViewItem()
{
}
bool BasketListViewItem::acceptDrop(const QMimeSource *) const
{
std::cout << "accept" << std::endl;
return true;
}
void BasketListViewItem::dropped(QDropEvent *event)
{
std::cout << "Dropping into basket " << m_basket->name() << std::endl;
m_basket->contentsDropEvent(event);
//Global::bnpView->currentBasket()->contentsDropEvent(event); // FIXME
}
int BasketListViewItem::width(const QFontMetrics &/* fontMetrics */, const QListView */*listView*/, int /* column */) const
{
return listView()->visibleWidth() + 100;
/*
int BASKET_ICON_SIZE = 16;
int MARGIN = 1;
QRect textRect = fontMetrics.boundingRect(0, 0, / *width=* /1, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::ShowPrefix, text(column));
return MARGIN + BASKET_ICON_SIZE + MARGIN + textRect.width() + BASKET_ICON_SIZE/2 + MARGIN;
*/
}
QString BasketListViewItem::escapedName(const QString &string)
{
// Underlining the Alt+Letter shortcut (and escape all other '&' characters), if any:
QString basketName = string;
basketName.replace('&', "&&"); // First escape all the amperstamp
QString letter; // Find the letter
QString altKey = /*i18n(*/"Alt"/*)*/; //i18n("The [Alt] key, as shown in shortcuts like Alt+C...", "Alt");
QString shiftKey = /*i18n(*/"Shift"/*)*/; //i18n("The [Shift] key, as shown in shortcuts like Alt+Shift+1...", "Shift");
QRegExp altLetterExp( QString("^%1\\+(.)$").arg(altKey) );
QRegExp altShiftLetterExp( QString("^%1\\+%2\\+(.)$").arg(altKey, shiftKey) );
if (altLetterExp.search(m_basket->shortcut().toStringInternal()) != -1)
letter = altLetterExp.cap(1);
if (letter.isEmpty() && altShiftLetterExp.search(m_basket->shortcut().toStringInternal()) != -1)
letter = altShiftLetterExp.cap(1);
if (!letter.isEmpty()) {
int index = basketName.find(letter, /*index=*/0, /*caseSensitive=*/false);
if (index != -1)
basketName.insert(index, '&');
}
return basketName;
}
void BasketListViewItem::setup()
{
int BASKET_ICON_SIZE = 16;
int MARGIN = 1;
setText(/*column=*/0, escapedName(m_basket->basketName()));
widthChanged();
QRect textRect = listView()->fontMetrics().boundingRect(0, 0, /*width=*/1, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::ShowPrefix, text(/*column=*/0));
int height = MARGIN + QMAX(BASKET_ICON_SIZE, textRect.height()) + MARGIN;
setHeight(height);
QPixmap icon = kapp->iconLoader()->loadIcon(m_basket->icon(), KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/false);
setPixmap(/*column=*/0, icon);
repaint();
}
BasketListViewItem* BasketListViewItem::lastChild()
{
QListViewItem *child = firstChild();
while (child) {
if (child->nextSibling())
child = child->nextSibling();
else
return (BasketListViewItem*)child;
}
return 0;
}
BasketListViewItem* BasketListViewItem::prevSibling()
{
BasketListViewItem *item = this;
while (item) {
if (item->nextSibling() == this)
return item;
item = (BasketListViewItem*)(item->itemAbove());
}
return 0;
}
BasketListViewItem* BasketListViewItem::shownItemAbove()
{
BasketListViewItem *item = (BasketListViewItem*)itemAbove();
while (item) {
if (item->isShown())
return item;
item = (BasketListViewItem*)(item->itemAbove());
}
return 0;
}
BasketListViewItem* BasketListViewItem::shownItemBelow()
{
BasketListViewItem *item = (BasketListViewItem*)itemBelow();
while (item) {
if (item->isShown())
return item;
item = (BasketListViewItem*)(item->itemBelow());
}
return 0;
}
QStringList BasketListViewItem::childNamesTree(int deep)
{
QStringList result;
for (QListViewItem *child = firstChild(); child; child = child->nextSibling()) {
BasketListViewItem *item = (BasketListViewItem*)child;
// Compute indentation spaces:
QString spaces;
for (int i = 0; i < deep; ++i)
spaces += " ";
// Append the name:
result.append(spaces + item->basket()->basketName());
// Append the childs:
if (child->firstChild()) {
QStringList childs = item->childNamesTree(deep + 1);
for (QStringList::iterator it = childs.begin(); it != childs.end(); ++it)
result.append(*it);
}
}
return result;
}
void BasketListViewItem::moveChildsBaskets()
{
QListViewItem *insertAfterThis = this;
QListViewItem *nextOne;
for (QListViewItem *child = firstChild(); child; child = nextOne) {
nextOne = child->nextSibling();
// Re-insert the item with the good parent:
takeItem(child);
if (parent())
parent()->insertItem(child);
else
listView()->insertItem(child);
// And move it at the good place:
child->moveItem(insertAfterThis);
insertAfterThis = child;
}
}
void BasketListViewItem::ensureVisible()
{
BasketListViewItem *item = this;
while (item->parent()) {
item = (BasketListViewItem*)(item->parent());
item->setOpen(true);
}
}
bool BasketListViewItem::isShown()
{
QListViewItem *item = parent();
while (item) {
if (!item->isOpen())
return false;
item = item->parent();
}
return true;
}
bool BasketListViewItem::isCurrentBasket()
{
return basket() == Global::bnpView->currentBasket();
}
// TODO: Move this function from item.cpp to class Tools:
extern void drawGradient( QPainter *p, const QColor &colorTop, const QColor & colorBottom,
int x, int y, int w, int h,
bool sunken, bool horz, bool flat ); /*const*/
QPixmap BasketListViewItem::circledTextPixmap(const QString &text, int height, const QFont &font, const QColor &color)
{
QString key = QString("BLI-%1.%2.%3.%4")
.arg(text).arg(height).arg(font.toString()).arg(color.rgb());
if (QPixmap* cached=QPixmapCache::find(key)) {
return *cached;
}
// Compute the sizes of the image components:
QRect textRect = QFontMetrics(font).boundingRect(0, 0, /*width=*/1, height, Qt::AlignAuto | Qt::AlignTop, text);
int xMargin = height / 6;
int width = xMargin + textRect.width() + xMargin;
// Create the gradient image:
QPixmap gradient(3 * width, 3 * height); // We double the size to be able to smooth scale down it (== antialiased curves)
QPainter gradientPainter(&gradient);
#if 1 // Enable the new look of the gradient:
QColor topColor = KGlobalSettings::highlightColor().light(130); //120
QColor topMidColor = KGlobalSettings::highlightColor().light(105); //105
QColor bottomMidColor = KGlobalSettings::highlightColor().dark(130); //120
QColor bottomColor = KGlobalSettings::highlightColor();
drawGradient(&gradientPainter, topColor, topMidColor,
0, 0, gradient.width(), gradient.height() / 2, /*sunken=*/false, /*horz=*/true, /*flat=*/false);
drawGradient(&gradientPainter, bottomMidColor, bottomColor,
0, gradient.height() / 2, gradient.width(), gradient.height() - gradient.height() / 2, /*sunken=*/false, /*horz=*/true, /*flat=*/false);
gradientPainter.fillRect(0, 0, gradient.width(), 3, KGlobalSettings::highlightColor());
#else
drawGradient(&gradientPainter, KGlobalSettings::highlightColor(), KGlobalSettings::highlightColor().dark(),
0, 0, gradient.width(), gradient.height(), /*sunken=*/false, /*horz=*/true, /*flat=*/false);
#endif
gradientPainter.end();
// Draw the curved rectangle:
QBitmap curvedRectangle(3 * width, 3 * height);
curvedRectangle.fill(Qt::color0);
QPainter curvePainter(&curvedRectangle);
curvePainter.setPen(Qt::color1);
curvePainter.setBrush(Qt::color1);
curvePainter.setClipRect(0, 0, 3*(height / 5), 3*(height)); // If the width is small, don't fill the right part of the pixmap
curvePainter.drawEllipse(0, 3*(-height / 4), 3*(height), 3*(height * 3 / 2)); // Don't forget we double the sizes
curvePainter.setClipRect(3*(width - height / 5), 0, 3*(height / 5), 3*(height));
curvePainter.drawEllipse(3*(width - height), 3*(-height / 4), 3*(height), 3*(height * 3 / 2));
curvePainter.setClipping(false);
curvePainter.fillRect(3*(height / 6), 0, 3*(width - 2 * height / 6), 3*(height), curvePainter.brush());
curvePainter.end();
// Apply the curved rectangle as the mask of the gradient:
gradient.setMask(curvedRectangle);
QImage resultImage = gradient.convertToImage();
resultImage.setAlphaBuffer(true);
// Scale down the image smoothly to get anti-aliasing:
QPixmap pmScaled;
pmScaled.convertFromImage(resultImage.smoothScale(width, height));
// Draw the text, and return the result:
QPainter painter(&pmScaled);
painter.setPen(color);
painter.setFont(font);
painter.drawText(0+1, 0, width, height, Qt::AlignHCenter | Qt::AlignVCenter, text);
painter.end();
QPixmapCache::insert(key, pmScaled);
return pmScaled;
}
QPixmap BasketListViewItem::foundCountPixmap(bool isLoading, int countFound, bool childsAreLoading, int countChildsFound, const QFont &font, int height)
{
if (isLoading)
return QPixmap();
QFont boldFont(font);
boldFont.setBold(true);
QString text;
if (childsAreLoading) {
if (countChildsFound > 0)
text = i18n("%1+%2+").arg(QString::number(countFound), QString::number(countChildsFound));
else
text = i18n("%1+").arg(QString::number(countFound));
} else {
if (countChildsFound > 0)
text = i18n("%1+%2").arg(QString::number(countFound), QString::number(countChildsFound));
else if (countFound > 0)
text = QString::number(countFound);
else
return QPixmap();
}
return circledTextPixmap(text, height, boldFont, KGlobalSettings::highlightedTextColor());
}
bool BasketListViewItem::haveChildsLoading()
{
QListViewItem *child = firstChild();
while (child) {
BasketListViewItem *childItem = (BasketListViewItem*)child;
if (!childItem->basket()->isLoaded() && !childItem->basket()->isLocked())
return true;
if (childItem->haveChildsLoading())
return true;
child = child->nextSibling();
}
return false;
}
bool BasketListViewItem::haveHiddenChildsLoading()
{
if (isOpen())
return false;
return haveChildsLoading();
}
bool BasketListViewItem::haveChildsLocked()
{
QListViewItem *child = firstChild();
while (child) {
BasketListViewItem *childItem = (BasketListViewItem*)child;
if (/*!*/childItem->basket()->isLocked())
return true;
if (childItem->haveChildsLocked())
return true;
child = child->nextSibling();
}
return false;
}
bool BasketListViewItem::haveHiddenChildsLocked()
{
if (isOpen())
return false;
return haveChildsLocked();
}
int BasketListViewItem::countChildsFound()
{
int count = 0;
QListViewItem *child = firstChild();
while (child) {
BasketListViewItem *childItem = (BasketListViewItem*)child;
count += childItem->basket()->countFounds();
count += childItem->countChildsFound();
child = child->nextSibling();
}
return count;
}
int BasketListViewItem::countHiddenChildsFound()
{
if (isOpen())
return 0;
return countChildsFound();
}
void BasketListViewItem::paintCell(QPainter *painter, const QColorGroup &/*colorGroup*/, int /*column*/, int width, int /*align*/)
{
// Workaround a Qt bug:
// When the splitter is moved to hide the tree view and then the application is restarted,
// Qt try to draw items with a negative size!
if (width <= 0) {
std::cout << "width <= 0" << std::endl;
return;
}
int BASKET_ICON_SIZE = 16;
int MARGIN = 1;
// If we are filtering all baskets, and are effectively filtering on something:
bool showLoadingIcon = false;
bool showEncryptedIcon = false;
QPixmap countPixmap;
bool showCountPixmap = Global::bnpView->isFilteringAllBaskets() &&
Global::bnpView->currentBasket()->decoration()->filterBar()->filterData().isFiltering;
if (showCountPixmap) {
showLoadingIcon = (!m_basket->isLoaded() && !m_basket->isLocked()) || haveHiddenChildsLoading();
showEncryptedIcon = m_basket->isLocked() || haveHiddenChildsLocked();
countPixmap = foundCountPixmap(!m_basket->isLoaded(), m_basket->countFounds(), haveHiddenChildsLoading() || haveHiddenChildsLocked(),
countHiddenChildsFound(), listView()->font(), height() - 2 * MARGIN);
}
int effectiveWidth = width - (countPixmap.isNull() ? 0 : countPixmap.width() + MARGIN)
- (showLoadingIcon || showEncryptedIcon ? BASKET_ICON_SIZE + MARGIN : 0)/*
- (showEncryptedIcon ? BASKET_ICON_SIZE + MARGIN : 0)*/;
bool drawRoundRect = m_basket->backgroundColorSetting().isValid() || m_basket->textColorSetting().isValid();
QColor textColor = (drawRoundRect ? m_basket->textColor() : (isCurrentBasket() ? KGlobalSettings::highlightedTextColor() : KGlobalSettings::textColor()));
BasketListViewItem *shownAbove = shownItemAbove();
BasketListViewItem *shownBelow = shownItemBelow();
// Don't forget to update the key computation if parameters
// affecting the rendering logic change
QString key = QString("BLVI::pC-%1.%2.%3.%4.%5.%6.%7.%8.%9.%10.%11.%12.%13.%14.%15")
.arg(effectiveWidth)
.arg(drawRoundRect)
.arg(textColor.rgb())
.arg(m_basket->backgroundColor().rgb())
.arg(isCurrentBasket())
.arg(shownBelow && shownBelow->isCurrentBasket())
.arg(shownAbove && shownAbove->isCurrentBasket())
.arg(showLoadingIcon)
.arg(showEncryptedIcon)
.arg(showCountPixmap)
.arg(m_basket->countFounds())
.arg(countHiddenChildsFound())
.arg(m_isUnderDrag)
.arg(m_basket->basketName())
.arg(m_basket->icon());
if (QPixmap* cached = QPixmapCache::find(key)) {
// Qt's documentation recommends copying the pointer
// into a QPixmap immediately
QPixmap cachedBuffer = *cached;
painter->drawPixmap(0, 0, cachedBuffer);
return;
}
// Bufferize the drawing of items (otherwize, resizing the splitter make the tree act like a Christmas Tree ;-D ):
QPixmap theBuffer(width, height());
QPainter thePainter(&theBuffer);
// Fill with the basket background color:
QColor background = (isCurrentBasket() ? KGlobalSettings::highlightColor() : listView()->paletteBackgroundColor());
thePainter.fillRect(0, 0, width, height(), background);
int textWidth = effectiveWidth - MARGIN - BASKET_ICON_SIZE - MARGIN - MARGIN;
// Draw the rounded rectangle:
if (drawRoundRect) {
QRect textRect = listView()->fontMetrics().boundingRect(0, 0, /*width=*/1, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::ShowPrefix, text(/*column=*/0));
int xRound = MARGIN;
int yRound = MARGIN;
int hRound = height() - 2 * MARGIN;
int wRound = QMIN(BASKET_ICON_SIZE + MARGIN + textRect.width() + hRound/2, effectiveWidth - MARGIN - MARGIN);
if (wRound > 0) { // Do not crash if there is no space anymore to draw the rounded rectangle:
QPixmap buffer(wRound * 2, hRound * 2);
buffer.fill(background);
QPainter pBuffer(&buffer);
QColor colorRound = m_basket->backgroundColor();
pBuffer.setPen(colorRound);
pBuffer.setBrush(colorRound);
if (wRound > hRound) { // If the rectangle is smaller in width than in height, don't overlap ellipses...
pBuffer.drawEllipse(0, 0, hRound * 2, hRound * 2);
pBuffer.drawEllipse(wRound * 2 - hRound * 2, 0, hRound * 2, hRound * 2);
pBuffer.fillRect(hRound*2/2, 0, wRound * 2 - hRound * 2, hRound * 2, colorRound);
} else
pBuffer.drawEllipse(0, 0, wRound * 2, hRound * 2);
pBuffer.end();
QImage imageToScale = buffer.convertToImage();
QPixmap pmScaled;
pmScaled.convertFromImage(imageToScale.smoothScale(wRound, hRound));
thePainter.drawPixmap(xRound, yRound, pmScaled);
textWidth -= hRound/2;
}
}
QColor bgColor = listView()->paletteBackgroundColor();
QColor selColor = KGlobalSettings::highlightColor();
QColor midColor = Tools::mixColor(bgColor, selColor);
// Draw the left selection roundings:
if (isCurrentBasket()) {
thePainter.setPen(bgColor);
thePainter.drawPoint(0, 0);
thePainter.drawPoint(1, 0);
thePainter.drawPoint(0, 1);
thePainter.drawPoint(0, height() - 1);
thePainter.drawPoint(1, height() - 1);
thePainter.drawPoint(0, height() - 2);
thePainter.setPen(midColor);
thePainter.drawPoint(2, 0);
thePainter.drawPoint(0, 2);
thePainter.drawPoint(2, height() - 1);
thePainter.drawPoint(0, height() - 3);
}
// Draw the bottom-right selection roundings:
//BasketListViewItem *shownBelow = shownItemBelow();
if (shownBelow && shownBelow->isCurrentBasket()) {
thePainter.setPen(selColor);
thePainter.drawPoint(width - 1, height() - 1);
thePainter.drawPoint(width - 2, height() - 1);
thePainter.drawPoint(width - 1, height() - 2);
thePainter.setPen(midColor);
thePainter.drawPoint(width - 3, height() - 1);
thePainter.drawPoint(width - 1, height() - 3);
}
// Draw the top-right selection roundings:
// BasketListViewItem *shownAbove = shownItemAbove();
if (shownAbove && shownAbove->isCurrentBasket()) {
thePainter.setPen(selColor);
thePainter.drawPoint(width - 1, 0);
thePainter.drawPoint(width - 2, 0);
thePainter.drawPoint(width - 1, 1);
thePainter.setPen(midColor);
thePainter.drawPoint(width - 3, 0);
thePainter.drawPoint(width - 1, 2);
}
// Draw the icon and text:
int yPixmap = (height() - BASKET_ICON_SIZE) / 2;
thePainter.drawPixmap(MARGIN, yPixmap, *pixmap(/*column=*/0));
thePainter.setPen(textColor);
if (textWidth > 0) { // IF there is space left to draw the text:
int xText = MARGIN + BASKET_ICON_SIZE + MARGIN;
QString theText = m_basket->basketName();
if (painter->fontMetrics().width(theText) > textWidth) {
theText = KStringHandler::rPixelSqueeze(theText, painter->fontMetrics(), textWidth);
m_isAbbreviated = true;
}
else {
m_isAbbreviated = false;
}
theText = escapedName(theText);
thePainter.drawText(xText, 0, textWidth, height(), Qt::AlignAuto | Qt::AlignVCenter | Qt::ShowPrefix, theText);
}
// If we are filtering all baskets, and are effectively filtering on something:
if (!countPixmap.isNull())
{
thePainter.drawPixmap(effectiveWidth, 1, countPixmap);
effectiveWidth += countPixmap.width() + MARGIN;
}
if (showLoadingIcon) {
QPixmap icon = kapp->iconLoader()->loadIcon("find", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/false);
thePainter.drawPixmap(effectiveWidth, 0, icon);
effectiveWidth += BASKET_ICON_SIZE + MARGIN;
}
if (showEncryptedIcon && !showLoadingIcon) {
QPixmap icon = kapp->iconLoader()->loadIcon("encrypted", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/false);
thePainter.drawPixmap(effectiveWidth, 0, icon);
}
if (m_isUnderDrag) {
thePainter.drawWinFocusRect(0, 0, width, height());
}
thePainter.end();
QPixmapCache::insert(key, theBuffer);
// Apply the buffer:
painter->drawPixmap(0, 0, theBuffer);
}
void BasketListViewItem::setUnderDrag(bool underDrag)
{
m_isUnderDrag = underDrag;
}
bool BasketListViewItem::isAbbreviated()
{
return m_isAbbreviated;
}
/** class BasketListViewToolTip: */
class BasketTreeListView_ToolTip : public QToolTip {
public:
BasketTreeListView_ToolTip(BasketTreeListView* basketView)
: QToolTip(basketView->viewport())
, m_basketView(basketView)
{}
public:
void maybeTip(const QPoint& pos)
{
QListViewItem *item = m_basketView->itemAt(m_basketView->contentsToViewport(pos));
BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
if (bitem && bitem->isAbbreviated()) {
tip(m_basketView->itemRect(bitem), bitem->basket()->basketName());
}
}
private:
BasketTreeListView* m_basketView;
};
/** class BasketTreeListView: */
BasketTreeListView::BasketTreeListView(QWidget *parent, const char *name)
: KListView(parent, name), m_autoOpenItem(0)
, m_itemUnderDrag(0)
{
setWFlags(Qt::WStaticContents | WNoAutoErase);
clearWFlags(Qt::WStaticContents | WNoAutoErase);
//viewport()->clearWFlags(Qt::WStaticContents);
connect( &m_autoOpenTimer, SIGNAL(timeout()), this, SLOT(autoOpen()) );
new BasketTreeListView_ToolTip(this);
}
void BasketTreeListView::viewportResizeEvent(QResizeEvent *event)
{
KListView::viewportResizeEvent(event);
triggerUpdate();
}
void BasketTreeListView::contentsDragEnterEvent(QDragEnterEvent *event)
{
if (event->provides("application/x-qlistviewitem")) {
QListViewItemIterator it(this); // TODO: Don't show expanders if it's not a basket drag...
while (it.current()) {
QListViewItem *item = it.current();
if (!item->firstChild()) {
item->setExpandable(true);
item->setOpen(true);
}
++it;
}
update();
}
KListView::contentsDragEnterEvent(event);
}
void BasketTreeListView::removeExpands()
{
QListViewItemIterator it(this);
while (it.current()) {
QListViewItem *item = it.current();
if (!item->firstChild())
item->setExpandable(false);
++it;
}
viewport()->update();
}
void BasketTreeListView::contentsDragLeaveEvent(QDragLeaveEvent *event)
{
std::cout << "BasketTreeListView::contentsDragLeaveEvent" << std::endl;
m_autoOpenItem = 0;
m_autoOpenTimer.stop();
setItemUnderDrag(0);
removeExpands();
KListView::contentsDragLeaveEvent(event);
}
void BasketTreeListView::contentsDropEvent(QDropEvent *event)
{
std::cout << "BasketTreeListView::contentsDropEvent()" << std::endl;
if (event->provides("application/x-qlistviewitem"))
{
KListView::contentsDropEvent(event);
}
else {
std::cout << "Forwarding dropped data to the basket" << std::endl;
QListViewItem *item = itemAt(contentsToViewport(event->pos()));
BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
if (bitem) {
bitem->basket()->blindDrop(event);
}
else {
std::cout << "Forwarding failed: no bitem found" << std::endl;
}
}
m_autoOpenItem = 0;
m_autoOpenTimer.stop();
setItemUnderDrag(0);
removeExpands();
Global::bnpView->save(); // TODO: Don't save if it was not a basket drop...
}
void BasketTreeListView::contentsDragMoveEvent(QDragMoveEvent *event)
{
std::cout << "BasketTreeListView::contentsDragMoveEvent" << std::endl;
if (event->provides("application/x-qlistviewitem"))
KListView::contentsDragMoveEvent(event);
else {
QListViewItem *item = itemAt(contentsToViewport(event->pos()));
BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
if (m_autoOpenItem != item) {
m_autoOpenItem = item;
m_autoOpenTimer.start(1700, /*singleShot=*/true);
}
if (item) {
event->acceptAction(true);
event->accept(true);
}
setItemUnderDrag(bitem);
KListView::contentsDragMoveEvent(event); // FIXME: ADDED
}
}
void BasketTreeListView::setItemUnderDrag(BasketListViewItem* item)
{
if (m_itemUnderDrag != item) {
if (m_itemUnderDrag) {
// Remove drag status from the old item
m_itemUnderDrag->setUnderDrag(false);
repaintItem(m_itemUnderDrag);
}
m_itemUnderDrag = item;
if (m_itemUnderDrag) {
// add drag status to the new item
m_itemUnderDrag->setUnderDrag(true);
repaintItem(m_itemUnderDrag);
}
}
}
void BasketTreeListView::autoOpen()
{
BasketListViewItem *item = (BasketListViewItem*)m_autoOpenItem;
if (item)
Global::bnpView->setCurrentBasket(item->basket());
}
void BasketTreeListView::resizeEvent(QResizeEvent *event)
{
KListView::resizeEvent(event);
}
void BasketTreeListView::paintEmptyArea(QPainter *painter, const QRect &rect)
{
QListView::paintEmptyArea(painter, rect);
BasketListViewItem *last = Global::bnpView->lastListViewItem();
if (last && !last->isShown())
last = last->shownItemAbove();
if (last && last->isCurrentBasket()) {
int y = last->itemPos() + last->height();
QColor bgColor = paletteBackgroundColor();
QColor selColor = KGlobalSettings::highlightColor();
QColor midColor = Tools::mixColor(bgColor, selColor);
painter->setPen(selColor);
painter->drawPoint(visibleWidth() - 1, y);
painter->drawPoint(visibleWidth() - 2, y);
painter->drawPoint(visibleWidth() - 1, y + 1);
painter->setPen(midColor);
painter->drawPoint(visibleWidth() - 3, y);
painter->drawPoint(visibleWidth() - 1, y + 2);
}
}
/** We should NEVER get focus (because of QWidget::NoFocus focusPolicy())
* but KListView can programatically give us the focus.
* So we give it to the basket.
*/
void BasketTreeListView::focusInEvent(QFocusEvent*)
{
//KListView::focusInEvent(event);
Basket *basket = Global::bnpView->currentBasket();
if (basket)
basket->setFocus();
}
#include "basketlistview.moc"

@ -0,0 +1,103 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKETLISTVIEW_H
#define BASKETLISTVIEW_H
#include <klistview.h>
#include <qtimer.h>
class Basket;
class BasketListViewItem : public QListViewItem
{
public:
/// CONSTRUCTOR AND DESTRUCTOR:
BasketListViewItem(QListView *parent, Basket *basket);
BasketListViewItem(QListViewItem *parent, Basket *basket);
BasketListViewItem(QListView *parent, QListViewItem *after, Basket *basket);
BasketListViewItem(QListViewItem *parent, QListViewItem *after, Basket *basket);
~BasketListViewItem();
///
bool acceptDrop(const QMimeSource *mime) const;
void dropped(QDropEvent *event);
Basket *basket() { return m_basket; }
void setup();
int width(const QFontMetrics &fontMetrics, const QListView *listView, int column) const;
BasketListViewItem* lastChild();
BasketListViewItem* prevSibling();
BasketListViewItem* shownItemAbove();
BasketListViewItem* shownItemBelow();
QStringList childNamesTree(int deep = 0);
void moveChildsBaskets();
void ensureVisible();
bool isShown();
bool isCurrentBasket();
void paintCell(QPainter *painter, const QColorGroup &colorGroup, int column, int width, int align);
QString escapedName(const QString &string);
///
QPixmap circledTextPixmap(const QString &text, int height, const QFont &font, const QColor &color);
QPixmap foundCountPixmap(bool isLoading, int countFound, bool childsAreLoading, int countChildsFound, const QFont &font, int height);
bool haveChildsLoading();
bool haveHiddenChildsLoading();
bool haveChildsLocked();
bool haveHiddenChildsLocked();
int countChildsFound();
int countHiddenChildsFound();
void setUnderDrag(bool);
bool isAbbreviated();
///
// QDragObject* dragObject();
// bool acceptDrop ( const QMimeSource * mime ) const;
private:
Basket *m_basket;
int m_width;
bool m_isUnderDrag;
bool m_isAbbreviated;
};
class BasketTreeListView : public KListView
{
Q_OBJECT
public:
BasketTreeListView(QWidget *parent = 0, const char *name = 0);
void contentsDragEnterEvent(QDragEnterEvent *event);
void removeExpands();
void contentsDragLeaveEvent(QDragLeaveEvent *event);
void contentsDragMoveEvent(QDragMoveEvent *event);
void contentsDropEvent(QDropEvent *event);
void resizeEvent(QResizeEvent *event);
void paintEmptyArea(QPainter *painter, const QRect &rect);
protected:
void focusInEvent(QFocusEvent*);
void viewportResizeEvent(QResizeEvent *event);
private:
QTimer m_autoOpenTimer;
QListViewItem *m_autoOpenItem;
private slots:
void autoOpen();
private:
void setItemUnderDrag(BasketListViewItem* item);
BasketListViewItem* m_itemUnderDrag;
};
#endif // BASKETLISTVIEW_H

@ -0,0 +1,203 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kicondialog.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <qvbuttongroup.h>
#include <knuminput.h>
#include <kkeybutton.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qstringlist.h>
#include <klocale.h>
#include <qstyle.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <kglobalsettings.h>
#include "basketproperties.h"
#include "basket.h"
#include "kcolorcombo2.h"
#include "variouswidgets.h"
#include "global.h"
#include "backgroundmanager.h"
BasketPropertiesDialog::BasketPropertiesDialog(Basket *basket, QWidget *parent)
: KDialogBase(KDialogBase::Swallow, i18n("Basket Properties"), KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"BasketProperties", /*modal=*/true, /*separator=*/false),
m_basket(basket)
{
QWidget *page = new QWidget(this);
QVBoxLayout *topLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
// Icon and Name:
QHBoxLayout *nameLayout = new QHBoxLayout(0, marginHint()*2/3, spacingHint());
m_icon = new KIconButton(page);
m_icon->setIconType(KIcon::NoGroup, KIcon::Action);
m_icon->setIconSize(16);
m_icon->setIcon(m_basket->icon());
int size = QMAX(m_icon->sizeHint().width(), m_icon->sizeHint().height());
m_icon->setFixedSize(size, size); // Make it square!
QToolTip::add(m_icon, i18n("Icon"));
m_name = new QLineEdit(m_basket->basketName(), page);
m_name->setMinimumWidth(m_name->fontMetrics().maxWidth()*20);
QToolTip::add(m_name, i18n("Name"));
nameLayout->addWidget(m_icon);
nameLayout->addWidget(m_name);
topLayout->addLayout(nameLayout);
// Appearance:
QGroupBox *appearance = new QGroupBox(1, Qt::Horizontal, i18n("Appearance"), page);
QWidget *appearanceWidget = new QWidget(appearance);
QGridLayout *grid = new QGridLayout(appearanceWidget, /*nRows=*/3, /*nCols=*/2, /*margin=*/0, spacingHint());
m_backgroundImage = new QComboBox(appearanceWidget);
m_backgroundColor = new KColorCombo2(m_basket->backgroundColorSetting(), KGlobalSettings::baseColor(), appearanceWidget);
m_textColor = new KColorCombo2(m_basket->textColorSetting(), KGlobalSettings::textColor(), appearanceWidget);
QLabel *label1 = new QLabel(m_backgroundImage, i18n("Background &image:"), appearanceWidget);
QLabel *label2 = new QLabel(m_backgroundColor, i18n("&Background color:"), appearanceWidget);
QLabel *label3 = new QLabel(m_textColor, i18n("&Text color:"), appearanceWidget);
grid->addWidget(label1, 0, 0, Qt::AlignVCenter);
grid->addWidget(label2, 1, 0, Qt::AlignVCenter);
grid->addWidget(label3, 2, 0, Qt::AlignVCenter);
grid->addWidget(m_backgroundImage, 0, 1, Qt::AlignVCenter);
grid->addWidget(m_backgroundColor, 1, 1, Qt::AlignVCenter);
grid->addWidget(m_textColor, 2, 1, Qt::AlignVCenter);
topLayout->addWidget(appearance);
m_backgroundImage->insertItem(i18n("(None)"), 0);
m_backgroundImagesMap.insert(0, "");
QStringList backgrounds = Global::backgroundManager->imageNames();
int index = 1;
for (QStringList::Iterator it = backgrounds.begin(); it != backgrounds.end(); ++it) {
QPixmap *preview = Global::backgroundManager->preview(*it);
if (preview) {
m_backgroundImagesMap.insert(index, *it);
m_backgroundImage->insertItem(*preview, index);
if (m_basket->backgroundImageName() == *it)
m_backgroundImage->setCurrentItem(index);
index++;
}
}
// m_backgroundImage->insertItem(i18n("Other..."), -1);
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
m_backgroundImage->setSizeLimit(50/*75 * 6 / m_backgroundImage->sizeHint().height()*/);
m_backgroundImage->setMinimumHeight(75 + 2 * BUTTON_MARGIN);
// Disposition:
m_disposition = new QVButtonGroup(i18n("Disposition"), page);
QWidget *columnsWidget = new QWidget(m_disposition);
QHBoxLayout *dispoLayout = new QHBoxLayout(columnsWidget, /*margin=*/0, spacingHint());
QRadioButton *radio = new QRadioButton(i18n("Col&umns:"), columnsWidget);
m_columnCount = new KIntNumInput(m_basket->columnsCount(), columnsWidget);
m_columnCount->setRange(1, 20, /*step=*/1, /*slider=*/false);
m_columnCount->setValue(m_basket->columnsCount());
connect( m_columnCount, SIGNAL(valueChanged(int)), this, SLOT(selectColumnsLayout()) );
dispoLayout->addWidget(radio);
dispoLayout->addWidget(m_columnCount);
m_disposition->insert(radio);
new QRadioButton(i18n("&Free-form"), m_disposition);
QRadioButton *mindMap = new QRadioButton(i18n("&Mind map"), m_disposition); // TODO: "Learn more..."
int height = QMAX(mindMap->sizeHint().height(), m_columnCount->sizeHint().height()); // Make all radioButtons vertically equaly-spaced!
mindMap->setMinimumSize(mindMap->sizeHint().width(), height); // Because the m_columnCount can be heigher, and make radio1 and radio2 more spaced than radio2 and radio3.
m_disposition->setButton(m_basket->isFreeLayout() ? (m_basket->isMindMap() ? 2 : 1) : 0);
topLayout->addWidget(m_disposition);
mindMap->hide();
// Keyboard Shortcut:
m_shortcutRole = new QVButtonGroup(i18n("&Keyboard Shortcut"), page);
QWidget *shortcutWidget = new QWidget(m_shortcutRole);
QHBoxLayout *shortcutLayout = new QHBoxLayout(shortcutWidget, /*margin=*/0, spacingHint());
m_shortcut = new KKeyButton(shortcutWidget);
m_shortcut->setShortcut(m_basket->shortcut(), /*bQtShortcut=*/true);
HelpLabel *helpLabel = new HelpLabel(i18n("Learn some tips..."), i18n(
"<p><strong>Easily Remember your Shortcuts</strong>:<br>"
"With the first option, giving the basket a shortcut of the form <strong>Alt+Letter</strong> will underline that letter in the basket tree.<br>"
"For instance, if you are assigning the shortcut <i>Alt+T</i> to a basket named <i>Tips</i>, the basket will be displayed as <i><u>T</u>ips</i> in the tree. "
"It helps you visualize the shortcuts to remember them more quickly.</p>"
"<p><strong>Local vs Global</strong>:<br>"
"The first option allows to show the basket while the main window is active. "
"Global shortcuts are valid from anywhere, even if the window is hidden.</p>"
"<p><strong>Show vs Switch</strong>:<br>"
"The last option makes this basket the current one without opening the main window. "
"It is useful in addition to the configurable global shortcuts, eg. to paste the clipboard or the selection into the current basket from anywhere.</p>"),
shortcutWidget);
shortcutLayout->addWidget(m_shortcut);
shortcutLayout->addStretch();
shortcutLayout->addWidget(helpLabel);
connect( m_shortcut, SIGNAL(capturedShortcut(const KShortcut&)), this, SLOT(capturedShortcut(const KShortcut&)) );
new QRadioButton(i18n("S&how this basket"), m_shortcutRole);
new QRadioButton(i18n("Show this basket (&global shortcut)"), m_shortcutRole);
new QRadioButton(i18n("S&witch to this basket (global shortcut)"), m_shortcutRole);
m_shortcutRole->setButton(m_basket->shortcutAction()/* + 1*/); // Id 0 is the KKeyButton!
topLayout->addWidget(m_shortcutRole);
topLayout->addSpacing(marginHint());
topLayout->addStretch(10);
setMainWidget(page);
}
BasketPropertiesDialog::~BasketPropertiesDialog()
{
}
void BasketPropertiesDialog::polish()
{
KDialogBase::polish();
m_name->setFocus();
}
void BasketPropertiesDialog::applyChanges()
{
m_basket->setDisposition(m_disposition->selectedId(), m_columnCount->value());
m_basket->setShortcut(m_shortcut->shortcut(), m_shortcutRole->selectedId());
// Should be called LAST, because it will emit the propertiesChanged() signal and the tree will be able to show the newly set Alt+Letter shortcut:
m_basket->setAppearance(m_icon->icon(), m_name->text(), m_backgroundImagesMap[m_backgroundImage->currentItem()], m_backgroundColor->color(), m_textColor->color());
m_basket->save();
}
void BasketPropertiesDialog::slotApply()
{
applyChanges();
KDialogBase::slotApply();
}
void BasketPropertiesDialog::slotOk()
{
applyChanges();
KDialogBase::slotOk();
}
void BasketPropertiesDialog::capturedShortcut(const KShortcut &shortcut)
{
// TODO: Validate it!
m_shortcut->setShortcut(shortcut, /*bQtShortcut=*/true);
}
void BasketPropertiesDialog::selectColumnsLayout()
{
m_disposition->setButton(0);
}
#include "basketproperties.moc"

@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKETPROPERTIES_H
#define BASKETPROPERTIES_H
#include <kdialogbase.h>
#include <qmap.h>
#include <qstring.h>
class KIconButton;
class QLineEdit;
class QComboBox;
class QVButtonGroup;
class KIntNumInput;
class KKeyButton;
class KShortcut;
class Basket;
class KColorCombo2;
/** The dialog that hold basket settings.
* @author Sébastien Laoût
*/
class BasketPropertiesDialog : public KDialogBase
{
Q_OBJECT
public:
BasketPropertiesDialog(Basket *basket, QWidget *parent = 0);
~BasketPropertiesDialog();
void polish();
void applyChanges();
protected slots:
void slotApply();
void slotOk();
void capturedShortcut(const KShortcut &shortcut);
void selectColumnsLayout();
private:
Basket *m_basket;
KIconButton *m_icon;
QLineEdit *m_name;
QComboBox *m_backgroundImage;
KColorCombo2 *m_backgroundColor;
KColorCombo2 *m_textColor;
QVButtonGroup *m_disposition;
KIntNumInput *m_columnCount;
KKeyButton *m_shortcut;
QVButtonGroup *m_shortcutRole;
QMap<int, QString> m_backgroundImagesMap;
};
#endif // BASKETPROPERTIES_H

@ -0,0 +1,176 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kparts/statusbarextension.h>
#include <kstatusbar.h>
#include <klocale.h>
#include <kdebug.h>
#include <qlabel.h>
#include <qobjectlist.h>
#include "basketstatusbar.h"
#include "clickablelabel.h"
#include "global.h"
#include "bnpview.h"
#include "basket.h"
#include "tools.h"
#include <kiconloader.h>
#include <qtooltip.h>
BasketStatusBar::BasketStatusBar(KStatusBar *bar)
: m_bar(bar), m_extension(0), m_selectionStatus(0), m_lockStatus(0), m_basketStatus(0), m_savedStatus(0)
{
}
BasketStatusBar::BasketStatusBar(KParts::StatusBarExtension *extension)
: m_bar(0), m_extension(extension), m_selectionStatus(0), m_lockStatus(0), m_basketStatus(0), m_savedStatus(0)
{
}
BasketStatusBar::~BasketStatusBar()
{
//delete m_extension;
}
KStatusBar *BasketStatusBar::statusBar () const
{
if(m_extension)
return m_extension->statusBar();
else
return m_bar;
}
void BasketStatusBar::addWidget(QWidget * widget, int stretch, bool permanent)
{
if(m_extension)
m_extension->addStatusBarItem(widget, stretch, permanent);
else
m_bar->addWidget(widget, stretch, permanent);
}
void BasketStatusBar::setupStatusBar()
{
QWidget* parent = statusBar();
QObjectList* lst = parent->queryList("KRSqueezedTextLabel");
//Tools::printChildren(parent);
if(lst->count() == 0)
{
m_basketStatus = new QLabel(parent);
m_basketStatus->setSizePolicy( QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored, 0, 0, false) );
addWidget( m_basketStatus, 1, false ); // Fit all extra space and is hiddable
}
else
m_basketStatus = static_cast<QLabel*>(lst->at(0));
delete lst;
m_selectionStatus = new QLabel(i18n("Loading..."), parent);
addWidget( m_selectionStatus, 0, true );
m_lockStatus = new ClickableLabel(0/*this*/);
m_lockStatus->setMinimumSize(18, 18);
m_lockStatus->setAlignment(Qt::AlignCenter);
// addWidget( m_lockStatus, 0, true );
connect( m_lockStatus, SIGNAL(clicked()), Global::bnpView, SLOT(lockBasket()) );
m_savedStatusPixmap = SmallIcon("filesave");
m_savedStatus = new QLabel(parent);
m_savedStatus->setPixmap(m_savedStatusPixmap);
m_savedStatus->setFixedSize(m_savedStatus->sizeHint());
m_savedStatus->clear();
//m_savedStatus->setPixmap(m_savedStatusIconSet.pixmap(QIconSet::Small, QIconSet::Disabled));
//m_savedStatus->setEnabled(false);
addWidget( m_savedStatus, 0, true );
QToolTip::add(m_savedStatus, "<p>" + i18n("Shows if there are changes that have not yet been saved."));
}
void BasketStatusBar::postStatusbarMessage(const QString& text)
{
if(statusBar())
statusBar()->message(text, 2000);
}
void BasketStatusBar::setStatusText(const QString &txt)
{
if(m_basketStatus && m_basketStatus->text() != txt)
m_basketStatus->setText(txt);
}
void BasketStatusBar::setStatusBarHint(const QString &hint)
{
if (hint.isEmpty())
updateStatusBarHint();
else
setStatusText(hint);
}
void BasketStatusBar::updateStatusBarHint()
{
QString message = "";
if (Global::bnpView->currentBasket()->isDuringDrag())
message = i18n("Ctrl+drop: copy, Shift+drop: move, Shift+Ctrl+drop: link.");
// Too much noise information:
// else if (currentBasket()->inserterShown() && currentBasket()->inserterSplit() && !currentBasket()->inserterGroup())
// message = i18n("Click to insert a note, right click for more options. Click on the right of the line to group instead of insert.");
// else if (currentBasket()->inserterShown() && currentBasket()->inserterSplit() && currentBasket()->inserterGroup())
// message = i18n("Click to group a note, right click for more options. Click on the left of the line to group instead of insert.");
else if (Global::debugWindow)
message = "DEBUG: " + Global::bnpView->currentBasket()->folderName();
setStatusText(message);
}
void BasketStatusBar::setLockStatus(bool isLocked)
{
if(!m_lockStatus)
return;
if (isLocked) {
m_lockStatus->setPixmap(SmallIcon("encrypted.png"));
QToolTip::add(m_lockStatus, i18n(
"<p>This basket is <b>locked</b>.<br>Click to unlock it.</p>").replace(" ", "&nbsp;") );
// QToolTip::add(m_lockStatus, i18n("This basket is locked.\nClick to unlock it."));
} else {
m_lockStatus->clear();
QToolTip::add(m_lockStatus, i18n(
"<p>This basket is <b>unlocked</b>.<br>Click to lock it.</p>").replace(" ", "&nbsp;") );
// QToolTip::add(m_lockStatus, i18n("This basket is unlocked.\nClick to lock it."));
}
}
void BasketStatusBar::setSelectionStatus(const QString &s)
{
if (m_selectionStatus)
m_selectionStatus->setText(s);
}
void BasketStatusBar::setUnsavedStatus(bool isUnsaved)
{
if (!m_savedStatus)
return;
if (isUnsaved) {
if (m_savedStatus->pixmap() == 0)
m_savedStatus->setPixmap(m_savedStatusPixmap);
} else
m_savedStatus->clear();
}
#include "basketstatusbar.moc"

@ -0,0 +1,68 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BASKETSTATUSBAR_H
#define BASKETSTATUSBAR_H
#include <qobject.h>
#include <qpixmap.h>
class KStatusBar;
namespace KParts { class StatusBarExtension; }
class QWidget;
class QLabel;
class ClickableLabel;
/**
@author Sébastien Laoût <slaout@linux62.org>
*/
class BasketStatusBar : public QObject
{
Q_OBJECT
public:
BasketStatusBar(KStatusBar *bar);
BasketStatusBar(KParts::StatusBarExtension *extension);
~BasketStatusBar();
public slots:
/** GUI Main Window actions **/
void setStatusBarHint(const QString &hint); /// << Set a specific message or update if hint is empty
void updateStatusBarHint(); /// << Display the current state message (dragging, editing) or reset the startsbar message
void postStatusbarMessage(const QString &text);
void setSelectionStatus(const QString &s);
void setLockStatus(bool isLocked);
void setupStatusBar();
void setUnsavedStatus(bool isUnsaved);
protected:
KStatusBar *statusBar () const;
void addWidget(QWidget * widget, int stretch = 0, bool permanent = false);
void setStatusText(const QString &txt);
private:
KStatusBar *m_bar;
KParts::StatusBarExtension *m_extension;
QLabel *m_selectionStatus;
ClickableLabel *m_lockStatus;
QLabel *m_basketStatus;
QLabel *m_savedStatus;
QPixmap m_savedStatusPixmap;
};
#endif

@ -0,0 +1,233 @@
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui version="1.0.3.1" name="basket" >
<MenuBar noMerge="1" >
<Menu name="basket" >
<text>&amp;Basket</text>
<Action name="basket_new_menu" />
<Separator/>
<Action name="basket_properties" />
<Menu icon="fileexport" >
<text>&amp;Export</text>
<Action name="basket_export_basket_archive" />
<Action name="basket_export_html" />
</Menu>
<Action name="basket_remove" />
<Separator/>
<Action name="basket_password" />
<Action name="basket_lock" />
<Separator/>
<Menu name="fileimport" icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
<Separator/>
<Action name="window_hide" />
<Action name="file_quit" />
</Menu>
<Menu name="edit" >
<text>&amp;Edit</text>
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_paste" />
<Action name="edit_delete" />
<Separator/>
<Action name="edit_select_all" />
<Action name="edit_unselect_all" />
<Action name="edit_invert_selection" />
<Separator/>
<Action name="edit_filter" />
<Action name="edit_filter_all_baskets" />
<Action name="edit_filter_reset" />
</Menu>
<Menu name="go" >
<text>&amp;Go</text>
<Action name="go_basket_previous" />
<Action name="go_basket_next" />
<Action name="go_basket_fold" />
<Action name="go_basket_expand" />
</Menu>
<Menu name="note" >
<text>&amp;Note</text>
<Action name="note_edit" />
<Action name="note_open" />
<Action name="note_open_with" />
<Action name="note_save_to_file" />
<Separator/>
<Action name="note_group" />
<Action name="note_ungroup" />
<Separator/>
<Action name="note_move_top" />
<Action name="note_move_up" />
<Action name="note_move_down" />
<Action name="note_move_bottom" />
</Menu>
<Menu name="tags" >
<text>&amp;Tags</text>
</Menu>
<Menu name="insert" >
<text>&amp;Insert</text>
<Action name="insert_html" />
<Action name="insert_image" />
<Action name="insert_link" />
<Action name="insert_launcher" />
<Action name="insert_color" />
<Separator/>
<Action name="insert_screen_capture" />
<Action name="insert_screen_color" />
<Separator/>
<Action name="insert_from_file" />
<Action name="insert_kmenu" />
<Action name="insert_icon" />
</Menu>
<Menu name="settings" >
<text>&amp;Settings</text>
<Merge name="StandardToolBarMenuHandler" />
<Action name="options_show_statusbar" />
<Separator/>
<Action name="options_configure_keybinding" />
<Action name="options_configure_global_keybinding" />
<Action name="options_configure_toolbars" />
<Action name="options_configure_notifications" />
<Action name="options_configure" />
</Menu>
<Menu name="help" >
<text>&amp;Help</text>
<Action name="help_contents" />
<Action name="help_plugins_contents" />
<Action name="help_whats_this" />
<Action name="help_show_tip" />
<Separator/>
<Action name="help_welcome_baskets" />
<!-- <Action name="help_report_bug" />-->
<Action name="likeback_send_a_comment" />
<Separator/>
<Action name="help_about_app" />
<Action name="help_about_kde" />
</Menu>
</MenuBar>
<ToolBar newline="false" position="Top" noMerge="1" name="mainToolBar" fullWidth="true" >
<text>Main Toolbar</text>
<Action name="basket_new_menu" />
<Action name="basket_properties" />
<Separator lineSeparator="true" name="separator_0" />
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_paste" />
<Action name="edit_delete" />
<Separator lineSeparator="true" name="separator_1" />
<Action name="note_group" />
</ToolBar>
<ToolBar newline="false" position="Top" noMerge="1" name="richTextEditToolBar" fullWidth="true" >
<text>Text Formating Toolbar</text>
<Action name="richtext_undo" />
<Action name="richtext_redo" />
<Separator lineSeparator="true" name="separator_1" />
<Action name="richtext_font" />
<Separator lineSeparator="false" name="separator_2" />
<Action name="richtext_font_size" />
<Separator lineSeparator="false" name="separator_3" />
<Action name="richtext_color" />
<Separator lineSeparator="true" name="separator_4" />
<Action name="richtext_bold" />
<Action name="richtext_italic" />
<Action name="richtext_underline" />
<!--
<Separator lineSeparator="true" name="separator_2" />
<Action name="richtext_super" />
<Action name="richtext_sub" />
-->
<Separator lineSeparator="true" name="separator_0" />
<Action name="richtext_left" />
<Action name="richtext_center" />
<Action name="richtext_right" />
<Action name="richtext_block" />
</ToolBar>
<Menu name="basket_popup" >
<Action name="basket_new_menu" />
<Separator/>
<Action name="basket_properties" />
<Menu icon="fileexport" >
<text>&amp;Export</text>
<Action name="basket_export_basket_archive" />
<Action name="basket_export_html" />
</Menu>
<Action name="basket_remove" />
<Separator/>
<Action name="basket_password" />
<Action name="basket_lock" />
<Separator/>
<Menu icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
</Menu>
<Menu name="tab_bar_popup" >
<Action name="basket_new" />
<Menu icon="fileimport" >
<text>&amp;Import</text>
<Action name="basket_import_basket_archive" />
<Separator/>
<Action name="basket_import_knotes" />
<Action name="basket_import_kjots" />
<Action name="basket_import_knowit" />
<Action name="basket_import_tuxcards" />
<Separator/>
<Action name="basket_import_sticky_notes" />
<Action name="basket_import_tomboy" />
<Separator/>
<Action name="basket_import_text_file" />
</Menu>
<Action name="basket_backup_restore" />
</Menu>
<Menu noMerge="1" name="note_popup" >
<Action name="note_edit" />
<Action name="note_open" />
<Action name="note_open_with" />
<Action name="note_save_to_file" />
<Separator/>
<Action name="note_group" />
<Action name="note_ungroup" />
<Separator/>
<Action name="edit_cut" />
<Action name="edit_copy" />
<Action name="edit_delete" />
</Menu>
<Menu noMerge="1" name="insert_popup" >
<Action name="insert_html" />
<Action name="insert_image" />
<Action name="insert_link" />
<Action name="insert_launcher" />
<Action name="insert_color" />
<Separator/>
<Action name="insert_screen_capture" />
<Action name="insert_screen_color" />
<Separator/>
<Action name="insert_from_file" />
<Action name="insert_kmenu" />
<Action name="insert_icon" />
<Separator/>
<Action name="edit_paste" />
</Menu>
</kpartgui>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,354 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef BNPVIEW_H
#define BNPVIEW_H
#include <klistview.h>
#include <kxmlguiclient.h>
#include <qtimer.h>
#include <qclipboard.h>
#include <qsplitter.h>
#include <qlistview.h>
#include <dcopref.h>
#include "global.h"
#include "basketdcopiface.h"
/// NEW:
class QWidgetStack;
class QDomDocument;
class QDomElement;
class KToggleAction;
class KPassivePopup;
class QPopupMenu;
class KPopupMenu;
class KTar;
class DesktopColorPicker;
class RegionGrabber;
class Basket;
class DecoratedBasket;
class BasketListViewItem;
class NoteSelection;
class BasketStatusBar;
class Tag;
class State;
class Note;
class BNPView : public QSplitter, virtual public BasketDcopInterface
{
Q_OBJECT
public:
/// CONSTRUCTOR AND DESTRUCTOR:
BNPView(QWidget *parent, const char *name, KXMLGUIClient *aGUIClient,
KActionCollection *actionCollection, BasketStatusBar *bar);
~BNPView();
/// MANAGE CONFIGURATION EVENTS!:
void setTreePlacement(bool onLeft);
void relayoutAllBaskets();
void recomputeAllStyles();
void removedStates(const QValueList<State*> &deletedStates);
void linkLookChanged();
void filterPlacementChanged(bool onTop);
/// MANAGE BASKETS:
BasketListViewItem* listViewItemForBasket(Basket *basket);
Basket* currentBasket();
Basket* parentBasketOf(Basket *basket);
void setCurrentBasket(Basket *basket);
void removeBasket(Basket *basket);
/// For NewBasketDialog (and later some other classes):
QListViewItem* firstListViewItem();
///
BasketListViewItem* lastListViewItem();
int basketCount(QListViewItem *parent = 0);
bool canFold();
bool canExpand();
void enableActions();
private:
QDomElement basketElement(QListViewItem *item, QDomDocument &document, QDomElement &parentElement);
public slots:
void countsChanged(Basket *basket);
void notesStateChanged();
bool convertTexts();
void updateBasketListViewItem(Basket *basket);
void save();
void save(QListViewItem *firstItem, QDomDocument &document, QDomElement &parentElement);
void saveSubHierarchy(QListViewItem *item, QDomDocument &document, QDomElement &parentElement, bool recursive);
void load();
void load(KListView *listView, QListViewItem *item, const QDomElement &baskets);
void loadNewBasket(const QString &folderName, const QDomElement &properties, Basket *parent);
void goToPreviousBasket();
void goToNextBasket();
void foldBasket();
void expandBasket();
void closeAllEditors();
///
void toggleFilterAllBaskets(bool doFilter);
void newFilter();
void newFilterFromFilterBar();
bool isFilteringAllBaskets();
// From main window
void importKNotes();
void importKJots();
void importKnowIt();
void importTuxCards();
void importStickyNotes();
void importTomboy();
void importTextFile();
void backupRestore();
/** Note */
void activatedTagShortcut();
void exportToHTML();
void editNote();
void cutNote();
void copyNote();
void delNote();
void openNote();
void openNoteWith();
void saveNoteAs();
void noteGroup();
void noteUngroup();
void moveOnTop();
void moveOnBottom();
void moveNoteUp();
void moveNoteDown();
void slotSelectAll();
void slotUnselectAll();
void slotInvertSelection();
void slotResetFilter();
void slotColorFromScreen(bool global = false);
void slotColorFromScreenGlobal();
void colorPicked(const QColor &color);
void colorPickingCanceled();
void slotConvertTexts();
/** Global shortcuts */
void addNoteText();
void addNoteHtml();
void addNoteImage();
void addNoteLink();
void addNoteColor();
/** Passive Popups for Global Actions */
void showPassiveDropped(const QString &title);
void showPassiveDroppedDelayed(); // Do showPassiveDropped(), but delayed
void showPassiveContent(bool forceShow = false);
void showPassiveContentForced();
void showPassiveImpossible(const QString &message);
void showPassiveLoading(Basket *basket);
// For GUI :
void setFiltering(bool filtering);
/** Edit */
void undo();
void redo();
void globalPasteInCurrentBasket();
void pasteInCurrentBasket();
void pasteSelInCurrentBasket();
void pasteToBasket(int index, QClipboard::Mode mode = QClipboard::Clipboard);
void showHideFilterBar(bool show, bool switchFocus = true);
/** Insert **/
void insertEmpty(int type);
void insertWizard(int type);
void grabScreenshot(bool global = false);
void grabScreenshotGlobal();
void screenshotGrabbed(const QPixmap &pixmap);
/** Basket */
void askNewBasket();
void askNewBasket(Basket *parent, Basket *pickProperties);
void askNewSubBasket();
void askNewSiblingBasket();
void aboutToHideNewBasketPopup();
void setNewBasketPopup();
void cancelNewBasketPopup();
void propBasket();
void delBasket();
void doBasketDeletion(Basket *basket);
void password();
void saveAsArchive();
void openArchive();
void delayedOpenArchive();
void lockBasket();
void hideOnEscape();
void changedSelectedNotes();
void timeoutTryHide();
void timeoutHide();
public:
static QString s_fileToOpen;
public slots:
void addWelcomeBaskets();
private slots:
void updateNotesActions();
void slotBasketNumberChanged(int number);
void slotBasketChanged();
void currentBasketChanged();
void isLockedChanged();
void lateInit();
void onFirstShow();
void showGlobalShortcutsSettingsDialog();
public:
KAction *m_actEditNote;
KAction *m_actOpenNote;
KAction *m_actPaste;
KAction *m_actGrabScreenshot;
KAction *m_actColorPicker;
KAction *m_actLockBasket;
KAction *m_actPassBasket;
KAction *actNewBasket;
KAction *actNewSubBasket;
KAction *actNewSiblingBasket;
KAction *m_actHideWindow;
KAction *m_actExportToHtml;
KAction *m_actPropBasket;
KAction *m_actDelBasket;
KToggleAction *m_actFilterAllBaskets;
private:
// Basket actions:
KAction *m_actSaveAsArchive;
KAction *m_actOpenArchive;
// Notes actions :
KAction *m_actOpenNoteWith;
KAction *m_actSaveNoteAs;
KAction *m_actGroup;
KAction *m_actUngroup;
KAction *m_actMoveOnTop;
KAction *m_actMoveNoteUp;
KAction *m_actMoveNoteDown;
KAction *m_actMoveOnBottom;
// Edit actions :
KAction *m_actUndo;
KAction *m_actRedo;
KAction *m_actCutNote;
KAction *m_actCopyNote;
KAction *m_actDelNote;
KAction *m_actSelectAll;
KAction *m_actUnselectAll;
KAction *m_actInvertSelection;
// Insert actions :
// KAction *m_actInsertText;
KAction *m_actInsertHtml;
KAction *m_actInsertLink;
KAction *m_actInsertImage;
KAction *m_actInsertColor;
KAction *m_actImportKMenu;
KAction *m_actInsertLauncher;
KAction *m_actImportIcon;
KAction *m_actLoadFile;
QPtrList<KAction> m_insertActions;
// Basket actions :
KToggleAction *m_actShowFilter;
KAction *m_actResetFilter;
// Go actions :
KAction *m_actPreviousBasket;
KAction *m_actNextBasket;
KAction *m_actFoldBasket;
KAction *m_actExpandBasket;
// KAction *m_convertTexts; // FOR_BETA_PURPOSE
KAction *actConfigGlobalShortcuts;
void setupActions();
void setupGlobalShortcuts();
DecoratedBasket* currentDecoratedBasket();
public:
Basket* loadBasket(const QString &folderName); // Public only for class Archive
BasketListViewItem* appendBasket(Basket *basket, QListViewItem *parentItem); // Public only for class Archive
Basket* basketForFolderName(const QString &folderName);
QPopupMenu* popupMenu(const QString &menuName);
bool isPart();
bool isMainWindowActive();
void showMainWindow();
// dcop calls
virtual void newBasket();
virtual void handleCommandLine();
public slots:
void setCaption(QString s);
void updateStatusBarHint();
void setSelectionStatus(QString s);
void setLockStatus(bool isLocked);
void postStatusbarMessage(const QString&);
void setStatusBarHint(const QString&);
void setUnsavedStatus(bool isUnsaved);
void setActive(bool active = true);
KActionCollection *actionCollection() { return m_actionCollection; };
void populateTagsMenu();
void populateTagsMenu(KPopupMenu &menu, Note *referenceNote);
void connectTagsMenu();
void disconnectTagsMenu();
void disconnectTagsMenuDelayed();
protected:
void showEvent(QShowEvent*);
void hideEvent(QHideEvent*);
private:
KPopupMenu *m_lastOpenedTagsMenu;
private slots:
void slotPressed(QListViewItem *item, const QPoint &/*pos*/ = QPoint(), int /*column*/ = 0);
void needSave(QListViewItem*);
void slotContextMenu(KListView *listView, QListViewItem *item, const QPoint &pos);
void slotMouseButtonPressed(int button, QListViewItem *item, const QPoint &pos, int column);
void slotShowProperties(QListViewItem *item, const QPoint&, int);
void initialize();
signals:
void basketNumberChanged(int number);
void basketChanged();
void setWindowCaption(const QString &s);
void showPart();
protected:
void enterEvent(QEvent*);
void leaveEvent(QEvent*);
private:
KListView *m_tree;
QWidgetStack *m_stack;
bool m_loading;
bool m_newBasketPopup;
bool m_firstShow;
DesktopColorPicker *m_colorPicker;
bool m_colorPickWasShown;
bool m_colorPickWasGlobal;
RegionGrabber *m_regionGrabber;
QString m_passiveDroppedTitle;
NoteSelection *m_passiveDroppedSelection;
KPassivePopup *m_passivePopup;
static const int c_delayTooltipTime;
KActionCollection *m_actionCollection;
KXMLGUIClient *m_guiClient;
BasketStatusBar *m_statusbar;
QTimer *m_tryHideTimer;
QTimer *m_hideTimer;
};
#endif // BNPVIEW_H

@ -0,0 +1,29 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "clickablelabel.h"
void ClickableLabel::mousePressEvent(QMouseEvent *event)
{
if (event->button() & Qt::LeftButton)
emit clicked();
}
#include "clickablelabel.moc"

@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef CLICKABLELABEL_H
#define CLICKABLELABEL_H
#include <qlabel.h>
/** This class is a QLabel that can emit a clicked() signal when clicked !
* @author S<EFBFBD>astien Laot
*/
class ClickableLabel : public QLabel
{
Q_OBJECT
public:
/** Construtor, initializer and destructor */
ClickableLabel(QWidget *parent = 0, const char *name = 0)
: QLabel(parent, name) {}
~ClickableLabel() {}
signals:
void clicked();
protected:
virtual void mousePressEvent(QMouseEvent *event);
};
#endif // CLICKABLELABEL_H

@ -0,0 +1,96 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "colorpicker.h"
#include "qtimer.h"
#include <kcolordialog.h>
/// ///
/** DektopColorPicker */
/* From Qt documentation:
* " Note that only visible widgets can grab mouse input.
* If isVisible() returns FALSE for a widget, that widget cannot call grabMouse(). "
* So, we should use an always visible widget to be able to pick a color from screen,
* even by first hidding the main window (user seldomly want to grab a color from BasKet!)
* or use a global shortcut (main window can be hidden when hitting that shortcut).
*/
DesktopColorPicker::DesktopColorPicker()
: QDesktopWidget()
{
setName("DesktopColorPicker");
m_gettingColorFromScreen = false;
}
DesktopColorPicker::~DesktopColorPicker()
{
}
void DesktopColorPicker::pickColor()
{
m_gettingColorFromScreen = true;
// Global::mainContainer->setActive(false);
QTimer::singleShot( 50, this, SLOT(slotDelayedPick()) );
}
/* When firered from basket context menu, and not from menu, grabMouse doesn't work!
* It's perhapse because context menu call slotColorFromScreen() and then
* ungrab the mouse (since menus grab the mouse).
* But why isn't there such bug with normal menus?...
* By calling this method with a QTimer::singleShot, we are sure context menu code is
* finished and we can grab the mouse without loosing the grab:
*/
void DesktopColorPicker::slotDelayedPick()
{
grabKeyboard();
grabMouse(crossCursor);
}
/* Validate the color
*/
void DesktopColorPicker::mouseReleaseEvent(QMouseEvent *event)
{
if (m_gettingColorFromScreen) {
m_gettingColorFromScreen = false;
releaseMouse();
releaseKeyboard();
QColor color = KColorDialog::grabColor(event->globalPos());
emit pickedColor(color);
} else
QDesktopWidget::mouseReleaseEvent(event);
}
/* Cancel the mode
*/
void DesktopColorPicker::keyPressEvent(QKeyEvent *event)
{
if (m_gettingColorFromScreen)
if (event->key() == Qt::Key_Escape) {
m_gettingColorFromScreen = false;
releaseMouse();
releaseKeyboard();
emit canceledPick();
}
QDesktopWidget::keyPressEvent(event);
}
#include "colorpicker.moc"

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef COLORPICKER_H
#define COLORPICKER_H
#include <qdesktopwidget.h>
/** Class to pick a color on the screen
* @author S<EFBFBD>astien Laot
*/
class DesktopColorPicker : public QDesktopWidget
{
Q_OBJECT
public:
/** Construtor, initializer and destructor */
DesktopColorPicker();
~DesktopColorPicker();
public slots:
/** Begin color picking.
* This function returns immediatly, and pickedColor() is emitted if user has
* choosen a color, and not canceled the process (by pressing Escape).
*/
void pickColor();
signals:
/** When user picked a color, this signal is emitted.
*/
void pickedColor(const QColor &color);
/** When user cancel a picking (by pressing Escape), this signal is emitted.
*/
void canceledPick();
protected slots:
void slotDelayedPick();
protected:
void mouseReleaseEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
bool m_gettingColorFromScreen;
};
#endif // COLORPICKER_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@ -0,0 +1,226 @@
// Code from Amarok.
/***************************************************************************
* Copyright (C) 2005 Max Howell <max.howell@methylblue.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
//#include "amarok.h"
//#include "amarokconfig.h"
#include "crashhandler.h"
//#include "debug.h"
#include "config.h"
#include <kapplication.h> //invokeMailer()
#include <kaboutdata.h>
#include <kdeversion.h>
#include <klocale.h>
#include <ktempfile.h>
#include <qfile.h>
#include <qregexp.h>
#include <qtextstream.h>
#include <cstdio> //popen, fread
#include <iostream>
#include <sys/types.h> //pid_t
#include <sys/wait.h> //waitpid
//#include <taglib/taglib.h>
#include <unistd.h> //write, getpid
//#ifndef TAGLIB_PATCH_VERSION
//// seems to be wheel's style
//#define TAGLIB_PATCH_VERSION 0
//#endif
#if 0
class CrashHandlerWidget : public KDialog {
public:
CrashHandlerWidget();
};
#endif
static QString
runCommand( const QCString &command )
{
static const uint SIZE = 40960; //40 KiB
static char stdoutBuf[ SIZE ];
// debug() << "Running: " << command << endl;
FILE *process = ::popen( command, "r" );
stdoutBuf[ std::fread( static_cast<void*>( stdoutBuf ), sizeof(char), SIZE-1, process ) ] = '\0';
::pclose( process );
return QString::fromLocal8Bit( stdoutBuf );
}
void
Crash::crashHandler( int /*signal*/ )
{
// we need to fork to be able to get a
// semi-decent bt - I dunno why
const pid_t pid = ::fork();
if( pid <= 0 )
{
// we are the child process (the result of the fork)
// debug() << "amaroK is crashing...\n";
QString subject = "[basket-crash] " VERSION " ";
QString body = i18n(
"%1 has crashed! We're sorry about this.\n"
"\n"
"But, all is not lost! You could potentially help us fix the crash. "
"Information describing the crash is below, so just click send, "
"or if you have time, write a brief description of how the crash happened first.\n\n"
"Many thanks." ).arg(kapp->aboutData()->programName()) + "\n\n";
body += "\n\n\n\n\n\n" + i18n(
"The information below is to help the developers identify the problem, "
"please do not modify it." ) + "\n\n\n\n";
body += "======== DEBUG INFORMATION =======\n"
"Version: " VERSION "\n"
"Build date: " __DATE__ "\n"
"CC version: " __VERSION__ "\n" //assuming we're using GCC
"KDElibs: " KDE_VERSION_STRING "\n"
;// "TagLib: %2.%3.%4\n";
/* body = body
.arg( TAGLIB_MAJOR_VERSION )
.arg( TAGLIB_MINOR_VERSION )
.arg( TAGLIB_PATCH_VERSION );*/
#ifdef NDEBUG
body += "NDEBUG: true";
#endif
body += "\n";
/// obtain the backtrace with gdb
KTempFile temp;
temp.setAutoDelete( true );
const int handle = temp.handle();
// QCString gdb_command_string =
// "file amarokapp\n"
// "attach " + QCString().setNum( ::getppid() ) + "\n"
// "bt\n" "echo \\n\n"
// "thread apply all bt\n";
const QCString gdb_batch =
"bt\n"
"echo \\n\\n\n"
"bt full\n"
"echo \\n\\n\n"
"echo ==== (gdb) thread apply all bt ====\\n\n"
"thread apply all bt\n";
::write( handle, gdb_batch, gdb_batch.length() );
::fsync( handle );
// so we can read stderr too
::dup2( fileno( stdout ), fileno( stderr ) );
QCString gdb;
gdb = "gdb --nw -n --batch -x ";
gdb += temp.name().latin1();
gdb += " basket ";
gdb += QCString().setNum( ::getppid() );
QString bt = runCommand( gdb );
/// clean up
bt.remove( "(no debugging symbols found)..." );
bt.remove( "(no debugging symbols found)\n" );
bt.replace( QRegExp("\n{2,}"), "\n" ); //clean up multiple \n characters
bt.stripWhiteSpace();
/// analyze usefulness
bool useful = true;
const QString fileCommandOutput = runCommand( "file `which basket`" );
if( fileCommandOutput.find( "not stripped", false ) == -1 )
subject += "[___stripped]"; //same length as below
else
subject += "[NOTstripped]";
if( !bt.isEmpty() ) {
const int invalidFrames = bt.contains( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in \\?\\?") );
const int validFrames = bt.contains( QRegExp("\n#[0-9]+\\s+0x[0-9A-Fa-f]+ in [^?]") );
const int totalFrames = invalidFrames + validFrames;
if( totalFrames > 0 ) {
const double validity = double(validFrames) / totalFrames;
subject += QString("[validity: %1]").arg( validity, 0, 'f', 2 );
if( validity <= 0.5 ) useful = false;
}
subject += QString("[frames: %1]").arg( totalFrames, 3 /*padding*/ );
if( bt.find( QRegExp(" at \\w*\\.cpp:\\d+\n") ) >= 0 )
subject += "[line numbers]";
}
else
useful = false;
// subject += QString("[%1]").arg( AmarokConfig::soundSystem().remove( QRegExp("-?engine") ) );
// debug() << subject << endl;
//TODO -fomit-frame-pointer buggers up the backtrace, so detect it
//TODO -O optimization can rearrange execution and stuff so show a warning for the developer
//TODO pass the CXXFLAGS used with the email
if( useful ) {
body += "==== file `which basket` ==========\n";
body += fileCommandOutput + "\n";
body += "==== (gdb) bt =====================\n";
body += bt;//+ "\n\n";
// body += "==== kdBacktrace() ================\n";
// body += kdBacktrace();
//TODO startup notification
kapp->invokeMailer(
/*to*/ "kelvie@ieee.org",
/*cc*/ QString(),
/*bcc*/ QString(),
/*subject*/ subject,
/*body*/ body,
/*messageFile*/ QString(),
/*attachURLs*/ QStringList(),
/*startup_id*/ "" );
}
else {
std::cout << "\n" + i18n( "%1 has crashed! We're sorry about this.\n\n"
"But, all is not lost! Perhaps an upgrade is already available "
"which fixes the problem. Please check your distribution's software repository." )
.arg(kapp->aboutData()->programName()).local8Bit() << std::endl;
}
//_exit() exits immediately, otherwise this
//function is called repeatedly ad finitum
::_exit( 255 );
}
else {
// we are the process that crashed
::alarm( 0 );
// wait for child to exit
::waitpid( pid, NULL, 0 );
::_exit( 253 );
}
}

@ -0,0 +1,31 @@
// Code from Amarok.
/***************************************************************************
* Copyright (C) 2005 Max Howell <max.howell@methylblue.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef CRASH_H
#define CRASH_H
#include <kcrash.h> //for main.cpp
/**
* @author Max Howell
* @short The amaroK crash-handler
*
* I'm not entirely sure why this had to be inside a class, but it
* wouldn't work otherwise *shrug*
*/
class Crash
{
public:
static void crashHandler( int signal );
};
#endif

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 54 KiB

@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qlayout.h>
#include <qtextbrowser.h>
#include <qstring.h>
#include <qevent.h>
#include <klocale.h>
#include "global.h"
#include "debugwindow.h"
DebugWindow::DebugWindow(QWidget *parent, const char *name )
: QWidget(parent, name != 0 ? name : "DebugWindow")
{
Global::debugWindow = this;
setCaption(i18n("Debug Window"));
layout = new QVBoxLayout(this);
textBrowser = new QTextBrowser(this);
textBrowser->setWordWrap(QTextBrowser::NoWrap);
layout->addWidget(textBrowser);
textBrowser->show();
}
DebugWindow::~DebugWindow()
{
delete textBrowser;
delete layout;
}
void DebugWindow::postMessage(const QString msg)
{
textBrowser->append(msg);
}
DebugWindow& DebugWindow::operator<<(const QString msg)
{
textBrowser->append(msg);
return *this;
}
void DebugWindow::insertHLine()
{
textBrowser->append("<hr>");
}
void DebugWindow::closeEvent(QCloseEvent *event)
{
Global::debugWindow = 0L;
QWidget::closeEvent(event);
}
#include "debugwindow.moc"

@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef DEBUGWINDOW_H
#define DEBUGWINDOW_H
#include <qwidget.h>
class QVBoxLayout;
class QTextBrowser;
class QString;
class QCloseEvent;
/**A simple window that display text through debuging messages.
*@author Sébastien Laoût
*/
class DebugWindow : public QWidget {
Q_OBJECT
public:
/** Construtor and destructor */
DebugWindow(QWidget *parent = 0, const char *name = 0);
~DebugWindow();
/** Methods to post a message to the debug window */
void postMessage(const QString msg);
DebugWindow& operator<<(const QString msg);
void insertHLine();
protected:
virtual void closeEvent(QCloseEvent *event);
private:
QVBoxLayout *layout;
QTextBrowser *textBrowser;
};
#define DEBUG_WIN if (Global::debugWindow) *Global::debugWindow
#endif // DEBUGWINDOW_H

@ -0,0 +1,148 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kurlrequester.h>
#include <klineedit.h>
#include <kfiledialog.h>
#include <qcheckbox.h>
#include <qdir.h>
#include <qhbox.h>
#include <qvbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <klocale.h>
#include <kconfig.h>
#include "exporterdialog.h"
#include "basket.h"
ExporterDialog::ExporterDialog(Basket *basket, QWidget *parent, const char *name)
: KDialogBase(parent, name, /*modal=*/true, i18n("Export Basket to HTML"),
KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, /*separator=*/true),
m_basket(basket)
{
QVBox *page = makeVBoxMainWidget();
QWidget *wid = new QWidget(page);
QHBoxLayout *hLay = new QHBoxLayout(wid, /*margin=*/0, KDialogBase::spacingHint());
m_url = new KURLRequester("", wid);
m_url->setCaption(i18n("HTML Page Filename"));
m_url->setFilter("text/html");
m_url->fileDialog()->setOperationMode(KFileDialog::Saving);
hLay->addWidget( new QLabel(m_url, i18n("&Filename:"), wid) );
hLay->addWidget( m_url );
m_embedLinkedFiles = new QCheckBox(i18n("&Embed linked local files"), page);
m_embedLinkedFolders = new QCheckBox(i18n("Embed &linked local folders"), page);
m_erasePreviousFiles = new QCheckBox(i18n("Erase &previous files in target folder"), page);
m_formatForImpression = new QCheckBox(i18n("For&mat for impression"), page);
m_formatForImpression->hide();
load();
m_url->lineEdit()->setFocus();
showTile(true);
// Add a stretch at the bottom:
// Duplicated code from AddBasketWizard::addStretch(QWidget *parent):
(new QWidget(page))->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Double the width, because the filename should be visible
QSize size(sizeHint());
resize(QSize(size.width() * 2, size.height()));
/*
==========================
+ [00000000000 ] Progress bar!
+ newBasket -> name folder as the basket
*/
}
ExporterDialog::~ExporterDialog()
{
}
void ExporterDialog::show()
{
KDialogBase::show();
QString lineEditText = m_url->lineEdit()->text();
int selectionStart = lineEditText.findRev("/") + 1;
m_url->lineEdit()->setSelection(selectionStart, lineEditText.length() - selectionStart - QString(".html").length());
}
void ExporterDialog::load()
{
KConfig *config = KGlobal::config();
config->setGroup("HTML Export");
QString folder = config->readEntry("lastFolder", QDir::homeDirPath()) + "/";
QString url = folder + QString(m_basket->basketName()).replace("/", "_") + ".html";
m_url->setURL(url);
m_embedLinkedFiles->setChecked( config->readBoolEntry("embedLinkedFiles", true) );
m_embedLinkedFolders->setChecked( config->readBoolEntry("embedLinkedFolders", false) );
m_erasePreviousFiles->setChecked( config->readBoolEntry("erasePreviousFiles", true) );
m_formatForImpression->setChecked( config->readBoolEntry("formatForImpression", false) );
}
void ExporterDialog::save()
{
KConfig *config = KGlobal::config();
config->setGroup("HTML Export");
QString folder = KURL(m_url->url()).directory();
config->writeEntry( "lastFolder", folder );
config->writeEntry( "embedLinkedFiles", m_embedLinkedFiles->isChecked() );
config->writeEntry( "embedLinkedFolders", m_embedLinkedFolders->isChecked() );
config->writeEntry( "erasePreviousFiles", m_erasePreviousFiles->isChecked() );
config->writeEntry( "formatForImpression", m_formatForImpression->isChecked() );
}
void ExporterDialog::slotOk()
{
save();
KDialogBase::slotOk();
}
QString ExporterDialog::filePath()
{
return m_url->url();
}
bool ExporterDialog::embedLinkedFiles()
{
return m_embedLinkedFiles->isChecked();
}
bool ExporterDialog::embedLinkedFolders()
{
return m_embedLinkedFolders->isChecked();
}
bool ExporterDialog::erasePreviousFiles()
{
return m_erasePreviousFiles->isChecked();
}
bool ExporterDialog::formatForImpression()
{
return m_formatForImpression->isChecked();
}
#include "exporterdialog.moc"

@ -0,0 +1,60 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef EXPORTERDIALOG_H
#define EXPORTERDIALOG_H
#include <kdialogbase.h>
class KURLRequester;
class QCheckBox;
class QString;
class Basket;
/**
* @author Sébastien Laoût
*/
class ExporterDialog : public KDialogBase
{
Q_OBJECT
public:
ExporterDialog(Basket *basket, QWidget *parent = 0, const char *name = 0);
~ExporterDialog();
QString filePath();
bool embedLinkedFiles();
bool embedLinkedFolders();
bool erasePreviousFiles();
bool formatForImpression();
void show();
protected slots:
void slotOk();
void load();
void save();
private:
Basket *m_basket;
KURLRequester *m_url;
QCheckBox *m_embedLinkedFiles;
QCheckBox *m_embedLinkedFolders;
QCheckBox *m_erasePreviousFiles;
QCheckBox *m_formatForImpression;
};
#endif // EXPORTERDIALOG_H

@ -0,0 +1,307 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qlayout.h>
//#include <ktoolbarbutton.h>
#include <qtoolbutton.h>
#include <qlabel.h>
//#include <qcombobox.h>
//#include <klineedit.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kglobalsettings.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qpainter.h>
#include <qbitmap.h>
#include <kdialogbase.h>
#include "filter.h"
//#include "settings.h"
#include "global.h"
#include "bnpview.h"
#include "tools.h"
#include "tag.h"
#include "focusedwidgets.h"
/** FilterBar */
FilterBar::FilterBar(QWidget *parent, const char *name)
: QWidget(parent, name)/*, m_blinkTimer(this), m_blinkedTimes(0)*/
{
QHBoxLayout *hBox = new QHBoxLayout(this, /*margin*/0, /*spacing*/0);
// Create every widgets:
QIconSet resetIconSet = kapp->iconLoader()->loadIconSet("locationbar_erase", KIcon::Toolbar);
QIconSet inAllIconSet = kapp->iconLoader()->loadIconSet("find", KIcon::Toolbar);
m_resetButton = new QToolButton(this);
m_resetButton->setIconSet(resetIconSet);
m_resetButton->setTextLabel(i18n("Reset Filter"));//, /*groupText=*/"", this, SLOT(reset()), 0);
m_resetButton->setAutoRaise(true);
//new KToolBarButton("locationbar_erase", /*id=*/1230, this, /*name=*/0, i18n("Reset Filter"));
m_lineEdit = new FocusedLineEdit(this);
QLabel *label = new QLabel(m_lineEdit, i18n("&Filter: "), this);
m_tagsBox = new FocusedComboBox(this);
QLabel *label2 = new QLabel(m_tagsBox, i18n("T&ag: "), this);
m_inAllBasketsButton = new QToolButton(this);
m_inAllBasketsButton->setIconSet(inAllIconSet);
m_inAllBasketsButton->setTextLabel(i18n("Filter all Baskets"));//, /*groupText=*/"", this, SLOT(inAllBaskets()), 0);
m_inAllBasketsButton->setAutoRaise(true);
// Configure the Reset button:
m_resetButton->setEnabled(false);
// Configure the Tags combobox:
repopulateTagsComnbo();
// Configure the Serach in all Baskets button:
m_inAllBasketsButton->setToggleButton(true);
// m_inAllBasketsButton->setOn(true);
// Global::bnpView->toggleFilterAllBaskets(true);
// m_lineEdit->setMaximumWidth(150);
// Layout all those widgets:
// hBox->addStretch();
hBox->addWidget(m_resetButton);
hBox->addSpacing(KDialogBase::spacingHint());
hBox->addWidget(label);
hBox->addWidget(m_lineEdit);
hBox->addSpacing(KDialogBase::spacingHint());
hBox->addWidget(label2);
hBox->addWidget(m_tagsBox);
hBox->addSpacing(KDialogBase::spacingHint());
hBox->addWidget(m_inAllBasketsButton);
m_data = new FilterData(); // TODO: Not a pointer! and return a const & !!
// connect( &m_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkBar()) );
connect( m_resetButton, SIGNAL(clicked()), this, SLOT(reset()) );
connect( m_lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&)) );
connect( m_tagsBox, SIGNAL(activated(int)), this, SLOT(tagChanged(int)) );
// connect( m_inAllBasketsButton, SIGNAL(clicked()), this, SLOT(inAllBaskets()) );
connect( m_inAllBasketsButton, SIGNAL(toggled(bool)), Global::bnpView, SLOT(toggleFilterAllBaskets(bool)) );
connect( m_lineEdit, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()) );
connect( m_lineEdit, SIGNAL(returnPressed()), this, SIGNAL(returnPressed()) );
connect( m_tagsBox, SIGNAL(escapePressed()), this, SIGNAL(escapePressed()) );
connect( m_tagsBox, SIGNAL(returnPressed2()), this, SIGNAL(returnPressed()) );
}
FilterBar::~FilterBar()
{
}
void FilterBar::setFilterAll(bool filterAll)
{
m_inAllBasketsButton->setOn(filterAll);
}
void FilterBar::setFilterData(const FilterData &data)
{
m_lineEdit->setText(data.string);
int index = 0;
switch (data.tagFilterType) {
default:
case FilterData::DontCareTagsFilter: index = 0; break;
case FilterData::NotTaggedFilter: index = 1; break;
case FilterData::TaggedFilter: index = 2; break;
case FilterData::TagFilter: filterTag(data.tag); return;
case FilterData::StateFilter: filterState(data.state); return;
}
if (m_tagsBox->currentItem() != index) {
m_tagsBox->setCurrentItem(index);
tagChanged(index);
}
}
void FilterBar::repopulateTagsComnbo()
{
static const int ICON_SIZE = 16;
m_tagsBox->clear();
m_tagsMap.clear();
m_statesMap.clear();
m_tagsBox->insertItem("", 0);
m_tagsBox->insertItem(i18n("(Not tagged)"), 1);
m_tagsBox->insertItem(i18n("(Tagged)"), 2);
int index = 3;
Tag *tag;
State *state;
QString icon;
QString text;
QPixmap emblem;
for (Tag::List::iterator it = Tag::all.begin(); it != Tag::all.end(); ++it) {
tag = *it;
state = tag->states().first();
// Insert the tag in the combo-box:
if (tag->countStates() > 1) {
text = tag->name();
icon = "";
} else {
text = state->name();
icon = state->emblem();
}
emblem = kapp->iconLoader()->loadIcon(icon, KIcon::Desktop, ICON_SIZE, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
m_tagsBox->insertItem(emblem, text, index);
// Update the mapping:
m_tagsMap.insert(index, tag);
++index;
// Insert sub-states, if needed:
if (tag->countStates() > 1) {
for (State::List::iterator it2 = tag->states().begin(); it2 != tag->states().end(); ++it2) {
state = *it2;
// Insert the state:
text = state->name();
icon = state->emblem();
emblem = kapp->iconLoader()->loadIcon(icon, KIcon::Desktop, ICON_SIZE, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
// Indent the emblem to show the hierarchy relation:
if (!emblem.isNull())
emblem = Tools::indentPixmap(emblem, /*depth=*/1, /*deltaX=*/2 * ICON_SIZE / 3);
m_tagsBox->insertItem(emblem, text, index);
// Update the mapping:
m_statesMap.insert(index, state);
++index;
}
}
}
}
void FilterBar::reset()
{
m_lineEdit->setText(""); // m_data->isFiltering will be set to false;
if (m_tagsBox->currentItem() != 0) {
m_tagsBox->setCurrentItem(0);
tagChanged(0);
}
}
void FilterBar::filterTag(Tag *tag)
{
int index = 0;
for (QMap<int, Tag*>::Iterator it = m_tagsMap.begin(); it != m_tagsMap.end(); ++it)
if (it.data() == tag) {
index = it.key();
break;
}
if (index <= 0)
return;
if (m_tagsBox->currentItem() != index) {
m_tagsBox->setCurrentItem(index);
tagChanged(index);
}
}
void FilterBar::filterState(State *state)
{
int index = 0;
for (QMap<int, State*>::Iterator it = m_statesMap.begin(); it != m_statesMap.end(); ++it)
if (it.data() == state) {
index = it.key();
break;
}
if (index <= 0)
return;
if (m_tagsBox->currentItem() != index) {
m_tagsBox->setCurrentItem(index);
tagChanged(index);
}
}
void FilterBar::inAllBaskets()
{
// TODO!
}
void FilterBar::setEditFocus()
{
m_lineEdit->setFocus();
}
bool FilterBar::hasEditFocus()
{
return m_lineEdit->hasFocus();
}
const FilterData& FilterBar::filterData()
{
return *m_data;
}
void FilterBar::textChanged(const QString &text)
{
m_data->string = text;
m_data->isFiltering = (!m_data->string.isEmpty() || m_data->tagFilterType != FilterData::DontCareTagsFilter);
m_resetButton->setEnabled(m_data->isFiltering);
emit newFilter(*m_data);
}
void FilterBar::tagChanged(int index)
{
m_data->tag = 0;
m_data->state = 0;
switch (index) {
case 0:
m_data->tagFilterType = FilterData::DontCareTagsFilter;
break;
case 1:
m_data->tagFilterType = FilterData::NotTaggedFilter;
break;
case 2:
m_data->tagFilterType = FilterData::TaggedFilter;
break;
default:
// Try to find if we are filtering a tag:
QMapIterator<int, Tag*> it = m_tagsMap.find(index);
if (it != m_tagsMap.end()) {
m_data->tagFilterType = FilterData::TagFilter;
m_data->tag = *it;
} else {
// If not, try to find if we are filtering a state:
QMapIterator<int, State*> it2 = m_statesMap.find(index);
if (it2 != m_statesMap.end()) {
m_data->tagFilterType = FilterData::StateFilter;
m_data->state = *it2;
} else {
// If not (should never happens), do as if the tags filter was reseted:
m_data->tagFilterType = FilterData::DontCareTagsFilter;
}
}
break;
}
m_data->isFiltering = (!m_data->string.isEmpty() || m_data->tagFilterType != FilterData::DontCareTagsFilter);
m_resetButton->setEnabled(m_data->isFiltering);
emit newFilter(*m_data);
}
#include "filter.moc"

@ -0,0 +1,93 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef FILTER_H
#define FILTER_H
#include <qwidget.h>
#include <qmap.h>
#include "focusedwidgets.h"
class QToolButton;
class Tag;
class State;
/** The structure that contain all filter terms
* @author Sébastien Laoût
*/
class FilterData
{
public:
// Useful Enum for tagFilterType:
enum TagFilterType { DontCareTagsFilter = 0, NotTaggedFilter, TaggedFilter, TagFilter, StateFilter };
// Constructor and Destructor:
FilterData() { isFiltering = false; tagFilterType = DontCareTagsFilter; tag = 0; state = 0; }
~FilterData() {}
// Filter data:
QString string;
int tagFilterType;
Tag *tag;
State *state;
bool isFiltering;
};
/** A QWidget that allow user to enter terms to filter in a Basket.
* @author Sébastien Laoût
*/
class FilterBar : public QWidget
{
Q_OBJECT
public:
FilterBar(QWidget *parent = 0, const char *name = 0);
~FilterBar();
const FilterData& filterData();
signals:
void newFilter(const FilterData &data);
void escapePressed();
void returnPressed();
public slots:
void repopulateTagsComnbo();
void reset();
void inAllBaskets();
void setEditFocus();
void filterTag(Tag *tag);
void filterState(State *state);
void setFilterAll(bool filterAll);
void setFilterData(const FilterData &data);
public:
bool hasEditFocus();
KLineEdit* lineEdit() { return m_lineEdit; }
private slots:
void textChanged(const QString &text);
void tagChanged(int index);
private:
FilterData *m_data;
FocusedLineEdit *m_lineEdit;
QToolButton *m_resetButton;
FocusedComboBox *m_tagsBox;
QToolButton *m_inAllBasketsButton;
QMap<int, Tag*> m_tagsMap;
QMap<int, State*> m_statesMap;
};
#endif // FILTER_H

@ -0,0 +1,295 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qpopupmenu.h>
#include <klocale.h>
#include <iostream>
#include "focusedwidgets.h"
#include "bnpview.h"
#include "global.h"
#include "basket.h"
#ifdef KeyPress
#undef KeyPress
#endif
#include <qevent.h>
/** class FocusedTextEdit */
FocusedTextEdit::FocusedTextEdit(bool disableUpdatesOnKeyPress, QWidget *parent, const char *name)
: KTextEdit(parent, name),
m_disableUpdatesOnKeyPress(disableUpdatesOnKeyPress)
{
setWFlags(Qt::WNoAutoErase); // Does not work, we still need the disableUpdatesOnKeyPress hack!
}
FocusedTextEdit::~FocusedTextEdit()
{
}
/**
* Thanks to alex.theel@gmx.net, author of TuxCards
* Code copied from tuxcards-1.2/src/gui/editor/editor.cpp
*
***
* Override the regular paste() methode, so that lines are
* not separated by each other with an blank line.
*/
void FocusedTextEdit::paste()
{
adaptClipboardText(QClipboard::Selection);
adaptClipboardText(QClipboard::Clipboard);
// If we paste a application/x-qrichtext content starting with a "-" or a "*",
// then auto-bulletting will crash.
// So we insert a space to be sure what we paste will not trigger the auto-bulleting.
// enum AutoFormatting { AutoNone = 0, AutoBulletList = 0x00000001, AutoAll = 0xffffffff }
// uint oldAutoFormating = autoFormatting();
// setAutoFormatting(AutoNone);
QClipboard *clipboard = QApplication::clipboard();
int paragraph;
int index;
getCursorPosition(&paragraph, &index);
bool preventAutoBullet = (index == 0) &&
(clipboard->data(QClipboard::Selection)->provides("application/x-qrichtext") ||
clipboard->data(QClipboard::Clipboard)->provides("application/x-qrichtext") );
if (preventAutoBullet)
insert(" ");
KTextEdit::paste();
if (preventAutoBullet) {
int paragraph2;
int index2;
getCursorPosition(&paragraph2, &index2);
setSelection(paragraph, index, paragraph, index + 1);
removeSelectedText();
if (paragraph == paragraph2) // We removed one character in that paragraph, so we should move the cursor back to old position... minus one character
index2--;
setCursorPosition(paragraph2, index2);
}
// setAutoFormatting(oldAutoFormating);
}
/**
* Thanks to alex.theel@gmx.net, author of TuxCards
* Code copied from tuxcards-1.2/src/gui/editor/editor.cpp
*
***
* Auxiliar method that takes the text from the clipboard - using the
* specified 'mode' -, replaces all '\n' within that text and writes
* it back to the clipboard.
*/
void FocusedTextEdit::adaptClipboardText(QClipboard::Mode mode)
{
QClipboard *clipboard = QApplication::clipboard();
if (!clipboard)
return;
if ( (textFormat() == Qt::RichText) && (!clipboard->data(mode)->provides("application/x-qrichtext")) ) {
QString text = clipboard->text(mode);
if (text) {
text = text.replace("\n", QChar(0x2028));
clipboard->setText(text, mode);
}
}
}
QTextCursor* FocusedTextEdit::textCursor() const
{
return KTextEdit::textCursor();
}
void FocusedTextEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape) {
emit escapePressed();
return;
// In RichTextFormat mode, [Return] create a new paragraphe.
// To keep consistency with TextFormat mode (new line on [Return]),
// we redirect [Return] to simulate [Ctrl+Return] (create a new line in both modes).
// Create new paragraphes still possible in RichTextFormat mode with [Shift+Enter].
} else if (event->key() == Qt::Key_Return && event->state() == 0)
event = new QKeyEvent(QEvent::KeyPress, event->key(), event->ascii(), Qt::ControlButton,
event->text(), event->isAutoRepeat(), event->count() );
else if (event->key() == Qt::Key_Return && event->state() & Qt::ControlButton)
event = new QKeyEvent(QEvent::KeyPress, event->key(), event->ascii(), Qt::ShiftButton,
event->text(), event->isAutoRepeat(), event->count() );
if (m_disableUpdatesOnKeyPress)
setUpdatesEnabled(false);
KTextEdit::keyPressEvent(event);
// Workarround (for ensuring the cursor to be visible): signal not emited when pressing those keys:
if (event->key() == Qt::Key_Home || event->key() == Qt::Key_End || event->key() == Qt::Key_PageUp || event->key() == Qt::Key_PageDown) {
int para;
int index;
getCursorPosition(&para, &index);
emit cursorPositionChanged(para, index);
}
if (m_disableUpdatesOnKeyPress) {
setUpdatesEnabled(true);
if (text().isEmpty())
;// emit textChanged(); // TODO: DOESN'T WORK: the editor is not resized down to only one line of text
else
ensureCursorVisible();
updateContents();
}
}
void FocusedTextEdit::wheelEvent(QWheelEvent *event)
{
if (event->delta() > 0 && contentsY() > 0) {
KTextEdit::wheelEvent(event);
return;
} else if (event->delta() < 0 && contentsY() + visibleHeight() < contentsHeight()) {
KTextEdit::wheelEvent(event);
return;
} else
Global::bnpView->currentBasket()->wheelEvent(event);
}
void FocusedTextEdit::enterEvent(QEvent *event)
{
emit mouseEntered();
KTextEdit::enterEvent(event);
}
QPopupMenu* FocusedTextEdit::createPopupMenu(const QPoint &pos)
{
QPopupMenu *menu = KTextEdit::createPopupMenu(pos);
int index = 0;
int id = 0;
while (true) {
id = menu->idAt(index);
if (id == -1)
break;
// Disable Spell Check for rich text editors, because it doesn't work anyway:
if (textFormat() == Qt::RichText && (menu->text(id) == i18n("Auto Spell Check") || menu->text(id) == i18n("Check Spelling...")))
menu->setItemEnabled(id, false);
// Always enable tabulations!:
if (menu->text(id) == i18n("Allow Tabulations"))
menu->setItemEnabled(id, false);
index++;
}
// And return the menu:
return menu;
}
/** class FocusedColorCombo: */
FocusedColorCombo::FocusedColorCombo(QWidget *parent, const char *name)
: KColorCombo(parent, name)
{
}
FocusedColorCombo::~FocusedColorCombo()
{
}
void FocusedColorCombo::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
else if (event->key() == Qt::Key_Return)
emit returnPressed2();
else
KColorCombo::keyPressEvent(event);
}
/** class FocusedFontCombo: */
FocusedFontCombo::FocusedFontCombo(QWidget *parent, const char *name)
: KFontCombo(parent, name)
{
}
FocusedFontCombo::~FocusedFontCombo()
{
}
void FocusedFontCombo::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
else if (event->key() == Qt::Key_Return)
emit returnPressed2();
else
KFontCombo::keyPressEvent(event);
}
/** class FocusedComboBox: */
FocusedComboBox::FocusedComboBox(QWidget *parent, const char *name)
: KComboBox(parent, name)
{
}
FocusedComboBox::~FocusedComboBox()
{
}
void FocusedComboBox::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
else if (event->key() == Qt::Key_Return)
emit returnPressed2();
else
KComboBox::keyPressEvent(event);
}
/** class FocusedLineEdit: */
FocusedLineEdit::FocusedLineEdit(QWidget *parent, const char *name)
: KLineEdit(parent, name)
{
}
FocusedLineEdit::~FocusedLineEdit()
{
}
void FocusedLineEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
else
KLineEdit::keyPressEvent(event);
}
void FocusedLineEdit::enterEvent(QEvent *event)
{
emit mouseEntered();
KLineEdit::enterEvent(event);
}
#include "focusedwidgets.moc"

@ -0,0 +1,110 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef FOCUSEDWIDGETS_H
#define FOCUSEDWIDGETS_H
#include <ktextedit.h>
#include <kcolorcombo.h>
#include <kfontcombo.h>
#include <kcombobox.h>
#include <klineedit.h>
#include <kapplication.h>
#include <qclipboard.h>
class FocusedTextEdit : public KTextEdit
{
Q_OBJECT
public:
FocusedTextEdit(bool disableUpdatesOnKeyPress, QWidget *parent = 0, const char *name = 0);
~FocusedTextEdit();
void paste();
QTextCursor* textCursor() const;
protected:
void adaptClipboardText(QClipboard::Mode mode);
void keyPressEvent(QKeyEvent *event);
void wheelEvent(QWheelEvent *event);
void enterEvent(QEvent *event);
QPopupMenu* createPopupMenu(const QPoint &pos);
signals:
void escapePressed();
void mouseEntered();
private:
bool m_disableUpdatesOnKeyPress;
};
// TODO: Rename to EscapableKColorCombo
class FocusedColorCombo : public KColorCombo
{
Q_OBJECT
public:
FocusedColorCombo(QWidget *parent = 0, const char *name = 0);
~FocusedColorCombo();
protected:
void keyPressEvent(QKeyEvent *event);
signals:
void escapePressed();
void returnPressed2();
};
// TODO: Rename to EscapableKFontCombo
class FocusedFontCombo : public KFontCombo
{
Q_OBJECT
public:
FocusedFontCombo(QWidget *parent = 0, const char *name = 0);
~FocusedFontCombo();
protected:
void keyPressEvent(QKeyEvent *event);
signals:
void escapePressed();
void returnPressed2();
};
// TODO: Rename to EscapableKComboBox
class FocusedComboBox : public KComboBox
{
Q_OBJECT
public:
FocusedComboBox(QWidget *parent = 0, const char *name = 0);
~FocusedComboBox();
protected:
void keyPressEvent(QKeyEvent *event);
signals:
void escapePressed();
void returnPressed2();
};
// TODO: Rename to EscapableKLineEdit
class FocusedLineEdit : public KLineEdit
{
Q_OBJECT
public:
FocusedLineEdit(QWidget *parent = 0, const char *name = 0);
~FocusedLineEdit();
protected:
void keyPressEvent(QKeyEvent *event);
void enterEvent(QEvent *event);
signals:
void escapePressed();
void mouseEntered();
};
#endif // FOCUSEDWIDGETS_H

@ -0,0 +1,307 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstring.h>
#include <qstringlist.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qdom.h>
#include <kglobalsettings.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kapplication.h>
#include <iostream>
#include "formatimporter.h"
#include "notecontent.h"
#include "notefactory.h"
#include "bnpview.h"
#include "basket.h"
#include "global.h"
#include "xmlwork.h"
#include "tools.h"
bool FormatImporter::shouldImportBaskets()
{
// We should import if the application have not successfully loaded any basket...
if (Global::bnpView->firstListViewItem())
return false;
// ... And there is at least one folder in the save folder, with a ".basket" file inside that folder.
QDir dir(Global::savesFolder(), QString::null, QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoSymLinks);
QStringList list = dir.entryList();
for (QStringList::Iterator it = list.begin(); it != list.end(); ++it)
if (*it != "." && *it != ".." && dir.exists(Global::savesFolder() + *it + "/.basket"))
return true;
return false;
}
void FormatImporter::copyFolder(const QString &folder, const QString &newFolder)
{
copyFinished = false;
KIO::CopyJob *copyJob = KIO::copyAs(KURL(folder), KURL(newFolder), /*showProgressInfo=*/false);
connect( copyJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotCopyingDone(KIO::Job*)) );
while (!copyFinished)
kapp->processEvents();
}
void FormatImporter::moveFolder(const QString &folder, const QString &newFolder)
{
copyFinished = false;
KIO::CopyJob *copyJob = KIO::moveAs(KURL(folder), KURL(newFolder), /*showProgressInfo=*/false);
connect( copyJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotCopyingDone(KIO::Job*)) );
while (!copyFinished)
kapp->processEvents();
}
void FormatImporter::slotCopyingDone(KIO::Job *)
{
// std::cout << "Copy finished of " + from.path() + " to " + to.path() << std::endl;
copyFinished = true;
}
void FormatImporter::importBaskets()
{
std::cout << "Import Baskets: Preparing..." << std::endl;
// Some preliminary preparations (create the destination folders and the basket tree file):
QDir dirPrep;
dirPrep.mkdir(Global::savesFolder());
dirPrep.mkdir(Global::basketsFolder());
QDomDocument document("basketTree");
QDomElement root = document.createElement("basketTree");
document.appendChild(root);
// First up, establish a list of every baskets, ensure the old order (if any), and count them.
QStringList baskets;
// Read the 0.5.0 baskets order:
QDomDocument *doc = XMLWork::openFile("container", Global::savesFolder() + "container.baskets");
if (doc != 0) {
QDomElement docElem = doc->documentElement();
QDomElement basketsElem = XMLWork::getElement(docElem, "baskets");
QDomNode n = basketsElem.firstChild();
while (!n.isNull()) {
QDomElement e = n.toElement();
if ((!e.isNull()) && e.tagName() == "basket")
baskets.append(e.text());
n = n.nextSibling();
}
}
// Then load the baskets that weren't loaded (import < 0.5.0 ones):
QDir dir(Global::savesFolder(), QString::null, QDir::Name | QDir::IgnoreCase, QDir::Dirs | QDir::NoSymLinks);
QStringList list = dir.entryList();
if (list.count() > 2) // Pass "." and ".."
for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) // For each folder
if (*it != "." && *it != ".." && dir.exists(Global::savesFolder() + *it + "/.basket")) // If it can be a basket folder
if ( baskets.find((*it) + "/") == baskets.end() &&
baskets.find(*it) == baskets.end() ) // And if it is not already in the imported baskets list
baskets.append(*it);
std::cout << "Import Baskets: Found " << baskets.count() << " baskets to import." << std::endl;
// Import every baskets:
int i = 0;
for (QStringList::iterator it = baskets.begin(); it != baskets.end(); ++it) {
++i;
std::cout << "Import Baskets: Importing basket " << i << " of " << baskets.count() << "..." << std::endl;
// Move the folder to the new repository (normal basket) or copy the folder (mirorred folder):
QString folderName = *it;
if (folderName.startsWith("/")) { // It was a folder mirror:
KMessageBox::information(0, i18n("<p>Folder mirroring is not possible anymore (see <a href='http://basket.kde.org/'>basket.kde.org</a> for more information).</p>"
"<p>The folder <b>%1</b> has been copied for the basket needs. You can either delete this folder or delete the basket, or use both. But remember that "
"modifying one will not modify the other anymore as they are now separate entities.</p>").arg(folderName), i18n("Folder Mirror Import"),
"", KMessageBox::AllowLink);
// Also modify folderName to be only the folder name and not the full path anymore:
QString newFolderName = folderName;
if (newFolderName.endsWith("/"))
newFolderName = newFolderName.left(newFolderName.length() - 1);
newFolderName = newFolderName.mid(newFolderName.findRev('/') + 1);
newFolderName = Tools::fileNameForNewFile(newFolderName, Global::basketsFolder());
FormatImporter f;
f.copyFolder(folderName, Global::basketsFolder() + newFolderName);
folderName = newFolderName;
} else
dir.rename(Global::savesFolder() + folderName, Global::basketsFolder() + folderName); // Move the folder
// Import the basket structure file and get the properties (to add them in the tree basket-properties cache):
QDomElement properties = importBasket(folderName);
// Add it to the XML document:
QDomElement basketElement = document.createElement("basket");
root.appendChild(basketElement);
basketElement.setAttribute("folderName", folderName);
basketElement.appendChild(properties);
}
// Finalize (write to disk and delete now useless files):
std::cout << "Import Baskets: Finalizing..." << std::endl;
QFile file(Global::basketsFolder() + "baskets.xml");
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
QString xml = document.toString();
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
stream << xml;
file.close();
}
Tools::deleteRecursively(Global::savesFolder() + ".tmp");
dir.remove(Global::savesFolder() + "container.baskets");
std::cout << "Import Baskets: Finished." << std::endl;
}
QDomElement FormatImporter::importBasket(const QString &folderName)
{
// Load the XML file:
QDomDocument *document = XMLWork::openFile("basket", Global::basketsFolder() + folderName + "/.basket");
if (!document) {
std::cout << "Import Baskets: Failed to read the basket file!" << std::endl;
return QDomElement();
}
QDomElement docElem = document->documentElement();
// Import properties (change <background color=""> to <appearance backgroundColor="">, and figure out if is a checklist or not):
QDomElement properties = XMLWork::getElement(docElem, "properties");
QDomElement background = XMLWork::getElement(properties, "background");
QColor backgroundColor = QColor(background.attribute("color"));
if (backgroundColor.isValid() && (backgroundColor != KGlobalSettings::baseColor())) { // Use the default color if it was already that color:
QDomElement appearance = document->createElement("appearance");
appearance.setAttribute("backgroundColor", backgroundColor.name());
properties.appendChild(appearance);
}
QDomElement disposition = document->createElement("disposition");
disposition.setAttribute("mindMap", "false");
disposition.setAttribute("columnCount", "1");
disposition.setAttribute("free", "false");
bool isCheckList = XMLWork::trueOrFalse( XMLWork::getElementText(properties, "showCheckBoxes", false) );
// Insert all notes in a group (column): 1/ rename "items" to "group", 2/ add "notes" to root, 3/ move "group" into "notes"
QDomElement column = XMLWork::getElement(docElem, "items");
column.setTagName("group");
QDomElement notes = document->createElement("notes");
notes.appendChild(column);
docElem.appendChild(notes);
// Import notes from older representations:
QDomNode n = column.firstChild();
while ( ! n.isNull() ) {
QDomElement e = n.toElement();
if (!e.isNull()) {
e.setTagName("note");
QDomElement content = XMLWork::getElement(e, "content");
// Add Check tag:
if (isCheckList) {
bool isChecked = XMLWork::trueOrFalse(e.attribute("checked", "false"));
XMLWork::addElement(*document, e, "tags", (isChecked ? "todo_done" : "todo_unchecked"));
}
// Import annotations as folded groups:
QDomElement parentE = column;
QString annotations = XMLWork::getElementText(e, "annotations", "");
if (!annotations.isEmpty()) {
QDomElement annotGroup = document->createElement("group");
column.insertBefore(annotGroup, e);
annotGroup.setAttribute("folded", "true");
annotGroup.appendChild(e);
parentE = annotGroup;
// Create the text note and add it to the DOM tree:
QDomElement annotNote = document->createElement("note");
annotNote.setAttribute("type", "text");
annotGroup.appendChild(annotNote);
QString annotFileName = Tools::fileNameForNewFile("annotations1.txt", Basket::fullPathForFolderName(folderName));
QString annotFullPath = Basket::fullPathForFolderName(folderName) + "/" + annotFileName;
QFile file(annotFullPath);
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream << annotations;
file.close();
}
XMLWork::addElement(*document, annotNote, "content", annotFileName);
n = annotGroup;
}
// Import Launchers from 0.3.x, 0.4.0 and 0.5.0-alphas:
QString runCommand = e.attribute("runcommand"); // Keep compatibility with 0.4.0 and 0.5.0-alphas versions
runCommand = XMLWork::getElementText(e, "action", runCommand); // Keep compatibility with 0.3.x versions
if ( ! runCommand.isEmpty() ) { // An import should be done
// Prepare the launcher note:
QString title = content.attribute("title", "");
QString icon = content.attribute("icon", "");
if (title.isEmpty()) title = runCommand;
if (icon.isEmpty()) icon = NoteFactory::iconForCommand(runCommand);
// Import the launcher note:
// Adapted version of "QString launcherName = NoteFactory::createNoteLauncherFile(runCommand, title, icon, this)":
QString launcherContent = QString(
"[Desktop Entry]\n"
"Exec=%1\n"
"Name=%2\n"
"Icon=%3\n"
"Encoding=UTF-8\n"
"Type=Application\n").arg(runCommand, title, icon.isEmpty() ? QString("exec") : icon);
QString launcherFileName = Tools::fileNameForNewFile("launcher.desktop", Global::basketsFolder() + folderName /*+ "/"*/);
QString launcherFullPath = Global::basketsFolder() + folderName /*+ "/"*/ + launcherFileName;
QFile file(launcherFullPath);
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
stream << launcherContent;
file.close();
}
// Add the element to the DOM:
QDomElement launcherElem = document->createElement("note");
parentE.insertBefore(launcherElem, e);
launcherElem.setAttribute("type", "launcher");
XMLWork::addElement(*document, launcherElem, "content", launcherFileName);
}
// Import unknown ns to 0.6.0:
if (e.attribute("type") == "unknow")
e.setAttribute("type", "unknown");
// Import links from version < 0.5.0:
if (!content.attribute("autotitle").isEmpty() && content.attribute("autoTitle").isEmpty())
content.setAttribute("autoTitle", content.attribute("autotitle"));
if (!content.attribute("autoicon").isEmpty() && content.attribute("autoIcon").isEmpty())
content.setAttribute("autoIcon", content.attribute("autoicon"));
}
n = n.nextSibling();
}
// Save the resulting XML file:
QFile file(Global::basketsFolder() + folderName + "/.basket");
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
// QString xml = document->toString();
// stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
// stream << xml;
stream << document->toString(); // Document is ALREADY using UTF-8
file.close();
} else
std::cout << "Import Baskets: Failed to save the basket file!" << std::endl;
// Return the newly created properties (to put in the basket tree):
return properties;
}
#include "formatimporter.moc"

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef FORMATIMPORTER_H
#define FORMATIMPORTER_H
#include <qobject.h>
//#include <qwidget.h>
#include <qdom.h>
namespace KIO {
class Job;
}
/**
* @author S<EFBFBD>astien Laot
*/
class FormatImporter : QObject
{
Q_OBJECT
public:
static bool shouldImportBaskets();
static void importBaskets();
static QDomElement importBasket(const QString &folderName);
void copyFolder(const QString &folder, const QString &newFolder);
void moveFolder(const QString &folder, const QString &newFolder);
private slots:
void slotCopyingDone(KIO::Job*);
private:
bool copyFinished;
};
#endif // FORMATIMPORTER_H

@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kglobal.h>
#include <kstandarddirs.h>
#include <qstring.h>
#include <kaction.h>
#include <kapplication.h>
#include <kmainwindow.h>
#include <qdir.h>
#include <kdebug.h>
#include <kconfig.h>
#include "global.h"
#include "bnpview.h"
#include "settings.h"
/** Define initial values for global variables : */
QString Global::s_customSavesFolder = "";
LikeBack *Global::likeBack = 0L;
DebugWindow *Global::debugWindow = 0L;
BackgroundManager *Global::backgroundManager = 0L;
SystemTray *Global::systemTray = 0L;
BNPView *Global::bnpView = 0L;
KGlobalAccel *Global::globalAccel = 0L;
KConfig *Global::basketConfig = 0L;
AboutData Global::basketAbout;
void Global::setCustomSavesFolder(const QString &folder)
{
s_customSavesFolder = folder;
}
#include <iostream>
QString Global::savesFolder()
{
static QString *folder = 0L; // Memorize the folder to do not have to re-compute it each time it's needed
if (folder == 0L) { // Initialize it if not yet done
if (!s_customSavesFolder.isEmpty()) { // Passed by command line (for development & debug purpose)
QDir dir;
dir.mkdir(s_customSavesFolder);
folder = new QString(s_customSavesFolder.endsWith("/") ? s_customSavesFolder : s_customSavesFolder + "/");
} else if (!Settings::dataFolder().isEmpty()) { // Set by config option (in Basket -> Backup & Restore)
QDir dir;
dir.mkdir(s_customSavesFolder);
folder = new QString(Settings::dataFolder().endsWith("/") ? Settings::dataFolder() : Settings::dataFolder() + "/");
} else { // The default path (should be that for most computers)
folder = new QString(KGlobal::dirs()->saveLocation("data", "basket/"));
}
}
return *folder;
}
QString Global::basketsFolder() { return savesFolder() + "baskets/"; }
QString Global::backgroundsFolder() { return savesFolder() + "backgrounds/"; }
QString Global::templatesFolder() { return savesFolder() + "templates/"; }
QString Global::tempCutFolder() { return savesFolder() + "temp-cut/"; }
QString Global::openNoteIcon() // FIXME: Now an edit icon
{
return Global::bnpView->m_actEditNote->icon();
}
KMainWindow* Global::mainWindow()
{
QWidget* res = kapp->mainWidget();
if(res && res->inherits("KMainWindow"))
{
return static_cast<KMainWindow*>(res);
}
return 0;
}
KConfig* Global::config()
{
if(!Global::basketConfig)
Global::basketConfig = KSharedConfig::openConfig("basketrc");
return Global::basketConfig;
}

@ -0,0 +1,71 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef GLOBAL_H
#define GLOBAL_H
#include <qstring.h>
#include "aboutdata.h"
class LikeBack;
class DebugWindow;
class BackgroundManager;
class SystemTray;
class BNPView;
class KGlobalAccel;
class KMainWindow;
class KAboutData;
/** Handle all global variables of the application.
* This file only declare classes : developer should include
* the .h files of variables he use.
* @author S<EFBFBD>astien Laot
*/
class Global
{
private:
static QString s_customSavesFolder;
public:
// Global Variables:
static LikeBack *likeBack;
static DebugWindow *debugWindow;
static BackgroundManager *backgroundManager;
static SystemTray *systemTray;
static BNPView *bnpView;
static KGlobalAccel *globalAccel;
static KConfig *basketConfig;
static AboutData basketAbout;
// Application Folders:
static void setCustomSavesFolder(const QString &folder);
static QString savesFolder(); /// << @return e.g. "/home/username/.kde/share/apps/basket/".
static QString basketsFolder(); /// << @return e.g. "/home/username/.kde/share/apps/basket/baskets/".
static QString backgroundsFolder(); /// << @return e.g. "/home/username/.kde/share/apps/basket/backgrounds/".
static QString templatesFolder(); /// << @return e.g. "/home/username/.kde/share/apps/basket/templates/".
static QString tempCutFolder(); /// << @return e.g. "/home/username/.kde/share/apps/basket/temp-cut/". (was ".tmp/")
// Various Things:
static QString openNoteIcon(); /// << @return the icon used for the "Open" action on notes.
static KMainWindow* mainWindow();
static KConfig* config();
static KAboutData* about() { return &basketAbout; };
};
#endif // GLOBAL_H

@ -0,0 +1,560 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "htmlexporter.h"
#include "bnpview.h"
#include "basketlistview.h"
#include "basket.h"
#include "note.h"
#include "tools.h"
#include "config.h"
#include "tag.h"
#include <kapplication.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <qdir.h>
#include <qfile.h>
#include <qpainter.h>
#include <kglobalsettings.h>
#include <kprogress.h>
HTMLExporter::HTMLExporter(Basket *basket)
{
QDir dir;
// Compute a default file name & path:
KConfig *config = KGlobal::config();
config->setGroup("Export to HTML");
QString folder = config->readEntry("lastFolder", QDir::homeDirPath()) + "/";
QString url = folder + QString(basket->basketName()).replace("/", "_") + ".html";
// Ask a file name & path to the user:
QString filter = "*.html *.htm|" + i18n("HTML Documents") + "\n*|" + i18n("All Files");
QString destination = url;
for (bool askAgain = true; askAgain; ) {
// Ask:
destination = KFileDialog::getSaveFileName(destination, filter, 0, i18n("Export to HTML"));
// User canceled?
if (destination.isEmpty())
return;
// File already existing? Ask for overriding:
if (dir.exists(destination)) {
int result = KMessageBox::questionYesNoCancel(
0,
"<qt>" + i18n("The file <b>%1</b> already exists. Do you really want to override it?")
.arg(KURL(destination).fileName()),
i18n("Override File?"),
KGuiItem(i18n("&Override"), "filesave")
);
if (result == KMessageBox::Cancel)
return;
else if (result == KMessageBox::Yes)
askAgain = false;
} else
askAgain = false;
}
// Create the progress dialog that will always be shown during the export:
KProgressDialog dialog(0, 0, i18n("Export to HTML"), i18n("Exporting to HTML. Please wait..."), /*Not modal, for password dialogs!*/false);
dialog.showCancelButton(false);
dialog.setAutoClose(true);
dialog.show();
progress = dialog.progressBar();
// Remember the last folder used for HTML exporation:
config->writeEntry("lastFolder", KURL(destination).directory());
config->sync();
prepareExport(basket, destination);
exportBasket(basket, /*isSubBasket*/false);
progress->advance(1); // Finishing finished
}
HTMLExporter::~HTMLExporter()
{
}
void HTMLExporter::prepareExport(Basket *basket, const QString &fullPath)
{
progress->setTotalSteps(/*Preparation:*/1 + /*Finishing:*/1 + /*Basket:*/1 + /*SubBaskets:*/Global::bnpView->basketCount(Global::bnpView->listViewItemForBasket(basket)));
progress->setValue(0);
kapp->processEvents();
// Remember the file path choosen by the user:
filePath = fullPath;
fileName = KURL(fullPath).fileName();
exportedBasket = basket;
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
withBasketTree = (item->firstChild() != 0);
// Create and empty the files folder:
QString filesFolderPath = i18n("HTML export folder (files)", "%1_files").arg(filePath) + "/"; // eg.: "/home/seb/foo.html_files/"
Tools::deleteRecursively(filesFolderPath);
QDir dir;
dir.mkdir(filesFolderPath);
// Create sub-folders:
iconsFolderPath = filesFolderPath + i18n("HTML export folder (icons)", "icons") + "/"; // eg.: "/home/seb/foo.html_files/icons/"
imagesFolderPath = filesFolderPath + i18n("HTML export folder (images)", "images") + "/"; // eg.: "/home/seb/foo.html_files/images/"
basketsFolderPath = filesFolderPath + i18n("HTML export folder (baskets)", "baskets") + "/"; // eg.: "/home/seb/foo.html_files/baskets/"
dir.mkdir(iconsFolderPath);
dir.mkdir(imagesFolderPath);
dir.mkdir(basketsFolderPath);
progress->advance(1); // Preparation finished
}
#include <iostream>
void HTMLExporter::exportBasket(Basket *basket, bool isSubBasket)
{
if (!basket->isLoaded()) {
basket->load();
}
// Compute the absolute & relative paths for this basket:
filesFolderPath = i18n("HTML export folder (files)", "%1_files").arg(filePath) + "/";
if (isSubBasket) {
basketFilePath = basketsFolderPath + basket->folderName().left(basket->folderName().length() - 1) + ".html";
filesFolderName = "../";
dataFolderName = basket->folderName().left(basket->folderName().length() - 1) + "-" + i18n("HTML export folder (data)", "data") + "/";
dataFolderPath = basketsFolderPath + dataFolderName;
basketsFolderName = "";
} else {
basketFilePath = filePath;
filesFolderName = i18n("HTML export folder (files)", "%1_files").arg(KURL(filePath).fileName()) + "/";
dataFolderName = filesFolderName + i18n("HTML export folder (data)", "data") + "/";
dataFolderPath = filesFolderPath + i18n("HTML export folder (data)", "data") + "/";
basketsFolderName = filesFolderName + i18n("HTML export folder (baskets)", "baskets") + "/";
}
iconsFolderName = (isSubBasket ? "../" : filesFolderName) + i18n("HTML export folder (icons)", "icons") + "/"; // eg.: "foo.html_files/icons/" or "../icons/"
imagesFolderName = (isSubBasket ? "../" : filesFolderName) + i18n("HTML export folder (images)", "images") + "/"; // eg.: "foo.html_files/images/" or "../images/"
std::cout << "Exporting ================================================" << std::endl;
std::cout << " filePath:" << filePath << std::endl;
std::cout << " basketFilePath:" << basketFilePath << std::endl;
std::cout << " filesFolderPath:" << filesFolderPath << std::endl;
std::cout << " filesFolderName:" << filesFolderName << std::endl;
std::cout << " iconsFolderPath:" << iconsFolderPath << std::endl;
std::cout << " iconsFolderName:" << iconsFolderName << std::endl;
std::cout << " imagesFolderPath:" << imagesFolderPath << std::endl;
std::cout << " imagesFolderName:" << imagesFolderName << std::endl;
std::cout << " dataFolderPath:" << dataFolderPath << std::endl;
std::cout << " dataFolderName:" << dataFolderName << std::endl;
std::cout << " basketsFolderPath:" << basketsFolderPath << std::endl;
std::cout << " basketsFolderName:" << basketsFolderName << std::endl;
// Create the data folder for this basket:
QDir dir;
dir.mkdir(dataFolderPath);
backgroundColorName = basket->backgroundColor().name().lower().mid(1);
// Generate basket icons:
QString basketIcon16 = iconsFolderName + copyIcon(basket->icon(), 16);
QString basketIcon32 = iconsFolderName + copyIcon(basket->icon(), 32);
// Generate the [+] image for groups:
QPixmap expandGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
expandGroup.fill(basket->backgroundColor());
QPainter painter(&expandGroup);
Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/true, basket);
painter.end();
expandGroup.save(imagesFolderPath + "expand_group_" + backgroundColorName + ".png", "PNG");
// Generate the [-] image for groups:
QPixmap foldGroup(Note::EXPANDER_WIDTH, Note::EXPANDER_HEIGHT);
foldGroup.fill(basket->backgroundColor());
painter.begin(&foldGroup);
Note::drawExpander(&painter, 0, 0, basket->backgroundColor(), /*expand=*/false, basket);
painter.end();
foldGroup.save(imagesFolderPath + "fold_group_" + backgroundColorName + ".png", "PNG");
// Open the file to write:
QFile file(basketFilePath);
if (!file.open(IO_WriteOnly))
return;
stream.setDevice(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
// Compute the colors to draw dragient for notes:
QColor topBgColor;
QColor bottomBgColor;
Note::getGradientColors(basket->backgroundColor(), &topBgColor, &bottomBgColor);
// Compute the gradient image for notes:
QString gradientImageFileName = Basket::saveGradientBackground(basket->backgroundColor(), basket->QScrollView::font(), imagesFolderPath);
// Output the header:
QString borderColor = Tools::mixColor(basket->backgroundColor(), basket->textColor()).name();
stream <<
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
"<html>\n"
" <head>\n"
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"
" <meta name=\"Generator\" content=\"" << kapp->aboutData()->programName() << " " << VERSION << " http://basket.kde.org/\">\n"
" <style type=\"text/css\">\n"
// " @media print {\n"
// " span.printable { display: inline; }\n"
// " }\n"
" body { margin: 10px; font: 11px sans-serif; }\n" // TODO: Use user font
" h1 { text-align: center; }\n"
" img { border: none; vertical-align: middle; }\n";
if (withBasketTree) {
stream <<
" .tree { margin: 0; padding: 1px 0 1px 1px; width: 150px; _width: 149px; overflow: hidden; float: left; }\n"
" .tree ul { margin: 0 0 0 10px; padding: 0; }\n"
" .tree li { padding: 0; margin: 0; list-style: none; }\n"
" .tree a { display: block; padding: 1px; height: 16px; text-decoration: none;\n"
" white-space: nowrap; word-wrap: normal; text-wrap: suppress; color: black; }\n"
" .tree span { -moz-border-radius: 6px; display: block; float: left;\n"
" line-height: 16px; height: 16px; vertical-align: middle; padding: 0 1px; }\n"
" .tree img { vertical-align: top; padding-right: 1px; }\n"
" .tree .current { background-color: " << KGlobalSettings::highlightColor().name() << "; "
"-moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; color: " << KGlobalSettings::highlightedTextColor().name() << "; }\n"
" .basketSurrounder { margin-left: 152px; _margin: 0; _float: right; }\n";
}
stream <<
" .basket { background-color: " << basket->backgroundColor().name() << "; border: solid " << borderColor << " 1px; "
"font: " << Tools::cssFontDefinition(basket->QScrollView::font()) << "; color: " << basket->textColor().name() << "; padding: 1px; width: 100%; }\n"
" table.basket { border-collapse: collapse; }\n"
" .basket * { padding: 0; margin: 0; }\n"
" .basket table { width: 100%; border-spacing: 0; _border-collapse: collapse; }\n"
" .column { vertical-align: top; }\n"
" .columnHandle { width: " << Note::RESIZER_WIDTH << "px; background: transparent url('" << imagesFolderName << "column_handle_" << backgroundColorName << ".png') repeat-y; }\n"
" .group { margin: 0; padding: 0; border-collapse: collapse; width: 100% }\n"
" .groupHandle { margin: 0; width: " << Note::GROUP_WIDTH << "px; text-align: center; }\n"
" .note { padding: 1px 2px; background: " << bottomBgColor.name() << " url('" << imagesFolderName << gradientImageFileName << "')"
" repeat-x; border-top: solid " << topBgColor.name() <<
" 1px; border-bottom: solid " << Tools::mixColor(topBgColor, bottomBgColor).name() <<
" 1px; width: 100%; }\n"
" .tags { width: 1px; white-space: nowrap; }\n"
" .tags img { padding-right: 2px; }\n"
<< LinkLook::soundLook->toCSS("sound", basket->textColor())
<< LinkLook::fileLook->toCSS("file", basket->textColor())
<< LinkLook::localLinkLook->toCSS("local", basket->textColor())
<< LinkLook::networkLinkLook->toCSS("network", basket->textColor())
<< LinkLook::launcherLook->toCSS("launcher", basket->textColor())
<<
" .unknown { margin: 1px 2px; border: 1px solid " << borderColor << "; -moz-border-radius: 4px; }\n";
QValueList<State*> states = basket->usedStates();
QString statesCss;
for (State::List::Iterator it = states.begin(); it != states.end(); ++it)
statesCss += (*it)->toCSS(imagesFolderPath, imagesFolderName, basket->QScrollView::font());
stream <<
statesCss <<
" .credits { text-align: right; margin: 3px 0 0 0; _margin-top: -17px; font-size: 80%; color: " << borderColor << "; }\n"
" </style>\n"
" <title>" << Tools::textToHTMLWithoutP(basket->basketName()) << "</title>\n"
" <link rel=\"shortcut icon\" type=\"image/png\" href=\"" << basketIcon16 << "\">\n";
// Create the column handle image:
QPixmap columnHandle(Note::RESIZER_WIDTH, 50);
painter.begin(&columnHandle);
Note::drawInactiveResizer(&painter, 0, 0, columnHandle.height(), basket->backgroundColor(), /*column=*/true);
painter.end();
columnHandle.save(imagesFolderPath + "column_handle_" + backgroundColorName + ".png", "PNG");
stream <<
" </head>\n"
" <body>\n"
" <h1><img src=\"" << basketIcon32 << "\" width=\"32\" height=\"32\" alt=\"\"> " << Tools::textToHTMLWithoutP(basket->basketName()) << "</h1>\n";
if (withBasketTree)
writeBasketTree(basket);
// If filtering, only export filtered notes, inform to the user:
// TODO: Filtering tags too!!
// TODO: Make sure only filtered notes are exported!
// if (decoration()->filterData().isFiltering)
// stream <<
// " <p>" << i18n("Notes matching the filter &quot;%1&quot;:").arg(Tools::textToHTMLWithoutP(decoration()->filterData().string)) << "</p>\n";
stream <<
" <div class=\"basketSurrounder\">\n";
if (basket->isColumnsLayout())
stream <<
" <table class=\"basket\">\n"
" <tr>\n";
else
stream <<
" <div class=\"basket\" style=\"position: relative; height: " << basket->contentsHeight() << "px; width: " << basket->contentsWidth() << "px; min-width: 100%;\">\n";
for (Note *note = basket->firstNote(); note; note = note->next())
exportNote(note, /*indent=*/(basket->isFreeLayout() ? 4 : 5));
// Output the footer:
if (basket->isColumnsLayout())
stream <<
" </tr>\n"
" </table>\n";
else
stream <<
" </div>\n";
stream << QString(
" </div>\n"
" <p class=\"credits\">%1</p>\n").arg(
i18n("Made with %1, a KDE tool to take notes and keep information at hand.")
.arg("<a href=\"http://basket.kde.org/\">%1</a> %2")
.arg(kapp->aboutData()->programName(), VERSION));
// Copy a transparent GIF image in the folder, needed for the JavaScript hack:
QString gifFileName = "spacer.gif";
QFile transGIF(imagesFolderPath + gifFileName);
if (!transGIF.exists() && transGIF.open(IO_WriteOnly)) {
QDataStream streamGIF(&transGIF);
// This is a 1px*1px transparent GIF image:
const uchar blankGIF[] = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x0a, 0x00, 0x0a, 0x00,
0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x21,
0xfe, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47,
0x49, 0x4d, 0x50, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00,
0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
0x00, 0x00, 0x02, 0x08, 0x8c, 0x8f, 0xa9, 0xcb, 0xed, 0x0f,
0x63, 0x2b, 0x00, 0x3b };
streamGIF.writeRawBytes((const char*)blankGIF, (unsigned int)74);
transGIF.close();
}
stream <<
" <!--[if lt IE 7]>\n"
" <script>\n"
" function fixPng(img) {\n"
" if (!img.style.filter) {\n"
" img.style.filter = \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='\" + img.src + \"')\";\n"
" img.src = \"" << imagesFolderName << gifFileName << "\";\n"
" }\n"
" }\n"
" for (i = document.images.length - 1; i >= 0; i -= 1) {\n"
" var img = document.images[i];\n"
" if (img.src.substr(img.src.length - 4) == \".png\")\n"
" if (img.complete)\n"
" fixPng(img);\n"
" else\n"
" img.attachEvent(\"onload\", function() { fixPng(window.event.srcElement); });\n"
" }\n"
" </script>\n"
" <![endif]-->\n"
" </body>\n"
"</html>\n";
file.close();
stream.unsetDevice();
progress->advance(1); // Basket exportation finished
// Recursively export child baskets:
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
if (item->firstChild()) {
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
exportBasket(child->basket(), /*isSubBasket=*/true);
}
}
}
void HTMLExporter::exportNote(Note *note, int indent)
{
QString spaces;
if (note->isColumn()) {
QString width = "";
if (false/*TODO: DEBUG AND REENABLE: hasResizer()*/) {
// As we cannot be precise in CSS (say eg. "width: 50%-40px;"),
// we output a percentage that is approximatively correct.
// For instance, we compute the currently used percentage of width in the basket
// and try make make it the same on a 1024*768 display in a Web browser:
int availableSpaceForColumnsInThisBasket = note->basket()->contentsWidth() - (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
int availableSpaceForColumnsInBrowser = 1024 /* typical screen width */
- 25 /* window border and scrollbar width */
- 2 * 5 /* page margin */
- (note->basket()->columnsCount() - 1) * Note::RESIZER_WIDTH;
if (availableSpaceForColumnsInThisBasket <= 0)
availableSpaceForColumnsInThisBasket = 1;
int widthValue = (int)(availableSpaceForColumnsInBrowser * (double) note->groupWidth() / availableSpaceForColumnsInThisBasket);
if (widthValue <= 0)
widthValue = 1;
if (widthValue > 100)
widthValue = 100;
width = QString(" width=\"%1%\"").arg(QString::number(widthValue));
}
stream << spaces.fill(' ', indent) << "<td class=\"column\"" << width << ">\n";
// Export child notes:
for (Note *child = note->firstChild(); child; child = child->next()) {
stream << spaces.fill(' ', indent + 1);
exportNote(child, indent + 1);
stream << '\n';
}
stream << spaces.fill(' ', indent) << "</td>\n";
if (note->hasResizer())
stream << spaces.fill(' ', indent) << "<td class=\"columnHandle\"></td>\n";
return;
}
QString freeStyle;
if (note->isFree())
freeStyle = " style=\"position: absolute; left: " + QString::number(note->x()) + "px; top: " + QString::number(note->y()) + "px; width: " + QString::number(note->groupWidth()) + "px\"";
if (note->isGroup()) {
stream << '\n' << spaces.fill(' ', indent) << "<table" << freeStyle << ">\n"; // Note content is expected to be on the same HTML line, but NOT groups
int i = 0;
for (Note *child = note->firstChild(); child; child = child->next()) {
stream << spaces.fill(' ', indent);
if (i == 0)
stream << " <tr><td class=\"groupHandle\"><img src=\"" << imagesFolderName << (note->isFolded() ? "expand_group_" : "fold_group_") << backgroundColorName << ".png"
<< "\" width=\"" << Note::EXPANDER_WIDTH << "\" height=\"" << Note::EXPANDER_HEIGHT << "\"></td>\n";
else if (i == 1)
stream << " <tr><td class=\"freeSpace\" rowspan=\"" << note->countDirectChilds() << "\"></td>\n";
else
stream << " <tr>\n";
stream << spaces.fill(' ', indent) << " <td>";
exportNote(child, indent + 3);
stream << "</td>\n"
<< spaces.fill(' ', indent) << " </tr>\n";
++i;
}
stream << '\n' << spaces.fill(' ', indent) << "</table>\n" /*<< spaces.fill(' ', indent - 1)*/;
} else {
// Additionnal class for the content (link, netword, color...):
QString additionnalClasses = note->content()->cssClass();
if (!additionnalClasses.isEmpty())
additionnalClasses = " " + additionnalClasses;
// Assign the style of each associted tags:
for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
additionnalClasses += " tag_" + (*it)->id();
//stream << spaces.fill(' ', indent);
stream << "<table class=\"note" << additionnalClasses << "\"" << freeStyle << "><tr>";
if (note->emblemsCount() > 0) {
stream << "<td class=\"tags\"><nobr>";
for (State::List::Iterator it = note->states().begin(); it != note->states().end(); ++it)
if (!(*it)->emblem().isEmpty()) {
int emblemSize = 16;
QString iconFileName = copyIcon((*it)->emblem(), emblemSize);
stream << "<img src=\"" << iconsFolderName << iconFileName
<< "\" width=\"" << emblemSize << "\" height=\"" << emblemSize
<< "\" alt=\"" << (*it)->textEquivalent() << "\" title=\"" << (*it)->fullName() << "\">";
}
stream << "</nobr></td>";
}
stream << "<td>";
note->content()->exportToHTML(this, indent);
stream << "</td></tr></table>";
}
}
void HTMLExporter::writeBasketTree(Basket *currentBasket)
{
stream << " <ul class=\"tree\">\n";
writeBasketTree(currentBasket, exportedBasket, 3);
stream << " </ul>\n";
}
void HTMLExporter::writeBasketTree(Basket *currentBasket, Basket *basket, int indent)
{
// Compute variable HTML code:
QString spaces;
QString cssClass = (basket == currentBasket ? " class=\"current\"" : "");
QString link = "#";
if (currentBasket != basket) {
if (currentBasket == exportedBasket) {
link = basketsFolderName + basket->folderName().left(basket->folderName().length() - 1) + ".html";
} else if (basket == exportedBasket) {
link = "../../" + fileName;
} else {
link = basket->folderName().left(basket->folderName().length() - 1) + ".html";
}
}
QString spanStyle = "";
if (basket->backgroundColorSetting().isValid() || basket->textColorSetting().isValid()) {
spanStyle = " style=\"background-color: " + basket->backgroundColor().name() + "; color: " + basket->textColor().name() + "\"";
}
// Write the basket tree line:
stream <<
spaces.fill(' ', indent) << "<li><a" << cssClass << " href=\"" << link << "\">"
"<span" << spanStyle << " title=\"" << Tools::textToHTMLWithoutP(basket->basketName()) << "\">"
"<img src=\"" << iconsFolderName << copyIcon(basket->icon(), 16) << "\" width=\"16\" height=\"16\" alt=\"\">" << Tools::textToHTMLWithoutP(basket->basketName()) << "</span></a>";
// Write the sub-baskets lines & end the current one:
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
if (item->firstChild() != 0) {
stream <<
"\n" <<
spaces.fill(' ', indent) << " <ul>\n";
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling())
writeBasketTree(currentBasket, child->basket(), indent + 2);
stream <<
spaces.fill(' ', indent) << " </ul>\n" <<
spaces.fill(' ', indent) << "</li>\n";
} else {
stream << "</li>\n";
}
}
/** Save an icon to a folder.
* If an icon with the same name already exist in the destination,
* it is assumed the icon is already copied, so no action is took.
* It is optimized so that you can have an empty folder receiving the icons
* and call copyIcon() each time you encounter one during export process.
*/
QString HTMLExporter::copyIcon(const QString &iconName, int size)
{
if (iconName.isEmpty())
return "";
// Sometimes icon can be "favicons/www.kde.org", we replace the '/' with a '_'
QString fileName = iconName; // QString::replace() isn't const, so I must copy the string before
fileName = "ico" + QString::number(size) + "_" + fileName.replace("/", "_") + ".png";
QString fullPath = iconsFolderPath + fileName;
if (!QFile::exists(fullPath))
DesktopIcon(iconName, size).save(fullPath, "PNG");
return fileName;
}
/** Done: Sometimes we can call two times copyFile() with the same srcPath and dataFolderPath
* (eg. when exporting basket to HTML with two links to same filename
* (but not necesary same path, as in "/home/foo.txt" and "/foo.txt") )
* The first copy isn't yet started, so the dest file isn't created and this method
* returns the same filename !!!!!!!!!!!!!!!!!!!!
*/
QString HTMLExporter::copyFile(const QString &srcPath, bool createIt)
{
QString fileName = Tools::fileNameForNewFile(KURL(srcPath).fileName(), dataFolderPath);
QString fullPath = dataFolderPath + fileName;
if (createIt) {
// We create the file to be sure another very near call to copyFile() willn't choose the same name:
QFile file(KURL(fullPath).path());
if (file.open(IO_WriteOnly))
file.close();
// And then we copy the file AND overwriting the file we juste created:
new KIO::FileCopyJob(
KURL(srcPath), KURL(fullPath), 0666, /*move=*/false,
/*overwrite=*/true, /*resume=*/true, /*showProgress=*/false );
} else
/*KIO::CopyJob *copyJob = */KIO::copy(KURL(srcPath), KURL(fullPath)); // Do it as before
return fileName;
}

@ -0,0 +1,79 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef HTMLEXPORTER_H
#define HTMLEXPORTER_H
#include <qstring.h>
#include <qtextstream.h>
class KProgress;
class Basket;
class Note;
/**
* @author Sébastien Laoût <slaout@linux62.org>
*/
class HTMLExporter
{
public:
HTMLExporter(Basket *basket);
~HTMLExporter();
private:
void prepareExport(Basket *basket, const QString &fullPath);
void exportBasket(Basket *basket, bool isSubBasket);
void exportNote(Note *note, int indent);
void writeBasketTree(Basket *currentBasket);
void writeBasketTree(Basket *currentBasket, Basket *basket, int indent);
public:
QString copyIcon(const QString &iconName, int size);
QString copyFile(const QString &srcPath, bool createIt);
public:
// Absolute path of the file name the user choosen:
QString filePath; // eg.: "/home/seb/foo.html"
QString fileName; // eg.: "foo.html"
// Absolute & relative paths for the current basket to be exported:
QString basketFilePath; // eg.: "/home/seb/foo.html" or "/home/seb/foo.html_files/baskets/basketN.html"
QString filesFolderPath; // eg.: "/home/seb/foo.html_files/"
QString filesFolderName; // eg.: "foo.html_files/" or "../"
QString iconsFolderPath; // eg.: "/home/seb/foo.html_files/icons/"
QString iconsFolderName; // eg.: "foo.html_files/icons/" or "../icons/"
QString imagesFolderPath; // eg.: "/home/seb/foo.html_files/images/"
QString imagesFolderName; // eg.: "foo.html_files/images/" or "../images/"
QString dataFolderPath; // eg.: "/home/seb/foo.html_files/data/" or "/home/seb/foo.html_files/baskets/basketN-data/"
QString dataFolderName; // eg.: "foo.html_files/data/" or "basketN-data/"
QString basketsFolderPath; // eg.: "/home/seb/foo.html_files/baskets/"
QString basketsFolderName; // eg.: "foo.html_files/baskets/" or ""
// Various properties of the currently exporting basket:
QString backgroundColorName;
// Variables used by every export methods:
QTextStream stream;
Basket *exportedBasket;
bool withBasketTree;
KProgress *progress;
};
#endif // HTMLEXPORTER_H

@ -0,0 +1,72 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
// This must be first
#include <config.h>
#include "settings.h"
#include <kcmodule.h>
//----------------------------
// KCM stuff
//----------------------------
extern "C"
{
KDE_EXPORT KCModule *create_basket_config_general(QWidget *parent, const char *)
{
GeneralPage *page = new GeneralPage(parent, "kcmbasket_config_general");
return page;
}
}
extern "C"
{
KDE_EXPORT KCModule *create_basket_config_baskets(QWidget *parent, const char *)
{
BasketsPage *page = new BasketsPage(parent, "kcmbasket_config_baskets");
return page;
}
}
extern "C"
{
KDE_EXPORT KCModule *create_basket_config_new_notes(QWidget *parent, const char *)
{
NewNotesPage *page = new NewNotesPage(parent, "kcmbasket_config_new_notes");
return page;
}
}
extern "C"
{
KDE_EXPORT KCModule *create_basket_config_notes_appearance(QWidget *parent, const char *)
{
NotesAppearancePage *page = new NotesAppearancePage(parent, "kcmbasket_config_notes_appearance");
return page;
}
}
extern "C"
{
KDE_EXPORT KCModule *create_basket_config_apps(QWidget *parent, const char *)
{
ApplicationsPage *page = new ApplicationsPage(parent, "kcmbasket_config_apps");
return page;
}
}

@ -0,0 +1,769 @@
/***************************************************************************
* Copyright (C) 2005 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qapplication.h>
#include <qpixmap.h>
#include <qbitmap.h>
#include <qpainter.h>
#include <qlistbox.h>
#include <kglobalsettings.h>
#include <klocale.h>
#include <kcolordialog.h>
#include <qclipboard.h>
#include <kstdaccel.h>
#include <kcolordrag.h>
#include "kcolorcombo2.h"
//#include "qeffects.h"
//#define DEBUG_COLOR_ARRAY
//#define OUTPUT_GIMP_PALETTE
#ifdef DEBUG_COLOR_ARRAY
#include <iostream>
#include <iomanip>
#endif
#ifdef OUTPUT_GIMP_PALETTE
#include <iostream>
#include <iomanip>
#endif
/** class KColorPopup: */
const int KColorPopup::MARGIN = 1;
const int KColorPopup::FRAME_WIDTH = 1;
KColorPopup::KColorPopup(KColorCombo2 *parent)
: QWidget(/*parent=*/0, /*name=*/0, WType_Popup | WNoAutoErase),
m_selector(parent)
{
hide();
setMouseTracking(true);
//resize(20, 20);
//setWFlags(Qt::WNoAutoErase);
}
KColorPopup::~KColorPopup()
{
}
#include <qcursor.h>
void KColorPopup::relayout() // FIXME: relayout should NOT redraw the pixmap!
{
int columnCount = m_selector->columnCount();
int rowCount = m_selector->rowCount();
int colorHeight = m_selector->colorRectHeight();
int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
bool haveDefault = m_selector->defaultColor().isValid();
int width = 2 + MARGIN + (colorWidth + MARGIN) * columnCount;
int height = 2 + MARGIN + (colorHeight + MARGIN) * rowCount + (colorHeight + MARGIN);
resize(width, height);
// Initialize the pixmap:
m_pixmap.resize(width, height);
QPainter painter(&m_pixmap);
painter.fillRect(0, 0, width, height, KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, width, height);
// Needed to draw:
int x, y;
QRect selectionRect;
// Draw the color array:
for (int i = 0; i < columnCount; ++i) {
for (int j = 0; j < rowCount; ++j) {
x = 1 + MARGIN + (colorWidth + MARGIN) * i;
y = 1 + MARGIN + (colorHeight + MARGIN) * j;
if (i == m_selectedColumn && j == m_selectedRow) {
selectionRect = QRect(x - 2, y - 2, colorWidth + 4, colorHeight + 4);
painter.fillRect(selectionRect, KGlobalSettings::highlightColor());
}
m_selector->drawColorRect(painter, x, y, m_selector->colorAt(i, j), /*isDefault=*/false, colorWidth, colorHeight);
}
}
m_columnOther = (haveDefault ? columnCount / 2 : 0); // "(Default)" is allowed, paint "Other..." on the right
int defaultCellWidth = (colorWidth + MARGIN) * m_columnOther;
int otherCellWidth = (colorWidth + MARGIN) * (columnCount - m_columnOther);
// Draw the "(Default)" and "Other..." colors:
y = height - (colorHeight + MARGIN) - 1;
QColor textColor;
if (m_selector->defaultColor().isValid()) {
x = 1 + MARGIN;
if (m_selectedColumn < m_columnOther && rowCount == m_selectedRow) {
selectionRect = QRect(x - 2, y - 2, defaultCellWidth, colorHeight + 4);
painter.fillRect(selectionRect, KGlobalSettings::highlightColor());
textColor = KGlobalSettings::highlightedTextColor();
} else
textColor = KGlobalSettings::textColor();
m_selector->drawColorRect(painter, x, y, m_selector->defaultColor(), /*isDefault=*/true, colorWidth, colorHeight);
painter.setFont(m_selector->font());
painter.setPen(textColor);
painter.drawText(x + 2 + colorWidth, y, /*width=*/5000, colorHeight, AlignLeft | AlignVCenter | DontClip, i18n("(Default)"));
}
x = 1 + MARGIN + m_columnOther * (colorWidth + MARGIN);
if (m_selectedColumn >= m_columnOther && rowCount == m_selectedRow) {
selectionRect = QRect(x - 2, y - 2, otherCellWidth, colorHeight + 4);
painter.fillRect(selectionRect, KGlobalSettings::highlightColor());
textColor = KGlobalSettings::highlightedTextColor();
} else
textColor = KGlobalSettings::textColor();
m_selector->drawColorRect(painter, x, y, m_otherColor, /*isDefault=*/false, colorWidth, colorHeight);
painter.setFont(m_selector->font());
painter.setPen(textColor);
painter.drawText(x + 2 + colorWidth, y, /*width=*/5000, colorHeight, AlignLeft | AlignVCenter | DontClip, i18n("Other..."));
// QPoint pos = mapFromGlobal(QCursor::pos());
// painter.drawRect(pos.x(), pos.y(), 5000, 5000);
}
void KColorPopup::updateCell(int column, int row)
{
int colorHeight = m_selector->colorRectHeight();
int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
int x = 1 + MARGIN + - 2 + column * (colorWidth + MARGIN);
int y = 1 + MARGIN + - 2 + row * (colorHeight + MARGIN);
int width = colorWidth + MARGIN;
int height = colorHeight + MARGIN;
if (row == m_selector->rowCount()) {
if (m_selectedColumn < m_columnOther) // The "(Default)" cell:
width = (colorWidth + MARGIN) * m_columnOther;
else // The "Other..." cell:
width = (colorWidth + MARGIN) * (m_selector->columnCount() - m_columnOther);
}
update(x, y, width, height);
}
void KColorPopup::doSelection()
{
m_otherColor = QColor();
// If the selected color is not the default one, try to find it in the array:
if (m_selector->color().isValid()) {
bool isInArray = false;
for (int column = 0; column < m_selector->columnCount(); ++column)
for (int row = 0; row < m_selector->rowCount(); ++row)
if (m_selector->color() == m_selector->colorAt(column, row)) {
m_selectedColumn = column;
m_selectedRow = row;
isInArray = true;
}
// If not found in array, it's another one:
if (!isInArray) {
m_selectedColumn = m_columnOther;
m_selectedRow = m_selector->rowCount();
m_otherColor = m_selector->color();
}
// If it's the default one:
} else {
m_selectedColumn = 0;
m_selectedRow = m_selector->rowCount();
}
}
void KColorPopup::validate()
{
hide();
close();
if (m_selectedRow != m_selector->rowCount()) // A normal row:
m_selector->setColor(m_selector->colorAt(m_selectedColumn, m_selectedRow));
else if (m_selectedColumn < m_columnOther) // The default color:
m_selector->setColor(QColor());
else { // The user want to choose one:
QColor color = m_selector->effectiveColor();
if (KColorDialog::getColor(color, this) == QDialog::Accepted)
m_selector->setColor(color);
}
}
void KColorPopup::mousePressEvent(QMouseEvent *event)
{
int x = event->pos().x();
int y = event->pos().y();
if (x < 0 || y < 0 || x >= width() || y >= height()) {
hide();
close();
} else
validate();
event->accept();
}
void KColorPopup::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.drawPixmap(0, 0, m_pixmap);
painter.setPen(Qt::black);
painter.drawRect(event->rect());
}
void KColorPopup::mouseMoveEvent(QMouseEvent *event)
{
int x = event->pos().x();
int y = event->pos().y();
if (x < FRAME_WIDTH + 2 || y < FRAME_WIDTH + 2 || x > width() - 2 - 2*FRAME_WIDTH || y > height() - 2 - 2*FRAME_WIDTH)
return;
int colorHeight = m_selector->colorRectHeight();
int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
// int oldSelectedColumn = m_selectedColumn;
// int oldSelectedRow = m_selectedRow;
m_selectedColumn = (x - FRAME_WIDTH - MARGIN + 2) / (colorWidth + MARGIN);
m_selectedRow = (y - FRAME_WIDTH - MARGIN + 2) / (colorHeight + MARGIN);
relayout();
update();
}
void KColorPopup::keyPressEvent(QKeyEvent *event)
{
int column = m_selectedColumn;
int row = m_selectedRow;
int columnCount = m_selector->columnCount();
int rowCount = m_selector->rowCount();
switch (event->key()) {
case Qt::Key_Right:
if (m_selectedRow != rowCount) // A normal row:
column = (column + 1) % columnCount;
else {
// The last row, if there are two choices, switch. Else, do nothing:
if (m_selector->defaultColor().isValid())
column = (m_selectedColumn < m_columnOther ? m_columnOther : 0);
}
break;
case Qt::Key_Left:
if (m_selectedRow != rowCount) { // A normal row:
column = (column - 1);
if (column < 0)
column = columnCount - 1;
} else {
// The last row, if there are two choices, switch. Else, do nothing:
if (m_selector->defaultColor().isValid())
column = (m_selectedColumn < m_columnOther ? m_columnOther : 0);
}
break;
case Qt::Key_Up: row = (row - 1); if (row < 0) row = rowCount; break;
case Qt::Key_Down: row = (row + 1) % (rowCount+1); break;
case Qt::Key_PageDown: row += 10; if (row > rowCount) row = rowCount; break;
case Qt::Key_PageUp: row -= 10; if (row < 0) row = 0; break;
case Qt::Key_Home: row = 0; column = 0; break;
case Qt::Key_End: row = rowCount; column = columnCount - 1; break;
case Qt::Key_Return:
validate();
break;
default:
QWidget::keyPressEvent(event);
}
if (row != m_selectedRow || column != m_selectedColumn) {
m_selectedRow = row;
m_selectedColumn = column;
relayout();
update();
}
}
/** Helper function: */
QColor Tool_mixColors(const QColor &color1, const QColor &color2)
{
QColor mixedColor;
mixedColor.setRgb( (color1.red() + color2.red()) / 2,
(color1.green() + color2.green()) / 2,
(color1.blue() + color2.blue()) / 2 );
return mixedColor;
}
/** class KColorCombo2Private */
class KColorCombo2::KColorCombo2Private
{
};
/** class KColorCombo2: */
/* All code for the popup management (including the constructor, popup() and eventFilter())
* has been copied from the KDateEdit widget (in libkdepim).
*
* Some other piece of code comes from KColorButton (in libkdeui) to enable color drag, drop, copy and paste.
*/
KColorCombo2::KColorCombo2(const QColor &color, const QColor &defaultColor, QWidget *parent, const char *name)
: QComboBox(/*editable=*/false, parent, name),
m_color(color), m_defaultColor(defaultColor)
{
init();
}
KColorCombo2::KColorCombo2(const QColor &color, QWidget *parent, const char *name)
: QComboBox(/*editable=*/false, parent, name),
m_color(color), m_defaultColor()
{
init();
}
void KColorCombo2::init()
{
m_discardNextMousePress = false;
m_colorArray = 0;
d = new KColorCombo2Private();
setDefaultColor(m_defaultColor);
insertItem("", /*index=*/0);
updateComboBox(); // It need an item of index 0 to exists, so we created it.
setAcceptDrops(true);
m_popup = new KColorPopup(this);
m_popup->installEventFilter(this);
// By default, the array is filled with setRainbowPreset().
// But we allocate it on demand (the later as possible) to avoid performances issues if the developer set another array.
// However, to keep columnCount() rowCount() const, we define theme here:
m_columnCount = 13;
m_rowCount = 9;
}
KColorCombo2::~KColorCombo2()
{
deleteColorArray();
}
void KColorCombo2::setColor(const QColor &color)
{
// Do nothing if the color should be set to the default one and there is no such default color allowed:
if (!color.isValid() && !m_defaultColor.isValid()) {
// kdebug << this::FUNCTION << "Trying to assign the default color (an invalid one) whereas no such default color is allowed";
return;
}
if (m_color != color) {
m_color = color;
updateComboBox();
emit changed(color);
}
}
QColor KColorCombo2::color() const
{
return m_color;
}
QColor KColorCombo2::effectiveColor() const
{
if (m_color.isValid())
return m_color;
else
return m_defaultColor;
}
void KColorCombo2::setRainbowPreset(int colorColumnCount, int lightRowCount, int darkRowCount, bool withGray)
{
// At least one row and one column:
if (colorColumnCount < 1 - (withGray ? 1 : 0))
colorColumnCount = 1 - (withGray ? 1 : 0);
if (lightRowCount < 0)
lightRowCount = 0;
if (darkRowCount < 0)
darkRowCount = 0;
// Create the array:
int columnCount = colorColumnCount + (withGray ? 1 : 0);
int rowCount = lightRowCount + 1 + darkRowCount;
newColorArray(columnCount, rowCount);
// Fill the array:
for (int i = 0; i < colorColumnCount; ++i) {
int hue = i * 360 / colorColumnCount;
// With light colors:
for (int j = 1; j <= lightRowCount; ++j) { // Start to 1 because we don't want a row full of white!
int saturation = j * 255 / (lightRowCount + 1);
setColorAt(i, j - 1, QColor(hue, saturation, 255, QColor::Hsv));
}
// With pure colors:
setColorAt(i, lightRowCount, QColor(hue, 255, 255, QColor::Hsv));
// With dark colors:
for (int j = 1; j <= darkRowCount; ++j) {
int value = 255 - j * 255 / (darkRowCount + 1);
setColorAt(i, lightRowCount + j, QColor(hue, 255, value, QColor::Hsv));
}
}
// Fill the gray column:
if (withGray) {
for (int i = 0; i < rowCount; ++i) {
int gray = ( rowCount == 1 ? 128 : 255 - (i * 255 / (rowCount - 1)) );
setColorAt(columnCount-1, i, QColor(gray, gray, gray));
}
}
#ifdef DEBUG_COLOR_ARRAY
std::cout << "KColorCombo2::setColorPreset" << std::endl;
for (int j = 0; j < rowCount; ++j) {
for (int i = 0; i < columnCount; ++i) {
int h, s, v;
m_colorArray[i][j].getHsv(h, s, v);
std::cout << "(" << std::setw(3) << h << "," << std::setw(3) << s << "," << std::setw(3) << v << ") ";
//std::cout << colorArray[i][j].name() << " ";
}
std::cout << std::endl;
}
#endif
#ifdef OUTPUT_GIMP_PALETTE
std::cout << "GIMP Palette" << std::endl;
for (int j = 0; j < rowCount; ++j) {
for (int i = 0; i < columnCount; ++i) {
std::cout << std::setw(3) << m_colorArray[i][j].red() << ", " << std::setw(3) << m_colorArray[i][j].green() << ", " << std::setw(3) << m_colorArray[i][j].blue() << std::endl;
}
}
#endif
}
int KColorCombo2::columnCount() const
{
return m_columnCount;
}
int KColorCombo2::rowCount() const
{
return m_rowCount;
}
QColor KColorCombo2::colorAt(int column, int row)/* const*/
{
if (!m_colorArray)
setRainbowPreset();
if (column < 0 || row < 0 || column >= m_columnCount || row >= m_rowCount)
return QColor();
return m_colorArray[column][row];
}
QColor KColorCombo2::defaultColor() const
{
return m_defaultColor;
}
void KColorCombo2::newColorArray(int columnCount, int rowCount)
{
if (columnCount <= 0 || rowCount <= 0) {
// kdebug << this::FUNCTION << "Trying to create an empty new color array (with %d columns and %d rows)";
return;
}
// Delete any previous array (if any):
deleteColorArray();
// Create a new array of the wanted dimentions:
m_columnCount = columnCount;
m_rowCount = rowCount;
m_colorArray = new QColor* [columnCount];
for (int i = 0; i < columnCount; ++i)
m_colorArray[i] = new QColor[rowCount];
m_popup->relayout();
}
void KColorCombo2::setColorAt(int column, int row, const QColor &color)
{
if (!m_colorArray)
setRainbowPreset();
if (column < 0 || row < 0 || column >= m_columnCount || row >= m_rowCount) {
// kdebug << this::FUNCTION << "Trying to set a color at an invalid index (at column %d and row %d, whereas the array have %d columns and %d rows)";
return;
}
m_colorArray[column][row] = color;
}
void KColorCombo2::setDefaultColor(const QColor &color)
{
m_defaultColor = color;
if (!m_defaultColor.isValid() && !m_color.isValid())
m_color = Qt::white; // FIXME: Use the first one.
}
QPixmap KColorCombo2::colorRectPixmap(const QColor &color, bool isDefault, int width, int height)
{
// Prepare to draw:
QPixmap pixmap(width, height);
QBitmap mask(width, height);
QPainter painter(&pixmap);
QPainter maskPainter(&mask);
// Draw pixmap:
drawColorRect(painter, 0, 0, color, isDefault, width, height);
// Draw mask (make the four corners transparent):
maskPainter.fillRect(0, 0, width, height, Qt::color1); // opaque
maskPainter.setPen(Qt::color0); // transparent
maskPainter.drawPoint(0, 0);
maskPainter.drawPoint(0, height - 1);
maskPainter.drawPoint(width - 1, height - 1);
maskPainter.drawPoint(width - 1, 0);
// Finish:
painter.end();
maskPainter.end();
pixmap.setMask(mask);
return pixmap;
}
void KColorCombo2::drawColorRect(QPainter &painter, int x, int y, const QColor &color, bool isDefault, int width, int height)
{
// Fill:
if (color.isValid())
painter.fillRect(x /*+ 1*/, y /*+ 1*/, width /*- 2*/, height /*- 2*/, color);
else {
// If it's an invalid color, it's for the "Other..." entry: draw a rainbow.
// If it wasn't for the "Other..." entry, the programmer made a fault, so (s)he will be informed about that visually.
for (int i = 0; i < width-2; ++i) {
int hue = i * 360 / (width-2);
for (int j = 0; j < height-2; ++j) {
int saturation = 255 - (j * 255 / (height-2));
painter.setPen( QColor(hue, saturation, /*value=*/255, QColor::Hsv) );
painter.drawPoint(x + i + 1, y + j + 1);
}
}
}
// Stroke:
int dontCare, value;
color.getHsv(/*hue:*/dontCare, /*saturation:*/dontCare, value);
QColor stroke = (color.isValid() ? color.dark(125) : KGlobalSettings::textColor());
painter.setPen(/*color);//*/stroke);
painter.drawLine(x + 1, y, x + width - 2, y);
painter.drawLine(x, y + 1, x, y + height - 2);
painter.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1);
painter.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2);
// Round corners:
QColor antialiasing;
if (color.isValid()) {
antialiasing = Tool_mixColors(color, stroke);
painter.setPen(antialiasing);
painter.drawPoint(x + 1, y + 1);
painter.drawPoint(x + 1, y + height - 2);
painter.drawPoint(x + width - 2, y + height - 2);
painter.drawPoint(x + width - 2, y + 1);
} else {
// The two top corners:
antialiasing = Tool_mixColors(Qt::red, stroke);
painter.setPen(antialiasing);
painter.drawPoint(x + 1, y + 1);
painter.drawPoint(x + width - 2, y + 1);
// The two bottom ones:
antialiasing = Tool_mixColors(Qt::white, stroke);
painter.setPen(antialiasing);
painter.drawPoint(x + 1, y + height - 2);
painter.drawPoint(x + width - 2, y + height - 2);
}
// Mark default color:
if (isDefault) {
painter.setPen(stroke);
painter.drawLine(x + 1, y + height - 2, x + width - 2, y + 1);
}
}
int KColorCombo2::colorRectHeight() const
{
return (fontMetrics().boundingRect(i18n("(Default)")).height() + 2)*3/2;
}
int KColorCombo2::colorRectWidthForHeight(int height) const
{
return height * 14 / 10; // 1.4 times the height, like A4 papers.
}
void KColorCombo2::deleteColorArray()
{
if (m_colorArray) {
for (int i = 0; i < m_columnCount; ++i)
delete[] m_colorArray[i];
delete[] m_colorArray;
m_colorArray = 0;
}
}
void KColorCombo2::updateComboBox()
{
int height = colorRectHeight()*2/3; // fontMetrics().boundingRect(i18n("(Default)")).height() + 2
QPixmap pixmap = colorRectPixmap(effectiveColor(), !m_color.isValid(), colorRectWidthForHeight(height), height); // TODO: isDefaultColorSelected()
changeItem(pixmap, (m_color.isValid() ? "" : i18n("(Default)")), /*index=*/0);
}
void KColorCombo2::popup()
{
if (!m_colorArray)
setRainbowPreset();
// Compute where to show the popup:
QRect desk = KGlobalSettings::desktopGeometry(this);
QPoint popupPoint = mapToGlobal(QPoint(0, 0));
int popupHeight = m_popup->sizeHint().height();
if (popupPoint.y() + height() + popupHeight > desk.bottom())
popupPoint.setY(popupPoint.y() - popupHeight);
else
popupPoint.setY(popupPoint.y() + height());
int popupWidth = m_popup->sizeHint().width();
if (popupPoint.x() + popupWidth > desk.right())
popupPoint.setX(desk.right() - popupWidth);
if (popupPoint.x() < desk.left())
popupPoint.setX(desk.left());
if (popupPoint.y() < desk.top())
popupPoint.setY(desk.top());
// Configure the popup:
m_popup->move(popupPoint);
//m_popup->setColor(m_color);
m_popup->doSelection();
m_popup->relayout(); // FIXME: In aboutToShow() ?
#if 0
//#ifndef QT_NO_EFFECTS
if (QApplication::isEffectEnabled(UI_AnimateCombo)) {
if (m_popup->y() < mapToGlobal(QPoint(0,0)).y())
qScrollEffect(m_popup, QEffects::UpScroll);
else
qScrollEffect(m_popup);
} else
#endif
m_popup->show();
// The combo box is now shown pressed. Make it show not pressed again
// by causing its (invisible) list box to emit a 'selected' signal.
// Simulate an Enter to unpress it:
QListBox *lb = listBox();
if (lb) {
lb->setCurrentItem(0);
QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0, 0);
QApplication::postEvent(lb, keyEvent);
}
}
bool KColorCombo2::eventFilter(QObject */*object*/, QEvent *event)
{
QMouseEvent *mouseEvent;
switch (event->type()) {
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
mouseEvent = (QMouseEvent*)event;
if ( !m_popup->rect().contains(mouseEvent->pos()) ) {
QPoint globalPos = m_popup->mapToGlobal(mouseEvent->pos());
if (QApplication::widgetAt(globalPos, /*child=*/true) == this) {
// The popup is being closed by a click on the KColorCombo2 widget.
// Avoid popping it up again immediately:
m_discardNextMousePress = true;
}
}
break;
default:
break;
}
// Don't stop the event being handled further:
return false;
}
void KColorCombo2::mousePressEvent(QMouseEvent *event)
{
m_dragStartPos = event->pos();
if (event->button() == Qt::LeftButton && m_discardNextMousePress)
m_discardNextMousePress = false;
else
QComboBox::mousePressEvent(event);
}
void KColorCombo2::mouseMoveEvent(QMouseEvent *event)
{
if( (event->state() & Qt::LeftButton) &&
(event->pos() - m_dragStartPos).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
// Drag color object:
KColorDrag *colorDrag = new KColorDrag(effectiveColor(), this);
// Replace the drag pixmap with our own rounded one, at the same position and dimetions:
QPixmap pixmap = colorDrag->pixmap();
pixmap = colorRectPixmap(effectiveColor(), /*isDefault=*/false, pixmap.width(), pixmap.height());
colorDrag->setPixmap(pixmap, colorDrag->pixmapHotSpot());
colorDrag->dragCopy();
//setDown(false);
}
}
void KColorCombo2::dragEnterEvent(QDragEnterEvent *event)
{
event->accept(isEnabled() && KColorDrag::canDecode(event));
}
void KColorCombo2::dropEvent(QDropEvent *event)
{
QColor color;
if (KColorDrag::decode(event, color))
setColor(color);
}
void KColorCombo2::keyPressEvent(QKeyEvent *event)
{
KKey key(event);
if (KStdAccel::copy().contains(key)) {
QMimeSource *mime = new KColorDrag(effectiveColor());
QApplication::clipboard()->setData(mime, QClipboard::Clipboard);
} else if (KStdAccel::paste().contains(key)) {
QColor color;
KColorDrag::decode(QApplication::clipboard()->data(QClipboard::Clipboard), color);
setColor(color);
} else
QComboBox::keyPressEvent(event);
}
void KColorCombo2::fontChange(const QFont &oldFont)
{
// Since the color-rectangle is the same height of the text, we should resize it if the font change:
updateComboBox();
QComboBox::fontChange(oldFont); // To update geometry.
}
void KColorCombo2::virtual_hook(int /*id*/, void */*data*/)
{
/* KBASE::virtual_hook(id, data); */
}
#include "kcolorcombo2.moc"

@ -0,0 +1,343 @@
/***************************************************************************
* Copyright (C) 2005 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef KCOLORCOMBO2_H
#define KCOLORCOMBO2_H
#include <qcombobox.h>
#include <qcolor.h>
#include <qpixmap.h>
class KColorPopup;
/**
* @short A combobox to display or allow user selection of a color in a user-friendly way.
*
* A combobox widget that popup an array of colors for the user to easily pick a common color.\n
* He/she can use the popup to quickly pick a reasonable color or open a color chooser dialog for a more precise choice.\n
* The user can also choose a default color (the standard background color, text color, etc... it's to the programmer to make sense of this property).\n
* \n
* The user is also offered some facilities: like KColorButton he/she can copy a color or paste it
* (with standard keyboard shortcuts, usually Ctrl+C and Ctrl+V), and he/she can drag or drop colors.
*
* @par Quick usage:
* Just create a new KColorCombo2() with the initial color and eventually an allowed default color
* (eg. KGlobalSettings::baseColor() for a background color, KGlobalSettings::textColor()...).\n
* You will be noticed of the color the user selects with the signal changed(), or you can use color() to get the color at any moment.\n
* Note that they can return an invalid color (see QColor::isValid()) if the user chosen the default color (if he can choose that).\n
* It's then easy to save in settings, but if you want the real color (even for the default), you can get it with effectiveColor().
*
* @par Notes about default color:
* If you set a default color using Qt or KDE standard colors, the user can change them in the KDE Control Center,
* but this widget willn't be update and will still show the old one.\n
* To be noticed of such color change and then update the widget with the new standard color, you can use one of those two methods:
* @code
* void QWidgetDerivate::paletteChange(const QPalette &oldPalette) { // QWidgetDerivate is a parent or near custom widget
* theComboBox->setDefaultColor(theNewDefaultColor);
* QWidget::paletteChange(oldPalette);
* }
* @endcode
* or connect the signal KApplication::kdisplayPaletteChanged() to a slot that will set the default color of this widget.
*
* @par Advanced usage:
* By default, the combobox show a well balanced rainbow, OK for most usages, and you don't need to do anything for it to work.\n
* You however can set your own color array by calling newColorArray() with the number of columns and rows.
* Then, setColorAt() several times to fill the array.\n
* This allow the most flexibility. But if you just want a rainbow with more or less colors, setRainbowPreset() is what you want.\n
* If you worry about performance issues of creating a combobox with the default color array and then allocating another color array by yourself,
* note that the default color array is not allocated in the constructor, but as soon as it is demanded (on first popup if no array has been
* set before, or on first call of any accessors: colorAt(), columnCount(), setColorAt()...).
* Finally, colorRectPixmap() and drawColorRect() allow to draw the color rounded-rectangle in other places for a consistent look.
*
* @see KGlobalSettings Use one of the static functions to get KDE standard colors for default values.
* @see KColorButton The same, but without the rainbow popup or the choice of a default color.
* @see KColorDialog The dialog that is shown when the user click the "Other..." entry.
* @author Sébastien Laoût <slaout@linux62.org>
*
* @image html commoncolorselector.png "Common Color Selector ComboBox"
*/
class KColorCombo2 : public QComboBox
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(QColor defaultColor READ defaultColor WRITE setDefaultColor)
public slots:
/**
* Change the selected color.\n
* If the popup is open, it will not reflect the change. FIXME: Should it?
* @param color The new selected color. Can be invalid to select the default one.\n
* If @p color is invalid and no default color is allowed, the function will keep the old one.
*/
void setColor(const QColor &color);
/**
* Change the default color.
* @param color The color to return if the user choose the default one. If it is not valid, the user willn't be allowed to choose a default one.
* @see defaultColor() to get it.
*/
void setDefaultColor(const QColor &color);
signals:
/**
* Emitted when the color of the widget is changed, either with setColor() or via user selection.
* @see color() to know the content of @p newColor.
*/
void changed(const QColor &newColor);
public:
/**
* Constructs a color combobox with parent @p parent called @p name.
* @param color The initial selected color. If it is not valid, the default one will then be selected.\n
* But if @p color is invalid and there is no default color, the result is undefined.
* @param defaultColor The color to return if the user choose the default one. If it is not valid, the user willn't be allowed to choose a default one.
*/
KColorCombo2(const QColor &color, const QColor &defaultColor, QWidget *parent = 0, const char *name = 0);
/**
* Constructs a color combobox with parent @p parent called @p name.\n
* The user is not allowed to choose a default color, unless you call setDefaultColor() later.
* @param color The initial selected color. If it is invalid, the result is undefined.
*/
KColorCombo2(const QColor &color, QWidget *parent = 0L, const char *name = 0L);
/**
* Destroys the combobox.
*/
virtual ~KColorCombo2();
/**
* Get the color chosen by the user.\n
* Can be invalid, if the user chosen the default one.\n
* Ideal to store it in settings for later recall.
* @see effectiveColor() if you want the color to be always valid.
*/
QColor color() const;
/**
* Return the color chosen by the user.\n
* If the user chosen the default color, the default one is then returned, so the returned color is always valid.\n
* Ideal to directly use to draw.
* @see color() if you want to be notified of a default color choice.
*/
QColor effectiveColor() const;
/**
* Returns the default color or an invalid color if no default color is set (if the user isn't allowed to choose a default color).
* @see setDefaultColor() to change it.
*/
QColor defaultColor() const;
/**
* Allocate a new color array of the specified dimention.\n
* The new array will have invalid colors: you should then assign them one by one.\n
* If one or both of the dimentions are negative or null, this function do nothing (both dimentions are always ensured to be at least equal to 1).
* @param columnCount The number of columns of the array.
* @param rowCount The number of rows of the array.
* @see setColorAt() to set all colors once the array have been created.
*/
void newColorArray(int columnCount, int rowCount);
/**
* Get the number of columns in the array that the user can see to choose.
* @see rowCount() for the number of rows, and colorAt() to get a color from the array.
*/
int columnCount() const;
/**
* Get the number of rows in the array that the user can see to choose.
* @see columnCount() for the number of columns, and colorAt() to get a color from the array.
*/
int rowCount() const;
/**
* Set a color in the array at position (column,row).\n
* If one or both of the indexes are out of range, this function do nothing.\n
* @p column and @p row start from 0 to columnCount()-1 and columnRow()-1.
*
* @param column The x coordinate of the color to set or change.
* @param row The y coordinate of the color to set or change.
* @param color The color to assign at this position.
*/
void setColorAt(int column, int row, const QColor &color);
/**
* Get a color in the array that the user can see to choose.\n
* @p column and @p row start from 0 to columnCount()-1 and columnRow()-1.
*
* @return The asked color, or an invalid color if the index is out of limit of the array.
* @see columnCount() and rowCount() to get the array dimentions.
*/
QColor colorAt(int column, int row)/* const*/;
/**
* Fill the array of colors (that will be shown to the user in the popup that appears when he/she click the arrow) with a rainbow of different luminosity.\n
* This rainbow representation have the advantage of being natural and well structured for a human to be able to select reasonable colors.\n
* This function will allocate a color array by itself depending on the parameters (no need to call newColorArray()).
* @param colorColumnCount The number of columns. The 360 possible colors of the rainbow will be splitted to take the wanted number of colors, equaly separated.
* @param lightRowCount There is always at least 1 row of colors: the "pure" colors: pure red, pure blue, pure green, pure fushia...\n
* Additionnaly, you can add row on top: they will contain the same colors, but lighter.\n
* The parameter @p lightRowCount specify how many different lighting grades shoud be shown (from near to white, but not white, to "pure").
* @param darkRowCount Finally, on bottom of the row of "pure colors", you can put any variety of dark colors (from "pure", to near to black, but not black).\n
* So, the number of rows is equal to @p lightRowCount + 1 + @p darkRowCount. On top are light colors, gradually going to dark ones on bottom.
* @param withGray If true, another column (so there will be @p colorColumnCount+1 columns) is added on the very-right of the popup
* to show different gray values, matching the brightness of the sibling colors.
*
* The most acceptable parameters:
* @li The default values are good to have the 7 colors of the rainbow + colors between them, and light/dark colors are well distinct.
* @li If the color is a background color, you can set @p darkRowCount to 0, so only light colors are shown.
* @li The inverse is true for text color choice: you can set @p lightRowCount to 0.
* @li But be careful: some advanced users prefer white text on dark background, so you eg. can set @p lightRowCount to a big value and
* @p darkRowCount to a small one for a fewer choice of dark colors, but at least some ones.
*/
void setRainbowPreset(int colorColumnCount = 12, int lightRowCount = 4, int darkRowCount = 4, bool withGray = true);
//void setHsvPreset(QColor hue[], QColor saturation[], QColor value[], bool withGray = true);
/**
* Returns a pixmap of a colored rounded-rectangle. The four corners are transparent.\n
* Useful if you want to set such a rectangle as an icon for a menu entry, or for drag and drop operation...
* @param color The color of the rectangle. If the color is invalid, a rainbow is then drawn (like for the "Other..." entry in the popup).
* @param isDefault True if @p color is the default one and should then be draw with a diagonal line.
* @param width The width of the rectangle pixmap to return.
* @param height The height of the rectangle pixmap to return.
*
* @see drawColorRect() if you need to draw it directly: it's faster.
*/
static QPixmap colorRectPixmap(const QColor &color, bool isDefault, int width, int height);
/**
* Draw an image of a colored rounded-rectangle.\n
* This is like colorRectPixmap() but significantly faster because there is nothing to copy, and no transparency mask to create and apply.
* @param painter The painter where to draw the image.
* @param x The x coordinate on the @p painter where to draw the rectangle.
* @param y The y coordinate on the @p painter where to draw the rectangle.
* @param color The color of the rectangle. If the color is invalid, a rainbow is then drawn (like for the "Other..." entry in the popup).
* @param isDefault True if @p color is the default one and should then be draw with a diagonal line.
* @param width The width of the rectangle pixmap to return.
* @param height The height of the rectangle pixmap to return.
*
* @see colorRectPixmap() to get a transparent pixmap of the rectangle.
*/
static void drawColorRect(QPainter &painter, int x, int y, const QColor &color, bool isDefault, int width, int height);
/**
* Get the height of a color rectangle for this combobox.\n
* This is equal to the text height, regarding to the current font of this combobox.
*/
int colorRectHeight() const;
/**
* Get the width of a color rectangle, depending of the @p height of it.\n
* It typically return 1.4 * @p height for decent rectangle proportions.
*/
int colorRectWidthForHeight(int height) const;
protected:
virtual void popup();
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseMoveEvent(QMouseEvent *event);
virtual bool eventFilter(QObject *object, QEvent *event);
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
virtual void keyPressEvent(QKeyEvent *event);
virtual void fontChange(const QFont &oldFont);
private:
/**
* Initialization routine common to every constructors.\n
* Constructors just have to initialize the QComboBox, m_color and m_defaultColor
* and this function do the rest to complete the creation of this widget.
*/
void init();
/**
* Free up all memory allocated for the color array.\n
* But only if an array have previously been allocated, of course.
*/
void deleteColorArray();
/**
* Update the only item of the combobox to mirror the new selected color.\n
* Mainly called on init() and setColor().
*/
void updateComboBox();
KColorPopup *m_popup;
QColor m_color;
QColor m_defaultColor;
bool m_discardNextMousePress;
QColor **m_colorArray;
int m_columnCount;
int m_rowCount;
QPoint m_dragStartPos;
protected:
/**
* Keep place for future improvements without having to break binary compatibility.\n
* Does nothing for the moment.
*/
virtual void virtual_hook(int id, void *data);
private:
/**
* Keep place for future improvements without having to break binary compatibility.
*/
class KColorCombo2Private;
KColorCombo2Private *d;
};
// TODO: setColorArray(QColor **, int, int) and use signals/slots ??
class KColorPopup : public QWidget
{
Q_OBJECT
public:
KColorPopup(KColorCombo2 *parent);
~KColorPopup();
void relayout(); // updateGeometry() ??
protected:
void paintEvent(QPaintEvent */*event*/);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
void doSelection();
void validate();
void updateCell(int column, int row);
friend class KColorCombo2;
private:
KColorCombo2 *m_selector;
QPixmap m_pixmap;
int m_selectedRow;
int m_selectedColumn;
int m_columnOther;
QColor m_otherColor;
static const int MARGIN;
static const int FRAME_WIDTH;
};
#endif // KCOLORCOMBO2_H

@ -0,0 +1,129 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kapplication.h> // it define Q_WS_X11
#include "keyboard.h"
/* This file contain modified code from klistbox.cpp
*/
// ShiftMask, ControlMask and Mod1Mask are defined in <X11/X.h>
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
#include <X11/Xlib.h> // schroder
#endif
void Keyboard::pressedKeys(bool &shiftPressed, bool &controlPressed)
{
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint keybstate;
XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &keybstate );
shiftPressed = keybstate & ShiftMask;
controlPressed = keybstate & ControlMask;
#endif
}
/** Same code as pressedKeys(...) but for shift key only
*/
bool Keyboard::shiftPressed()
{
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint keybstate;
XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &keybstate );
return (keybstate & ShiftMask) != 0;
#else
return false;
#endif
}
/** Same code as pressedKeys(...) but for control key only
*/
bool Keyboard::controlPressed()
{
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint keybstate;
XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &keybstate );
return (keybstate & ControlMask) != 0;
#else
return false;
#endif
}
/** Return if Alt key is pressed
*/
bool Keyboard::altPressed()
{
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint keybstate;
XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &keybstate );
return (keybstate & Mod1Mask) != 0;
#else
return false;
#endif
}
/*******************
* What does KDE 3.1 and later:
* FIXME: Use this function in KDE 4
* (I wasn't knowing it by creating this class)
/ *
* Returns the currently pressed keyboard modifiers (e.g. shift, control, etc.)
* Usually you simply want to test for those in key events, in which case
* QKeyEvent::state() does the job (or QKeyEvent::key() to
* notice when a modifier is pressed alone).
* But it can be useful to query for the status of the modifiers at another moment
* (e.g. some KDE apps do that upon a drop event).
* @return the keyboard modifiers
* @since 3.1
/
uint KApplication::keyboardModifiers()
{
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint keybstate;
XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &keybstate );
return keybstate & 0x00ff;
}
*
*******************/

@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef KEYBOARD_H
#define KEYBOARD_H
/**
* Methods to know if Shift and / or Ctrl keys are pressed.
* Depend on X, but neither Qt not KDE provide this class / methods.
* @author Sébastien Laoût
*/
namespace Keyboard
{
void pressedKeys(bool &shiftPressed, bool &controlPressed);
bool shiftPressed();
bool controlPressed();
bool altPressed();
}
#endif // KEYBOARD_H

@ -0,0 +1,443 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "kgpgme.h"
#ifdef HAVE_LIBGPGME
#include <kapplication.h>
#include <kmessagebox.h>
#include <kpassdlg.h>
#include <kiconloader.h>
#include <klistview.h>
#include <kdebug.h>
#include <qcheckbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <klocale.h>
#include <locale.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
// KGpgSelKey class based on class in KGpg with the same name
class KGpgSelKey : public KDialogBase
{
private:
KListView* keysListpr;
public:
KGpgSelKey(QWidget *parent, const char *name, QString preselected,
const KGpgMe& gpg):
KDialogBase( parent, name, true,i18n("Private Key List"),Ok | Cancel) {
QString keyname;
QVBoxLayout* vbox;
QWidget* page = new QWidget(this);
QLabel* labeltxt;
KIconLoader* loader = KGlobal::iconLoader();
QPixmap keyPair = loader->loadIcon("kgpg_key2", KIcon::Small, 20);
setMinimumSize(350,100);
keysListpr = new KListView(page);
keysListpr->setRootIsDecorated(true);
keysListpr->addColumn(i18n("Name"));
keysListpr->addColumn(i18n("Email"));
keysListpr->addColumn(i18n("ID"));
keysListpr->setShowSortIndicator(true);
keysListpr->setFullWidth(true);
keysListpr->setAllColumnsShowFocus(true);
labeltxt = new QLabel(i18n("Choose a secret key:"),page);
vbox = new QVBoxLayout(page);
KGpgKeyList list = gpg.keys(true);
for(KGpgKeyList::iterator it = list.begin(); it != list.end(); ++it) {
QString name = gpg.checkForUtf8((*it).name);
KListViewItem *item = new
KListViewItem(keysListpr, name, (*it).email, (*it).id);
item->setPixmap(0,keyPair);
if(preselected == (*it).id) {
keysListpr->setSelected(item, true);
keysListpr->setCurrentItem(item);
}
}
if(!keysListpr->selectedItem()) {
keysListpr->setSelected(keysListpr->firstChild(), true);
keysListpr->setCurrentItem(keysListpr->firstChild());
}
vbox->addWidget(labeltxt);
vbox->addWidget(keysListpr);
setMainWidget(page);
};
QString key() {
QListViewItem* item = keysListpr->selectedItem();
if(item)
return item->text(2);
return "";
}
};
KGpgMe::KGpgMe() : m_ctx(0), m_useGnuPGAgent(true)
{
init(GPGME_PROTOCOL_OpenPGP);
if(gpgme_new(&m_ctx)) {
m_ctx = 0;
}
else {
gpgme_set_armor(m_ctx, 1);
setPassphraseCb();
}
}
KGpgMe::~KGpgMe()
{
if(m_ctx)
gpgme_release(m_ctx);
clearCache();
}
void KGpgMe::clearCache()
{
if(m_cache.size() > 0)
{
m_cache.fill('\0');
m_cache.truncate(0);
}
}
void KGpgMe::init(gpgme_protocol_t proto)
{
gpgme_error_t err;
gpgme_check_version(NULL);
setlocale(LC_ALL, "");
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
err = gpgme_engine_check_version(proto);
if(err) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
}
}
QString KGpgMe::checkForUtf8(QString txt)
{
// code borrowed from KGpg which borrowed it from gpa
const char *s;
// Make sure the encoding is UTF-8.
// Test structure suggested by Werner Koch
if(txt.isEmpty())
return QString::null;
for(s = txt.ascii(); *s && !(*s & 0x80); s++)
;
if (*s && !strchr (txt.ascii(), 0xc3) && (txt.find("\\x")==-1))
return txt;
// The string is not in UTF-8
//if (strchr (txt.ascii(), 0xc3)) return (txt+" +++");
if (txt.find("\\x")==-1)
return QString::fromUtf8(txt.ascii());
// if (!strchr (txt.ascii(), 0xc3) || (txt.find("\\x")!=-1)) {
for(int idx = 0 ; (idx = txt.find( "\\x", idx )) >= 0 ; ++idx) {
char str[2] = "x";
str[0] = (char)QString(txt.mid(idx + 2, 2)).toShort(0, 16);
txt.replace(idx, 4, str);
}
if (!strchr (txt.ascii(), 0xc3))
return QString::fromUtf8(txt.ascii());
else
return QString::fromUtf8(QString::fromUtf8(txt.ascii()).ascii());
// perform Utf8 twice, or some keys display badly
return txt;
}
QString KGpgMe::selectKey(QString previous)
{
KGpgSelKey dlg(kapp->activeWindow(), "", previous, *this);
if(dlg.exec())
return dlg.key();
return "";
}
// Rest of the code is mainly based in gpgme examples
KGpgKeyList KGpgMe::keys(bool privateKeys /* = false */) const
{
KGpgKeyList keys;
gpgme_error_t err = 0, err2 = 0;
gpgme_key_t key = 0;
gpgme_keylist_result_t result = 0;
if(m_ctx) {
err = gpgme_op_keylist_start(m_ctx, NULL, privateKeys);
if(!err) {
while(!(err = gpgme_op_keylist_next(m_ctx, &key))) {
KGpgKey gpgkey;
if(!key->subkeys)
continue;
gpgkey.id = key->subkeys->keyid;
if(key->uids) {
gpgkey.name = key->uids->name;
gpgkey.email = key->uids->email;
}
keys.append(gpgkey);
gpgme_key_unref(key);
}
if (gpg_err_code (err) == GPG_ERR_EOF)
err = 0;
err2 = gpgme_op_keylist_end(m_ctx);
if(!err)
err = err2;
}
}
if(err) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
}
else {
result = gpgme_op_keylist_result(m_ctx);
if (result->truncated) {
KMessageBox::error(kapp->activeWindow(),
i18n("Key listing unexpectedly truncated."));
}
}
return keys;
}
bool KGpgMe::encrypt(const QByteArray& inBuffer, Q_ULONG length,
QByteArray* outBuffer, QString keyid /* = QString::null */)
{
gpgme_error_t err = 0;
gpgme_data_t in = 0, out = 0;
gpgme_key_t keys[2] = { NULL, NULL };
gpgme_key_t* key = NULL;
gpgme_encrypt_result_t result = 0;
outBuffer->resize(0);
if(m_ctx) {
err = gpgme_data_new_from_mem(&in, inBuffer.data(), length, 1);
if(!err) {
err = gpgme_data_new(&out);
if(!err) {
if(keyid.isNull()) {
key = NULL;
}
else {
err = gpgme_get_key(m_ctx, keyid.ascii(), &keys[0], 0);
key = keys;
}
if(!err) {
err = gpgme_op_encrypt(m_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST,
in, out);
if(!err) {
result = gpgme_op_encrypt_result(m_ctx);
if (result->invalid_recipients) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(i18n("That public key is not meant for encryption"))
.arg(result->invalid_recipients->fpr));
}
else {
err = readToBuffer(out, outBuffer);
}
}
}
}
}
}
if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
}
if(err != GPG_ERR_NO_ERROR)
clearCache();
if(keys[0])
gpgme_key_unref(keys[0]);
if(in)
gpgme_data_release(in);
if(out)
gpgme_data_release(out);
return (err == GPG_ERR_NO_ERROR);
}
bool KGpgMe::decrypt(const QByteArray& inBuffer, QByteArray* outBuffer)
{
gpgme_error_t err = 0;
gpgme_data_t in = 0, out = 0;
gpgme_decrypt_result_t result = 0;
outBuffer->resize(0);
if(m_ctx) {
err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1);
if(!err) {
err = gpgme_data_new(&out);
if(!err) {
err = gpgme_op_decrypt(m_ctx, in, out);
if(!err) {
result = gpgme_op_decrypt_result(m_ctx);
if(result->unsupported_algorithm) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(i18n("Unsupported algorithm"))
.arg(result->unsupported_algorithm));
}
else {
err = readToBuffer(out, outBuffer);
}
}
}
}
}
if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) {
KMessageBox::error(kapp->activeWindow(), QString("%1: %2")
.arg(gpgme_strsource(err)).arg(gpgme_strerror(err)));
}
if(err != GPG_ERR_NO_ERROR)
clearCache();
if(in)
gpgme_data_release(in);
if(out)
gpgme_data_release(out);
return (err == GPG_ERR_NO_ERROR);
}
#define BUF_SIZE (32 * 1024)
gpgme_error_t KGpgMe::readToBuffer(gpgme_data_t in, QByteArray* outBuffer) const
{
int ret;
gpgme_error_t err = GPG_ERR_NO_ERROR;
ret = gpgme_data_seek(in, 0, SEEK_SET);
if(ret) {
err = gpgme_err_code_from_errno(errno);
}
else {
char* buf = new char[BUF_SIZE + 2];
if(buf) {
while((ret = gpgme_data_read(in, buf, BUF_SIZE)) > 0) {
uint size = outBuffer->size();
if(outBuffer->resize(size + ret))
memcpy(outBuffer->data() + size, buf, ret);
}
if(ret < 0)
err = gpgme_err_code_from_errno(errno);
delete[] buf;
}
}
return err;
}
bool KGpgMe::isGnuPGAgentAvailable()
{
QString agent_info = getenv("GPG_AGENT_INFO");
if (agent_info.find(':') > 0)
return true;
return false;
}
void KGpgMe::setPassphraseCb()
{
bool agent = false;
QString agent_info;
agent_info = getenv("GPG_AGENT_INFO");
if(m_useGnuPGAgent)
{
if (agent_info.find(':'))
agent = true;
if(agent_info.startsWith("disable:"))
setenv("GPG_AGENT_INFO", agent_info.mid(8), 1);
}
else
{
if(!agent_info.startsWith("disable:"))
setenv("GPG_AGENT_INFO", "disable:" + agent_info, 1);
}
if (agent)
gpgme_set_passphrase_cb(m_ctx, 0, 0);
else
gpgme_set_passphrase_cb(m_ctx, passphraseCb, this);
}
gpgme_error_t KGpgMe::passphraseCb(void* hook, const char* uid_hint,
const char* passphrase_info,
int last_was_bad, int fd)
{
KGpgMe* gpg = static_cast<KGpgMe*>(hook);
return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd);
}
gpgme_error_t KGpgMe::passphrase(const char* uid_hint,
const char* /*passphrase_info*/,
int last_was_bad, int fd)
{
gpgme_error_t res = GPG_ERR_CANCELED;
QString s;
QString gpg_hint = checkForUtf8(uid_hint);
int result;
if(last_was_bad){
s += "<b>" + i18n("Wrong password.") + "</b><br><br>\n\n";
clearCache();
}
if(!m_text.isEmpty())
s += m_text + "<br>";
if(!gpg_hint.isEmpty())
s += gpg_hint;
if(m_cache.isEmpty()){
QCString password;
if(m_saving)
result = KPasswordDialog::getNewPassword(password, s);
else
result = KPasswordDialog::getPassword(password, s);
if(result == KPasswordDialog::Accepted)
m_cache = password;
}
else
result = KPasswordDialog::Accepted;
if(result == KPasswordDialog::Accepted) {
write(fd, m_cache.data(), m_cache.length());
res = 0;
}
write(fd, "\n", 1);
return res;
}
#endif // HAVE_LIBGPGME

@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef KGPGME_H
#define KGPGME_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_LIBGPGME
#include <gpgme.h>
#include <qstringlist.h>
/**
@author Petri Damsten <damu@iki.fi>
*/
class KGpgKey
{
public:
QString id;
QString name;
QString email;
};
typedef QValueList< KGpgKey > KGpgKeyList;
class KGpgMe
{
public:
KGpgMe();
~KGpgMe();
QString selectKey(QString previous = QString::null);
KGpgKeyList keys(bool privateKeys = false) const;
void setText(QString text, bool saving) { m_text = text; m_saving = saving; };
void setUseGnuPGAgent(bool use) { m_useGnuPGAgent = use; setPassphraseCb(); };
QString text() const { return m_text; };
bool saving() const { return m_saving; };
void clearCache();
bool encrypt(const QByteArray& inBuffer, Q_ULONG length,
QByteArray* outBuffer, QString keyid = QString::null);
bool decrypt(const QByteArray& inBuffer, QByteArray* outBuffer);
static QString checkForUtf8(QString txt);
static bool isGnuPGAgentAvailable();
private:
gpgme_ctx_t m_ctx;
QString m_text;
bool m_saving;
bool m_useGnuPGAgent;
QCString m_cache;
void init(gpgme_protocol_t proto);
gpgme_error_t readToBuffer(gpgme_data_t in, QByteArray* outBuffer) const;
void setPassphraseCb();
static gpgme_error_t passphraseCb(void *hook, const char *uid_hint,
const char *passphrase_info,
int last_was_bad, int fd);
gpgme_error_t passphrase(const char *uid_hint,
const char *passphrase_info,
int last_was_bad, int fd);
};
#endif // HAVE_LIBGPGME
#endif // KGPGME_H

@ -0,0 +1,244 @@
/* vi: ts=8 sts=4 sw=4
* kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
*
* This file is part of the KDE project, module kfile.
* Copyright (C) 2006 Luke Sandell <lasandell@gmail.com>
* (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
* (C) 2000 Geert Jansen <jansen@kde.org>
* (C) 2000 Kurt Granroth <granroth@kde.org>
* (C) 1997 Christoph Neerfeld <chris@kde.org>
*
* This is free software; it comes under the GNU Library General
* Public License, version 2. See the file "COPYING.LIB" for the
* exact licensing terms.
*/
#include "kiconcanvas.h"
#include "kicondialog.h"
#include <config.h>
#include <kiconviewsearchline.h>
#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <kimagefilepreview.h>
#include <kurldrag.h>
#include <kmultipledrag.h>
#include <qsortedlist.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qtimer.h>
#include <qfileinfo.h>
#include <qdragobject.h>
#include <cmath>
#include <math.h>
#include <algorithm>
#ifdef HAVE_LIBART
#include <svgicons/ksvgiconengine.h>
#include <svgicons/ksvgiconpainter.h>
#endif
class KIconCanvasItem : public QIconViewItem
{
public:
KIconCanvasItem ( QIconView * parent, const QString & key, const QPixmap & pixmap )
: QIconViewItem(parent)
{
setText(QFileInfo(key).baseName());
setKey(key);
setPixmap(pixmap);
setDragEnabled(true);
setDropEnabled(false);
}
int compare(QIconViewItem *rhs) const
{
return QString::localeAwareCompare(text().lower(), rhs->text().lower());
}
};
class KIconCanvas::KIconCanvasPrivate
{
public:
KIconCanvasPrivate()
{
m_bLoading = false;
mSize = 0;
}
~KIconCanvasPrivate()
{
}
bool m_bLoading;
QString mSetCurrent;
int mSize;
#ifdef HAVE_LIBART
KSvgIconEngine mSvgEngine;
#endif
bool mStrictIconSize;
};
/*
* KIconCanvas: Iconview for the iconloader dialog.
*/
KIconCanvas::KIconCanvas(QWidget *parent, const char *name)
: KIconView(parent, name)
{
d = new KIconCanvasPrivate;
mpLoader = KGlobal::iconLoader();
mpTimer = new QTimer(this);
connect(mpTimer, SIGNAL(timeout()), SLOT(slotLoadFiles()));
connect(this, SIGNAL(currentChanged(QIconViewItem *)),
SLOT(slotCurrentChanged(QIconViewItem *)));
setAcceptDrops(false);
setShowToolTips(true);
setStrictIconSize(false);
}
KIconCanvas::~KIconCanvas()
{
delete mpTimer;
delete d;
}
void KIconCanvas::setIconLoader(KIconLoader *loader)
{
mpLoader = loader;
}
void KIconCanvas::loadIcon(const QString &name)
{
QImage img;
QString path = mpLoader->iconPath(name,-d->mSize);
// Use the extension as the format. Works for XPM and PNG, but not for SVG
QString ext = path.right(3).upper();
int maxSize = std::min(d->mSize, 60);
if (ext != "SVG" && ext != "VGZ")
img.load(path);
#ifdef HAVE_LIBART
else
if (d->mSvgEngine.load(maxSize, maxSize, path))
img = *d->mSvgEngine.painter()->image();
#endif
if (img.isNull())
return;
// For non-KDE icons
if (d->mStrictIconSize && (img.width() != d->mSize || img.height() != d->mSize))
return;
if (img.width() > maxSize || img.height() > maxSize)
{
if (img.width() > img.height()) {
int height = (int) ((float(maxSize) / img.width()) * img.height());
img = img.smoothScale(maxSize, height);
} else {
int width = (int) ((float(maxSize) / img.height()) * img.width());
img = img.smoothScale(width, maxSize);
}
}
QPixmap pm;
pm.convertFromImage(img);
(void) new KIconCanvasItem(this, name, pm);
}
void KIconCanvas::loadFiles(const QStringList& files)
{
clear();
mFiles = files;
emit startLoading(mFiles.count());
mpTimer->start(10, true); // #86680
d->m_bLoading = false;
}
void KIconCanvas::slotLoadFiles()
{
setResizeMode(Fixed);
QApplication::setOverrideCursor(waitCursor);
// disable updates to not trigger paint events when adding child items
setUpdatesEnabled( false );
d->m_bLoading = true;
int count;
QStringList::ConstIterator it;
QStringList::ConstIterator end(mFiles.end());
for (it=mFiles.begin(), count=0; it!=end; ++it, count++)
{
loadIcon(*it);
// Calling kapp->processEvents() makes the iconview flicker like hell
// (it's being repainted once for every new item), so we don't do this.
// Instead, we directly repaint the progress bar without going through
// the event-loop. We do that just once for every 10th item so that
// the progress bar doesn't flicker in turn. (pfeiffer)
// FIXME: Qt4 will have double buffering
if ( count % 10 == 0) {
emit progress(count);
}
if ( !d->m_bLoading ) // user clicked on a button that will load another set of icons
break;
}
// enable updates since we have to draw the whole view now
sort();
d->m_bLoading = false;
setUpdatesEnabled( true );
QApplication::restoreOverrideCursor();
emit finished();
setResizeMode(Adjust);
}
QString KIconCanvas::getCurrent() const
{
return currentItem() ? currentItem()->key() : QString::null;
}
void KIconCanvas::stopLoading()
{
d->m_bLoading = false;
}
void KIconCanvas::slotCurrentChanged(QIconViewItem *item)
{
emit nameChanged((item != 0L) ? item->text() : QString::null);
}
void KIconCanvas::setGroupOrSize( int groupOrSize )
{
d->mSize = ((int)groupOrSize >= 0) ?
mpLoader->currentSize((KIcon::Group)groupOrSize) :
-groupOrSize;
}
void KIconCanvas::setStrictIconSize( bool strictIconSize )
{
d->mStrictIconSize = strictIconSize;
}
QDragObject *KIconCanvas::dragObject()
{
// We use QImageDrag rather than KURLDrag so that the user can't drag an icon out of the theme!
// TODO: support SVG?
QPixmap *pixmap = currentItem()->pixmap();
QPoint pos = viewportToContents( viewport()->mapFromGlobal( QCursor::pos() ) );
QPoint hot;
hot.setX(pos.x() - currentItem()->pos().x() - (currentItem()->width() - pixmap->width()) / 2);
hot.setY(pos.y() - currentItem()->pos().y() - (currentItem()->height() - pixmap->height()) / 2);
QImageDrag *drag = new QImageDrag( pixmap->convertToImage(), this );
drag->setPixmap(*pixmap, hot);
return drag;
}
#include "kiconcanvas.moc"

@ -0,0 +1,89 @@
/* vi: ts=8 sts=4 sw=4
* kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
*
* This file is part of the KDE project, module kfile.
* Copyright (C) 2006 Luke Sandell <lasandell@gmail.com>
* (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
* (C) 2000 Geert Jansen <jansen@kde.org>
* (C) 2000 Kurt Granroth <granroth@kde.org>
* (C) 1997 Christoph Neerfeld <chris@kde.org>
*
* This is free software; it comes under the GNU Library General
* Public License, version 2. See the file "COPYING.LIB" for the
* exact licensing terms.
*/
#ifndef _KICONCANVAS_H_
#define _KICONCANVAS_H_
#include <qstring.h>
#include <qstringlist.h>
#include <kiconview.h>
class QTimer;
class KIconLoader;
class QDragObject;
class QIconLoader;
/**
* Icon canvas for KIconDialog.
*/
class KIO_EXPORT KIconCanvas: public KIconView
/* NOTE: Why export this? */
{
Q_OBJECT
public:
KIconCanvas(QWidget *parent=0L, const char *name=0L);
~KIconCanvas();
/**
* Load icons into the canvas.
*/
void loadFiles(const QStringList& files);
/**
* Returns the current icon.
*/
QString getCurrent() const;
void setIconLoader(KIconLoader *loader);
void setGroupOrSize(int groupOrSize);
void setStrictIconSize(bool strictIconSize);
public slots:
void stopLoading();
signals:
/**
* Emitted when the current icon has changed.
*/
void nameChanged(QString);
/* KDE 4: Make it const QString */
void startLoading(int);
void progress(int);
void finished();
private slots:
void slotLoadFiles();
void slotCurrentChanged(QIconViewItem *item);
private:
QStringList mFiles;
QTimer *mpTimer;
KIconLoader *mpLoader;
protected:
virtual void virtual_hook( int id, void* data );
virtual QDragObject *dragObject();
void loadIcon(const QString &path);
private:
class KIconCanvasPrivate;
KIconCanvasPrivate *d;
};
#endif

@ -0,0 +1,559 @@
/* vi: ts=8 sts=4 sw=4
* kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
*
* This file is part of the KDE project, module kfile.
* Copyright (C) 2006 Luke Sandell <lasandell@gmail.com>
* (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
* (C) 2000 Geert Jansen <jansen@kde.org>
* (C) 2000 Kurt Granroth <granroth@kde.org>
* (C) 1997 Christoph Neerfeld <chris@kde.org>
*
* This is free software; it comes under the GNU Library General
* Public License, version 2. See the file "COPYING.LIB" for the
* exact licensing terms.
*/
#include "kicondialogui.h"
#include "kicondialog.h"
#include "kiconcanvas.h"
#include <config.h>
#include <kiconviewsearchline.h>
#include <kdebug.h>
#include <kapplication.h>
#include <klocale.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <kprogress.h>
#include <kiconview.h>
#include <kfiledialog.h>
#include <kimagefilepreview.h>
#include <kpushbutton.h>
#include <kmessagebox.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qsortedlist.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qtimer.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qfileinfo.h>
#include <qtoolbutton.h>
#include <qwhatsthis.h>
#include <qhbuttongroup.h>
#include <qdragobject.h>
/* NOTE: Must be in the same order as listbox */
enum ExtendedContext
{
ALL = 0,
RECENT = 1,
// Action thru MimeType, subtract 1 to convert to KIcon::Context
OTHER = 7
};
class KIconDialog::KIconDialogPrivate
{
public:
KIconDialogPrivate() {
m_bStrictIconSize = true;
}
~KIconDialogPrivate() {}
bool m_bStrictIconSize;
QString custom;
QString customLocation;
int recentMax;
QStringList recentList;
ExtendedContext extendedContext;
KIconDialogUI *ui; /* FIXME: KDE4 probably move this to the main class */
};
/*
* KIconDialog: Dialog for selecting icons. Both system and user
* specified icons can be chosen.
*/
KIconDialog::KIconDialog(QWidget *parent, const char*)
: KDialogBase(parent, "IconDialog", true, i18n("Select Icon"), Ok|Cancel, Ok)
{
d = new KIconDialogPrivate;
mpLoader = KGlobal::iconLoader();
init();
resize(minimumSize());
}
KIconDialog::KIconDialog(KIconLoader *loader, QWidget *parent,
const char *name)
: KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
{
d = new KIconDialogPrivate;
mpLoader = loader;
init();
}
void KIconDialog::init()
{
mGroupOrSize = KIcon::Desktop;
d->extendedContext = ALL;
mType = 0;
setCustomLocation(QString::null); // Initialize mFileList
// Read configuration
KConfig *config = KGlobal::config();
KConfigGroupSaver saver(config, "KIconDialog");
d->recentMax = config->readNumEntry("RecentMax", 10);
d->recentList = config->readPathListEntry("RecentIcons");
d->ui = new KIconDialogUI( this );
setMainWidget(d->ui);
d->ui->searchLine->setIconView(d->ui->iconCanvas);
d->ui->searchLine->setCaseSensitive(false);
// Hack standard Gui item, as KDevDesigner won't let us
d->ui->browseButton->setText(i18n("&Browse..."));
connect(d->ui->browseButton, SIGNAL(clicked()), SLOT(slotBrowse()));
connect(d->ui->listBox, SIGNAL(highlighted(int)), SLOT(slotContext(int)));
connect(d->ui->iconCanvas, SIGNAL(executed(QIconViewItem *)), SLOT(slotOk()));
connect(d->ui->iconCanvas, SIGNAL(returnPressed(QIconViewItem *)), SLOT(slotOk()));
connect(d->ui->iconCanvas, SIGNAL(startLoading(int)), SLOT(slotStartLoading(int)));
connect(d->ui->iconCanvas, SIGNAL(progress(int)), SLOT(slotProgress(int)));
connect(d->ui->iconCanvas, SIGNAL(finished()), SLOT(slotFinished()));
connect(this, SIGNAL(hidden()), d->ui->iconCanvas, SLOT(stopLoading()));
// NOTE: this must be consistent with the IconType enum (see above)
d->ui->listBox->insertItem(i18n("(All Icons)"));
d->ui->listBox->insertItem(i18n("(Recent)"));
d->ui->listBox->insertItem(i18n("Actions"));
d->ui->listBox->insertItem(i18n("Applications"));
d->ui->listBox->insertItem(i18n("Devices"));
d->ui->listBox->insertItem(i18n("Filesystem"));
d->ui->listBox->insertItem(i18n("File Types"));
d->ui->listBox->insertItem(i18n("Miscellaneous"));
}
KIconDialog::~KIconDialog()
{
// Write configuration
KConfig *config = KGlobal::config();
KConfigGroupSaver saver(config, "KIconDialog");
config->writeEntry("RecentMax", d->recentMax, true, true);
config->writePathEntry("RecentIcons", d->recentList, ',', true, true);
delete d;
}
void KIconDialog::slotAcceptIcons()
{
//FIXME: not used anymore
}
void KIconDialog::showIcons()
{
d->ui->iconCanvas->clear();
QStringList filelist;
KIcon::Context context = static_cast<KIcon::Context>(d->extendedContext - 1);
switch (d->extendedContext)
{
case RECENT:
filelist = d->recentList;
break;
case OTHER:
filelist = mFileList;
break;
case ALL:
filelist = mFileList;
context = KIcon::Any;
// ** Fallthrough to next case **
default:
QStringList list;
if (d->m_bStrictIconSize)
list=mpLoader->queryIcons(mGroupOrSize, context);
else
list=mpLoader->queryIconsByContext(mGroupOrSize, context);
// Remove path & extension
for ( QStringList::iterator it = list.begin(); it != list.end(); ++it)
filelist.append(QFileInfo(*it).baseName());
}
// Remove duplicate icons FIXME: Qt4 we can just use QSet
filelist.sort();
QString prev;
for ( QStringList::iterator it = filelist.begin(); it != filelist.end(); )
{
if (*it == prev)
{
it = filelist.remove(it);
}
else
{
prev = *it;
++it;
}
}
d->ui->iconCanvas->setGroupOrSize(mGroupOrSize);
d->ui->iconCanvas->loadFiles(filelist);
}
void KIconDialog::setStrictIconSize(bool b)
{
d->m_bStrictIconSize=b;
}
bool KIconDialog::strictIconSize() const
{
return d->m_bStrictIconSize;
}
void KIconDialog::setIconSize( int size )
{
// see KIconLoader, if you think this is weird
if ( size == 0 )
mGroupOrSize = KIcon::Desktop; // default Group
else
mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird
}
int KIconDialog::iconSize() const
{
// 0 or any other value ==> mGroupOrSize is a group, so we return 0
return (mGroupOrSize < 0) ? -mGroupOrSize : 0;
}
#ifndef KDE_NO_COMPAT
QString KIconDialog::selectIcon(KIcon::Group group, KIcon::Context context, bool user)
{
setup( group, context, false, 0, user );
return openDialog();
}
#endif
void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
bool strictIconSize, int iconSize, bool user )
{
setup(group, context, strictIconSize, iconSize, user, false, false);
}
void KIconDialog::setup(KIcon::Group group, KIcon::Context context,
bool strictIconSize, int iconSize, bool user,
bool lockContext, bool lockBrowse )
{
d->m_bStrictIconSize = strictIconSize;
d->ui->iconCanvas->setStrictIconSize(strictIconSize);
mGroupOrSize = (iconSize == 0) ? group : -iconSize;
mType = user;
d->extendedContext = static_cast<ExtendedContext>( ( context == KIcon::Any ) ? ALL : context + 1 );
// We cannot change layout because it is protected ;-(
// FIXME: Qt4 we will be able to inherit from both QDialog and our GUI
d->ui->listBox->setEnabled(!lockContext);
d->ui->browseButton->setEnabled(!lockBrowse);
d->ui->listBox->setHidden(lockContext && lockBrowse);
d->ui->browseButton->setHidden(lockContext && lockBrowse);
d->ui->listBox->setCurrentItem(d->extendedContext);
}
const QString & KIconDialog::customLocation( ) const
{
return d->customLocation;
}
void KIconDialog::setCustomLocation( const QString& location )
{
d->customLocation = location;
if (location.isEmpty())
{
mFileList = KGlobal::dirs()->findAllResources("appicon", QString::fromLatin1("*.png"));
} else {
mFileList = mpLoader->queryIconsByDir(location);
}
}
QString KIconDialog::openDialog()
{
showIcons();
if ( exec() == Accepted )
{
if (!d->custom.isEmpty())
return d->custom;
else
return d->ui->iconCanvas->getCurrent();
}
else
{
return QString::null;
}
}
void KIconDialog::showDialog()
{
d->custom = QString::null;
// Make it so minimumSize returns correct value
d->ui->filterLabel->hide();
d->ui->searchLine->hide();
d->ui->progressBar->show();
setModal(false);
show();
// FIXME: this should be before show() but it doesn't work ;-(
resize(minimumSize());
showIcons();
}
void KIconDialog::slotOk()
{
QString key = !d->custom.isEmpty() ? d->custom : d->ui->iconCanvas->getCurrent();
// Append to list of recent icons
if (!d->recentList.contains(key))
{
d->recentList.push_back(key);
// Limit recent list in size
while ( (int)d->recentList.size() > d->recentMax )
d->recentList.pop_front();
}
emit newIconName(key);
KDialogBase::slotOk();
}
QString KIconDialog::getIcon(KIcon::Group group, KIcon::Context context,
bool strictIconSize, int iconSize, bool user,
QWidget *parent, const QString &caption)
{
KIconDialog dlg(parent, "icon dialog");
dlg.setup( group, context, strictIconSize, iconSize, user );
if (!caption.isNull())
dlg.setCaption(caption);
return dlg.openDialog();
}
void KIconDialog::slotBrowse()
{
// Create a file dialog to select a PNG, XPM or SVG file,
// with the image previewer shown.
// KFileDialog::getImageOpenURL doesn't allow svg.
KFileDialog dlg(QString::null, i18n("*.png *.xpm *.svg *.svgz|Icon Files (*.png *.xpm *.svg *.svgz)"),
this, "filedialog", true);
dlg.setOperationMode( KFileDialog::Opening );
dlg.setCaption( i18n("Open") );
dlg.setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly );
KImageFilePreview *ip = new KImageFilePreview( &dlg );
dlg.setPreviewWidget( ip );
dlg.exec();
QString file = dlg.selectedFile();
if (!file.isEmpty())
{
d->custom = file;
if ( mType == 1 )
setCustomLocation(QFileInfo( file ).dirPath( true ));
slotOk();
}
}
void KIconDialog::slotContext(int id)
{
d->extendedContext = static_cast<ExtendedContext>(id);
showIcons();
}
void KIconDialog::slotStartLoading(int steps)
{
if (steps < 10)
d->ui->progressBar->hide();
else
{
d->ui->progressBar->setTotalSteps(steps);
d->ui->progressBar->setProgress(0);
d->ui->progressBar->show();
d->ui->filterLabel->hide();
d->ui->searchLine->hide();
}
}
void KIconDialog::slotProgress(int p)
{
d->ui->progressBar->setProgress(p);
}
void KIconDialog::slotFinished()
{
d->ui->progressBar->hide();
d->ui->filterLabel->show();
d->ui->searchLine->show();
}
class KIconButton::KIconButtonPrivate
{
public:
KIconButtonPrivate() {
m_bStrictIconSize = false;
iconSize = 0; // let KIconLoader choose the default
}
~KIconButtonPrivate() {}
bool m_bStrictIconSize;
bool lockUser;
bool lockCustom;
int iconSize;
};
/*
* KIconButton: A "choose icon" pushbutton.
*/
KIconButton::KIconButton(QWidget *parent, const char *name)
: QPushButton(parent, name)
{
init( KGlobal::iconLoader() );
}
KIconButton::KIconButton(KIconLoader *loader,
QWidget *parent, const char *name)
: QPushButton(parent, name)
{
init( loader );
}
void KIconButton::init( KIconLoader *loader )
{
d = new KIconButtonPrivate;
mGroup = KIcon::Desktop;
mContext = KIcon::Application;
mbUser = false;
mpLoader = loader;
mpDialog = 0L;
connect(this, SIGNAL(clicked()), SLOT(slotChangeIcon()));
}
KIconButton::~KIconButton()
{
delete mpDialog;
delete d;
}
void KIconButton::setStrictIconSize(bool b)
{
d->m_bStrictIconSize=b;
}
bool KIconButton::strictIconSize() const
{
return d->m_bStrictIconSize;
}
void KIconButton::setIconSize( int size )
{
d->iconSize = size;
}
int KIconButton::iconSize() const
{
return d->iconSize;
}
void KIconButton::setIconType(KIcon::Group group, KIcon::Context context, bool user)
{
mGroup = group;
mContext = context;
mbUser = user;
d->lockUser = false;
d->lockCustom = false;
}
void KIconButton::setIconType(KIcon::Group group, KIcon::Context context, bool user, bool lockUser, bool lockCustom)
{
mGroup = group;
mContext = context;
mbUser = user;
d->lockUser = lockUser;
d->lockCustom = lockCustom;
}
void KIconButton::setIcon(const QString& icon)
{
mIcon = icon;
setIconSet(mpLoader->loadIconSet(mIcon, mGroup, d->iconSize));
if (!mpDialog)
{
mpDialog = new KIconDialog(mpLoader, this);
connect(mpDialog, SIGNAL(newIconName(const QString&)), SLOT(newIconName(const QString&)));
}
}
const QString & KIconButton::customLocation( ) const
{
return mpDialog ? mpDialog->customLocation() : QString::null;
}
void KIconButton::setCustomLocation(const QString &custom)
{
if (!mpDialog)
{
mpDialog = new KIconDialog(mpLoader, this);
connect(mpDialog, SIGNAL(newIconName(const QString&)), SLOT(newIconName(const QString&)));
}
mpDialog->setCustomLocation(custom);
}
void KIconButton::resetIcon()
{
mIcon = QString::null;
setIconSet(QIconSet());
}
void KIconButton::slotChangeIcon()
{
if (!mpDialog)
{
mpDialog = new KIconDialog(mpLoader, this);
connect(mpDialog, SIGNAL(newIconName(const QString&)), SLOT(newIconName(const QString&)));
}
mpDialog->setup( mGroup, mContext, d->m_bStrictIconSize, d->iconSize, mbUser, d->lockUser, d->lockCustom );
mpDialog->showDialog();
}
void KIconButton::newIconName(const QString& name)
{
if (name.isEmpty())
return;
QIconSet iconset = mpLoader->loadIconSet(name, mGroup, d->iconSize);
setIconSet(iconset);
mIcon = name;
emit iconChanged(name);
}
void KIconCanvas::virtual_hook( int id, void* data )
{ KIconView::virtual_hook( id, data ); }
void KIconDialog::virtual_hook( int id, void* data )
{ KDialogBase::virtual_hook( id, data ); }
#include "kicondialog.moc"

@ -0,0 +1,329 @@
/* vi: ts=8 sts=4 sw=4
* kate: space-indent on; indent-width 4; mixedindent off; indent-mode cstyle;
*
* This file is part of the KDE project, module kfile.
* Copyright (C) 2006 Luke Sandell <lasandell@gmail.com>
* (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
* (C) 2000 Geert Jansen <jansen@kde.org>
* (C) 2000 Kurt Granroth <granroth@kde.org>
* (C) 1997 Christoph Neerfeld <chris@kde.org>
*
* This is free software; it comes under the GNU Library General
* Public License, version 2. See the file "COPYING.LIB" for the
* exact licensing terms.
*/
#ifndef __KIconDialog_h__
#define __KIconDialog_h__
#include <qstring.h>
#include <qstringlist.h>
#include <qpushbutton.h>
#include <kicontheme.h>
#include <kdialogbase.h>
#include <kiconview.h>
#include <kiconcanvas.h> // FIXME: BCI KDE 3 expects KIconCanvas to be defined in kicondialog.h
class KIconDialogUI;
class QComboBox;
class QTimer;
class QKeyEvent;
class QRadioButton;
class KProgress;
class KIconLoader;
/**
* Dialog for interactive selection of icons. Use the function
* getIcon() let the user select an icon.
*
* @short An icon selection dialog.
*/
class KIO_EXPORT KIconDialog: public KDialogBase
{
Q_OBJECT
public:
/**
* Constructs an icon selection dialog using the global iconloader.
*/
KIconDialog(QWidget *parent=0L, const char *name=0L);
/**
* Constructs an icon selection dialog using a specific iconloader.
*/
KIconDialog(KIconLoader *loader, QWidget *parent=0,
const char *name=0);
/**
* Destructs the dialog.
*/
~KIconDialog();
/**
* Sets a strict icon size policy for allowed icons. When true,
* only icons of the specified group's size in getIcon() are shown.
* When false, icons not available at the desired group's size will
* also be selectable.
*/
void setStrictIconSize(bool b);
/**
* Returns true if a strict icon size policy is set.
*/
bool strictIconSize() const;
/**
* gets the custom icon directory
*/
const QString & customLocation() const;
/**
* sets a custom icon directory
* @since 3.1
*/
void setCustomLocation( const QString& location );
/**
* Sets the size of the icons to be shown / selected.
* @see KIcon::StdSizes
* @see iconSize
*/
void setIconSize(int size);
/**
* Returns the iconsize set via setIconSize() or 0, if the default
* iconsize will be used.
*/
int iconSize() const;
#ifndef KDE_NO_COMPAT
/**
* @deprecated in KDE 3.0, use the static method getIcon instead.
*/
QString selectIcon(KIcon::Group group=KIcon::Desktop, KIcon::Context
context=KIcon::Application, bool user=false);
#endif
/**
* Allows you to set the same parameters as in the class method
* getIcon().
*
*/
void setup( KIcon::Group group,
KIcon::Context context = KIcon::Application,
bool strictIconSize = false, int iconSize = 0,
bool user = false );
/* FIXME: KDE4 remove -- same as next method with default arguments */
/**
* Allows you to set the same parameters as in the class method
* getIcon(), as well as two additional parameters to lock
* the choice between system and user dirs and to lock the custom user
* dir itself.
*
* @since 3.3
*/
void setup( KIcon::Group group, KIcon::Context context,
bool strictIconSize, int iconSize, bool user, bool lockContext,
bool lockBrowse );
// FIXME: KDE4 add default arguments (right now this would cause ambiguity with previous method)
/**
* exec()utes this modal dialog and returns the name of the selected icon,
* or QString::null if the dialog was aborted.
* @returns the name of the icon, suitable for loading with KIconLoader.
* @see getIcon
*/
QString openDialog();
/**
* show()es this dialog and emits a newIcon(const QString&) signal when
* successful. QString::null will be emitted if the dialog was aborted.
*/
void showDialog();
/**
* Pops up the dialog an lets the user select an icon.
*
* @param group The icon group this icon is intended for. Providing the
* group shows the icons in the dialog with the same appearance as when
* used outside the dialog.
* @param context The initial icon context. Initially, the icons having
* this context are shown in the dialog. The user can change this.
* @param strictIconSize When true, only icons of the specified group's size
* are shown, otherwise icon not available in the desired group's size
* will also be selectable.
* @param iconSize the size of the icons -- the default of the icongroup
* if set to 0
* @param user Begin with the "user icons" instead of "system icons".
* @param parent The parent widget of the dialog.
* @param caption The caption to use for the dialog.
* @return The name of the icon, suitable for loading with KIconLoader.
* @version New in 3.0
*/
static QString getIcon(KIcon::Group group=KIcon::Desktop,
KIcon::Context context=KIcon::Application,
bool strictIconSize=false, int iconSize = 0,
bool user=false, QWidget *parent=0,
const QString &caption=QString::null);
signals:
void newIconName(const QString&);
protected slots:
void slotOk();
private slots:
void slotContext(int);
void slotStartLoading(int);
void slotProgress(int);
void slotFinished();
void slotAcceptIcons();
void slotBrowse();
private:
void init();
void showIcons();
int mGroupOrSize;
KIcon::Context mContext;
int mType;
QStringList mFileList;
// FIXME: the following fields are obsolete, remove in KDE4
QComboBox *mpCombo;
QPushButton *mpBrowseBut;
QRadioButton *mpRb1, *mpRb2;
KProgress *mpProgress;
KIconLoader *mpLoader;
KIconCanvas *mpCanvas; // FIXME: obsolete, remove in KDE4
protected:
virtual void virtual_hook( int id, void* data );
private:
class KIconDialogPrivate;
KIconDialogPrivate *d;
};
/**
* A pushbutton for choosing an icon. Pressing on the button will open a
* KIconDialog for the user to select an icon. The current icon will be
* displayed on the button.
*
* @see KIconDialog
* @short A push button that allows selection of an icon.
*/
class KIO_EXPORT KIconButton: public QPushButton
{
Q_OBJECT
Q_PROPERTY( QString icon READ icon WRITE setIcon RESET resetIcon )
Q_PROPERTY( int iconSize READ iconSize WRITE setIconSize)
Q_PROPERTY( bool strictIconSize READ strictIconSize WRITE setStrictIconSize )
Q_PROPERTY( QString customLocation READ customLocation WRITE setCustomLocation )
public:
/**
* Constructs a KIconButton using the global iconloader.
*/
KIconButton(QWidget *parent=0L, const char *name=0L);
/**
* Constructs a KIconButton using a specific KIconLoader.
*/
KIconButton(KIconLoader *loader, QWidget *parent, const char *name=0L);
/**
* Destructs the button.
*/
~KIconButton();
/**
* Sets a strict icon size policy for allowed icons. When true,
* only icons of the specified group's size in setIconType are allowed,
* and only icons of that size will be shown in the icon dialog.
*/
void setStrictIconSize(bool b);
/**
* Returns true if a strict icon size policy is set.
*/
bool strictIconSize() const;
/**
* Sets the icon group and context. Use KIcon::NoGroup if you want to
* allow icons for any group in the given context.
*/
void setIconType(KIcon::Group group, KIcon::Context context, bool user=false);
/**
* Same as above method, but allows you to specify whether user and custom mode should be locked.
*/
void setIconType(KIcon::Group group, KIcon::Context context, bool user, bool lockContext, bool lockBrowse);
/* FIXME: KDE4 this should replace the above method using default params */
/**
* sets a custom icon directory
*/
void setCustomLocation(const QString &custom);
/**
* get the custom icon directory
*/
const QString & customLocation() const;
/**
* Sets the button's initial icon.
*/
void setIcon(const QString& icon);
/**
* Resets the icon (reverts to an empty button).
*/
void resetIcon();
/**
* Returns the name of the selected icon.
*/
QString icon() const { return mIcon; }
/**
* Sets the size of the icon to be shown / selected.
* @see KIcon::StdSizes
* @see iconSize
*/
void setIconSize( int size );
/**
* Returns the iconsize set via setIconSize() or 0, if the default
* iconsize will be used.
*/
int iconSize() const;
signals:
/**
* Emitted when the icon has changed.
*/
void iconChanged(QString icon);
/* FIXME: KDE4: Make it const QString & */
private slots:
void slotChangeIcon();
void newIconName(const QString& name);
private:
void init( KIconLoader *loader );
bool mbUser;
KIcon::Group mGroup;
KIcon::Context mContext;
QString mIcon;
KIconDialog *mpDialog;
KIconLoader *mpLoader;
class KIconButtonPrivate;
KIconButtonPrivate *d;
};
#endif // __KIconDialog_h__

@ -0,0 +1,243 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>KIconDialogUI</class>
<author>Luke Sandell</author>
<widget class="QWidget">
<property name="name">
<cstring>KIconDialogUI</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>340</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>3</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="caption">
<string>KIconDialogUI</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="margin">
<number>0</number>
</property>
<widget class="KListBox" row="0" column="0">
<property name="name">
<cstring>listBox</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>3</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="KIconCanvas" row="0" column="1">
<property name="name">
<cstring>iconCanvas</cstring>
</property>
<property name="minimumSize">
<size>
<width>370</width>
<height>290</height>
</size>
</property>
<property name="focusPolicy">
<enum>WheelFocus</enum>
</property>
<property name="gridX" stdset="0">
<number>80</number>
</property>
<property name="wordWrapIconText" stdset="0">
<bool>false</bool>
</property>
</widget>
<widget class="QLayoutWidget" row="1" column="1">
<property name="name">
<cstring>layout4</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="spacing">
<number>0</number>
</property>
<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>filterLabel</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Fi&amp;lter:</string>
</property>
<property name="buddy" stdset="0">
<cstring>searchLine</cstring>
</property>
</widget>
<widget class="KIconViewSearchLine">
<property name="name">
<cstring>searchLine</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>StrongFocus</enum>
</property>
</widget>
</hbox>
</widget>
<widget class="KProgress">
<property name="name">
<cstring>progressBar</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</vbox>
</widget>
<widget class="KPushButton" row="1" column="0">
<property name="name">
<cstring>browseButton</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Open...</string>
</property>
<property name="accel">
<string>Alt+O</string>
</property>
<property name="on">
<bool>false</bool>
</property>
<property name="stdItem" stdset="0">
<number>18</number>
</property>
</widget>
</grid>
</widget>
<customwidgets>
<customwidget>
<class>KIconViewSearchLine</class>
<header location="global">kiconviewsearchline.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>
<slot access="public" specifier="">updateSearch(const QString &amp;s)</slot>
<slot access="public" specifier="">setCaseSensitive(bool cs)</slot>
<slot access="public" specifier="">setIconView(QIconView *iv)</slot>
<slot access="public" specifier="">clear()</slot>
</customwidget>
<customwidget>
<class>KIconCanvas</class>
<header location="local">kiconcanvas.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>image1</pixmap>
<signal>nameChanged(QString &amp;)</signal>
<signal>startLoading(int)</signal>
<signal>progress(int)</signal>
<signal>finished()</signal>
<slot access="public" specifier="">nameChanged(QString name)</slot>
<slot access="public" specifier="">slot()</slot>
<slot access="public" specifier="">stopLoading()</slot>
<property type="Int">gridX</property>
<property type="Int">gridY</property>
<property type="Bool">itemsMovable</property>
<property type="Bool">wordWrapIconText</property>
<property type="Bool">autoArrange</property>
</customwidget>
</customwidgets>
<images>
<image name="image0">
<data format="XBM.GZ" length="79">789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f</data>
</image>
<image name="image1">
<data format="PNG" length="1125">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154388db5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c6a2573410000000049454e44ae426082</data>
</image>
</images>
<tabstops>
<tabstop>listBox</tabstop>
<tabstop>iconCanvas</tabstop>
<tabstop>browseButton</tabstop>
<tabstop>searchLine</tabstop>
</tabstops>
<layoutdefaults spacing="6" margin="11"/>
<includehints>
<includehint>klistbox.h</includehint>
<includehint>kiconcanvas.h</includehint>
<includehint>kiconviewsearchline.h</includehint>
<includehint>kprogress.h</includehint>
<includehint>kpushbutton.h</includehint>
</includehints>
</UI>

@ -0,0 +1,854 @@
/***************************************************************************
* Copyright (C) 2006 by Sebastien Laout *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library 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 Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#include <kapplication.h>
#include <kaboutdata.h>
#include <kconfig.h>
#include <kaction.h>
#include <kiconloader.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <qlayout.h>
#include <qtoolbutton.h>
#include <kpushbutton.h>
#include <qcheckbox.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qvgroupbox.h>
#include <kguiitem.h>
#include <qpopupmenu.h>
#include <qtextedit.h>
#include <qlayout.h>
#include <qlabel.h>
#include <kdialogbase.h>
#include <qhttp.h>
#include <kurl.h>
#include <kinputdialog.h>
#include <qvalidator.h>
#include <qaction.h>
#include <kdebug.h>
#include <pwd.h>
#include <iostream>
#include "likeback.h"
#include "likeback_private.h"
/****************************************/
/********** class LikeBackBar: **********/
/****************************************/
LikeBackBar::LikeBackBar(LikeBack *likeBack)
: QWidget(0, "LikeBackBar", Qt::WX11BypassWM | Qt::WStyle_NoBorder | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop | Qt::WStyle_NoBorder | Qt::Qt::WGroupLeader)
, m_likeBack(likeBack)
{
QHBoxLayout *layout = new QHBoxLayout(this);
QIconSet likeIconSet = kapp->iconLoader()->loadIconSet("likeback_like", KIcon::Small);
QIconSet dislikeIconSet = kapp->iconLoader()->loadIconSet("likeback_dislike", KIcon::Small);
QIconSet bugIconSet = kapp->iconLoader()->loadIconSet("likeback_bug", KIcon::Small);
QIconSet featureIconSet = kapp->iconLoader()->loadIconSet("likeback_feature", KIcon::Small);
m_likeButton = new QToolButton(this, "likeback_like");
m_likeButton->setIconSet(likeIconSet);
m_likeButton->setTextLabel("<p>" + i18n("Send application developers a comment about something you like"));
m_likeButton->setAutoRaise(true);
connect( m_likeButton, SIGNAL(clicked()), this, SLOT(clickedLike()) );
layout->add(m_likeButton);
m_dislikeButton = new QToolButton(this, "likeback_dislike");
m_dislikeButton->setIconSet(dislikeIconSet);
m_dislikeButton->setTextLabel("<p>" + i18n("Send application developers a comment about something you dislike"));
m_dislikeButton->setAutoRaise(true);
connect( m_dislikeButton, SIGNAL(clicked()), this, SLOT(clickedDislike()) );
layout->add(m_dislikeButton);
m_bugButton = new QToolButton(this, "likeback_bug");
m_bugButton->setIconSet(bugIconSet);
m_bugButton->setTextLabel("<p>" + i18n("Send application developers a comment about an improper behavior of the application"));
m_bugButton->setAutoRaise(true);
connect( m_bugButton, SIGNAL(clicked()), this, SLOT(clickedBug()) );
layout->add(m_bugButton);
m_featureButton = new QToolButton(this, "likeback_feature");
m_featureButton->setIconSet(featureIconSet);
m_featureButton->setTextLabel("<p>" + i18n("Send application developers a comment about a new feature you desire"));
m_featureButton->setAutoRaise(true);
connect( m_featureButton, SIGNAL(clicked()), this, SLOT(clickedFeature()) );
layout->add(m_featureButton);
connect( &m_timer, SIGNAL(timeout()), this, SLOT(autoMove()) );
LikeBack::Button buttons = likeBack->buttons();
m_likeButton->setShown( buttons & LikeBack::Like );
m_dislikeButton->setShown( buttons & LikeBack::Dislike );
m_bugButton->setShown( buttons & LikeBack::Bug );
m_featureButton->setShown( buttons & LikeBack::Feature );
}
LikeBackBar::~LikeBackBar()
{
}
void LikeBackBar::startTimer()
{
m_timer.start(10);
}
void LikeBackBar::stopTimer()
{
m_timer.stop();
}
void LikeBackBar::autoMove()
{
static QWidget *lastWindow = 0;
QWidget *window = kapp->activeWindow();
// When a Kicker applet has the focus, like the Commandline QLineEdit,
// the systemtray icon indicates to be the current window and the LikeBack is shown next to the system tray icon.
// It's obviously bad ;-) :
bool shouldShow = (m_likeBack->userWantsToShowBar() && m_likeBack->enabledBar() && window && !window->inherits("KSystemTray"));
if (shouldShow) {
//move(window->x() + window->width() - 100 - width(), window->y());
//move(window->x() + window->width() - 100 - width(), window->mapToGlobal(QPoint(0, 0)).y() - height());
move(window->mapToGlobal(QPoint(0, 0)).x() + window->width() - width(), window->mapToGlobal(QPoint(0, 0)).y() + 1);
if (window != lastWindow && m_likeBack->windowNamesListing() != LikeBack::NoListing) {
if (qstricmp(window->name(), "") == 0 || qstricmp(window->name(), "unnamed") == 0) {
std::cout << "===== LikeBack ===== UNNAMED ACTIVE WINDOW OF TYPE " << window->className() << " ======" << LikeBack::activeWindowPath() << std::endl;
} else if (m_likeBack->windowNamesListing() == LikeBack::AllWindows) {
std::cout << "LikeBack: Active Window: " << LikeBack::activeWindowPath() << std::endl;
}
}
lastWindow = window;
}
// Show or hide the bar accordingly:
if (shouldShow && !isShown()) {
show();
} else if (!shouldShow && isShown()) {
hide();
}
}
void LikeBackBar::clickedLike()
{
m_likeBack->execCommentDialog(LikeBack::Like);
}
void LikeBackBar::clickedDislike()
{
m_likeBack->execCommentDialog(LikeBack::Dislike);
}
void LikeBackBar::clickedBug()
{
m_likeBack->execCommentDialog(LikeBack::Bug);
}
void LikeBackBar::clickedFeature()
{
m_likeBack->execCommentDialog(LikeBack::Feature);
}
/********************************************/
/********** class LikeBackPrivate: **********/
/********************************************/
LikeBackPrivate::LikeBackPrivate()
: bar(0)
, config(0)
, aboutData(0)
, buttons(LikeBack::DefaultButtons)
, hostName()
, remotePath()
, hostPort(80)
, acceptedLocales()
, acceptedLanguagesMessage()
, windowListing(LikeBack::NoListing)
, showBar(false)
, disabledCount(0)
, fetchedEmail()
, action(0)
{
}
LikeBackPrivate::~LikeBackPrivate()
{
delete bar;
delete action;
config = 0;
aboutData = 0;
}
/*************************************/
/********** class LikeBack: **********/
/*************************************/
LikeBack::LikeBack(Button buttons, bool showBarByDefault, KConfig *config, const KAboutData *aboutData)
: QObject()
{
// Initialize properties (1/2):
d = new LikeBackPrivate();
d->buttons = buttons;
d->config = config;
d->aboutData = aboutData;
d->showBarByDefault = showBarByDefault;
// Use default KApplication config and aboutData if not provided:
if (d->config == 0)
d->config = kapp->config();
if (d->aboutData == 0)
d->aboutData = kapp->aboutData();
// Initialize properties (2/2) [Needs aboutData to be set]:
d->showBar = userWantsToShowBar();
// Fetch the KControl user email address as a default one:
if (!emailAddressAlreadyProvided())
fetchUserEmail();
// Initialize the button-bar:
d->bar = new LikeBackBar(this);
d->bar->resize(d->bar->sizeHint());
// Show the information message if it is the first time, and if the button-bar is shown:
static const char *messageShown = "LikeBack_starting_information";
if (d->showBar && KMessageBox::shouldBeShownContinue(messageShown)) {
showInformationMessage();
KMessageBox::saveDontShowAgainContinue(messageShown);
}
// Show the bar if that's wanted by the developer or the user:
if (d->showBar)
QTimer::singleShot( 0, d->bar, SLOT(startTimer()) );
#if 0
disableBar();
// Alex: Oh, it drove me nuts
d->buttons = (Button) ( 0); showInformationMessage();
d->buttons = (Button) ( Feature); showInformationMessage();
d->buttons = (Button) ( Bug ); showInformationMessage();
d->buttons = (Button) ( Bug | Feature); showInformationMessage();
d->buttons = (Button) ( Dislike ); showInformationMessage();
d->buttons = (Button) ( Dislike | Feature); showInformationMessage();
d->buttons = (Button) ( Dislike | Bug ); showInformationMessage();
d->buttons = (Button) ( Dislike | Bug | Feature); showInformationMessage();
d->buttons = (Button) (Like ); showInformationMessage();
d->buttons = (Button) (Like | Feature); showInformationMessage();
d->buttons = (Button) (Like | Bug ); showInformationMessage();
d->buttons = (Button) (Like | Bug | Feature); showInformationMessage();
d->buttons = (Button) (Like | Dislike ); showInformationMessage();
d->buttons = (Button) (Like | Dislike | Feature); showInformationMessage();
d->buttons = (Button) (Like | Dislike | Bug ); showInformationMessage();
d->buttons = (Button) (Like | Dislike | Bug | Feature); showInformationMessage();
enableBar();
#endif
}
LikeBack::~LikeBack()
{
delete d;
}
void LikeBack::setWindowNamesListing(WindowListing windowListing)
{
d->windowListing = windowListing;
}
LikeBack::WindowListing LikeBack::windowNamesListing()
{
return d->windowListing;
}
void LikeBack::setAcceptedLanguages(const QStringList &locales, const QString &message)
{
d->acceptedLocales = locales;
d->acceptedLanguagesMessage = message;
}
QStringList LikeBack::acceptedLocales()
{
return d->acceptedLocales;
}
QString LikeBack::acceptedLanguagesMessage()
{
return d->acceptedLanguagesMessage;
}
void LikeBack::setServer(const QString &hostName, const QString &remotePath, Q_UINT16 hostPort)
{
d->hostName = hostName;
d->remotePath = remotePath;
d->hostPort = hostPort;
}
QString LikeBack::hostName()
{
return d->hostName;
}
QString LikeBack::remotePath()
{
return d->remotePath;
}
Q_UINT16 LikeBack::hostPort()
{
return d->hostPort;
}
void LikeBack::disableBar()
{
d->disabledCount++;
if (d->bar && d->disabledCount > 0) {
d->bar->hide();
d->bar->stopTimer();
}
}
void LikeBack::enableBar()
{
d->disabledCount--;
if (d->disabledCount < 0)
std::cerr << "===== LikeBack ===== Enabled more times than it was disabled. Please refer to the disableBar() documentation for more information and hints." << std::endl;
if (d->bar && d->disabledCount <= 0) {
d->bar->startTimer();
}
}
bool LikeBack::enabledBar()
{
return d->disabledCount <= 0;
}
void LikeBack::execCommentDialog(Button type, const QString &initialComment, const QString &windowPath, const QString &context)
{
disableBar();
LikeBackDialog dialog(type, initialComment, windowPath, context, this);
dialog.exec();
enableBar();
}
void LikeBack::execCommentDialogFromHelp()
{
execCommentDialog(AllButtons, /*initialComment=*/"", /*windowPath=*/"HelpMenuAction");
}
LikeBack::Button LikeBack::buttons()
{
return d->buttons;
}
const KAboutData* LikeBack::aboutData()
{
return d->aboutData;
}
KConfig* LikeBack::config()
{
return d->config;
}
KAction* LikeBack::sendACommentAction(KActionCollection *parent)
{
if (d->action == 0)
d->action = new KAction(
i18n("&Send a Comment to Developers"), /*icon=*/"mail_new", /*shortcut=*/"",
this, SLOT(execCommentDialog()),
parent, "likeback_send_a_comment"
);
return d->action;
}
bool LikeBack::userWantsToShowBar()
{
// Store the button-bar per version, so it can be disabled by the developer for the final version:
d->config->setGroup("LikeBack");
return d->config->readBoolEntry("userWantToShowBarForVersion_" + d->aboutData->version(), d->showBarByDefault);
}
void LikeBack::setUserWantsToShowBar(bool showBar)
{
if (showBar == d->showBar)
return;
d->showBar = showBar;
// Store the button-bar per version, so it can be disabled by the developer for the final version:
d->config->setGroup("LikeBack");
d->config->writeEntry("userWantToShowBarForVersion_" + d->aboutData->version(), showBar);
d->config->sync(); // Make sure the option is saved, even if the application crashes after that.
if (showBar)
d->bar->startTimer();
}
void LikeBack::showInformationMessage()
{
// Load and register the images needed by the message:
QPixmap likeIcon = kapp->iconLoader()->loadIcon("likeback_like", KIcon::Small);
QPixmap dislikeIcon = kapp->iconLoader()->loadIcon("likeback_dislike", KIcon::Small);
QPixmap bugIcon = kapp->iconLoader()->loadIcon("likeback_bug", KIcon::Small);
QPixmap featureIcon = kapp->iconLoader()->loadIcon("likeback_feature", KIcon::Small);
QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_like", likeIcon);
QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_dislike", dislikeIcon);
QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_bug", bugIcon);
QMimeSourceFactory::defaultFactory()->setPixmap("likeback_icon_feature", featureIcon);
// Show a message reflecting the allowed types of comment:
Button buttons = d->buttons;
int nbButtons = (buttons & Like ? 1 : 0) +
(buttons & Dislike ? 1 : 0) +
(buttons & Bug ? 1 : 0) +
(buttons & Feature ? 1 : 0);
KMessageBox::information(0,
"<p><b>" + (isDevelopmentVersion(d->aboutData->version()) ?
i18n("Welcome to this testing version of %1.") :
i18n("Welcome to %1.")
).arg(d->aboutData->programName()) + "</b></p>"
"<p>" + i18n("To help us improve it, your comments are important.") + "</p>"
"<p>" +
((buttons & LikeBack::Like) && (buttons & LikeBack::Dislike) ?
i18n("Each time you have a great or frustrating experience, "
"please click the appropriate face below the window title-bar, "
"briefly describe what you like or dislike and click Send.")
: (buttons & LikeBack::Like ?
i18n("Each time you have a great experience, "
"please click the smiling face below the window title-bar, "
"briefly describe what you like and click Send.")
: (buttons & LikeBack::Dislike ?
i18n("Each time you have a frustrating experience, "
"please click the frowning face below the window title-bar, "
"briefly describe what you dislike and click Send.")
:
QString()
))) + "</p>" +
(buttons & LikeBack::Bug ?
"<p>" +
(buttons & (LikeBack::Like | LikeBack::Dislike) ?
i18n("Follow the same principle to quickly report a bug: "
"just click the broken-object icon in the top-right corner of the window, describe it and click Send.")
:
i18n("Each time you discover a bug in the application, "
"please click the broken-object icon below the window title-bar, "
"briefly describe the mis-behaviour and click Send.")
) + "</p>"
: "") +
"<p>" + i18n("Example:", "Examples:", nbButtons) + "</p>" +
(buttons & LikeBack::Like ?
"<p><img source=\"likeback_icon_like\"> &nbsp;" +
i18n("<b>I like</b> the new artwork. Very refreshing.") + "</p>"
: "") +
(buttons & LikeBack::Dislike ?
"<p><img source=\"likeback_icon_dislike\"> &nbsp;" +
i18n("<b>I dislike</b> the welcome page of that assistant. Too time consuming.") + "</p>"
: "") +
(buttons & LikeBack::Bug ?
"<p><img source=\"likeback_icon_bug\"> &nbsp;" +
i18n("<b>The application has an improper behaviour</b> when clicking the Add button. Nothing happens.") + "</p>"
: "") +
(buttons & LikeBack::Feature ?
"<p><img source=\"likeback_icon_feature\"> &nbsp;" +
i18n("<b>I desire a new feature</b> allowing me to send my work by email.") + "</p>"
: "") +
"</tr></table>",
i18n("Help Improve the Application"));
// Reset the images from the factory:
QMimeSourceFactory::defaultFactory()->setData("likeback_icon_like", 0L);
QMimeSourceFactory::defaultFactory()->setData("likeback_icon_dislike", 0L);
QMimeSourceFactory::defaultFactory()->setData("likeback_icon_bug", 0L);
QMimeSourceFactory::defaultFactory()->setData("likeback_icon_feature", 0L);
}
QString LikeBack::activeWindowPath()
{
// Compute the window hierarchy (from the latest to the oldest):
QStringList windowNames;
QWidget *window = kapp->activeWindow();
while (window) {
QString name = window->name();
// Append the class name to the window name if it is unnamed:
if (name == "unnamed")
name += QString(":") + window->className();
windowNames.append(name);
window = dynamic_cast<QWidget*>(window->parent());
}
// Create the string of windows starting by the end (from the oldest to the latest):
QString windowPath;
for (int i = ((int)windowNames.count()) - 1; i >= 0; i--) {
if (windowPath.isEmpty())
windowPath = windowNames[i];
else
windowPath += QString("~~") + windowNames[i];
}
// Finally return the computed path:
return windowPath;
}
bool LikeBack::emailAddressAlreadyProvided()
{
d->config->setGroup("LikeBack");
return d->config->readBoolEntry("emailAlreadyAsked", false);
}
QString LikeBack::emailAddress()
{
if (!emailAddressAlreadyProvided())
askEmailAddress();
d->config->setGroup("LikeBack");
return d->config->readEntry("emailAddress", "");
}
void LikeBack::setEmailAddress(const QString &address, bool userProvided)
{
d->config->setGroup("LikeBack");
d->config->writeEntry("emailAddress", address);
d->config->writeEntry("emailAlreadyAsked", userProvided || emailAddressAlreadyProvided());
d->config->sync(); // Make sure the option is saved, even if the application crashes after that.
}
void LikeBack::askEmailAddress()
{
d->config->setGroup("LikeBack");
QString currentEmailAddress = d->config->readEntry("emailAddress", "");
if (!emailAddressAlreadyProvided() && !d->fetchedEmail.isEmpty())
currentEmailAddress = d->fetchedEmail;
bool ok;
QString emailExpString = "[\\w-\\.]+@[\\w-\\.]+\\.[\\w]+";
//QString namedEmailExpString = "[.]*[ \\t]+<" + emailExpString + '>';
//QRegExp emailExp("^(|" + emailExpString + '|' + namedEmailExpString + ")$");
QRegExp emailExp("^(|" + emailExpString + ")$");
QRegExpValidator emailValidator(emailExp, this);
disableBar();
QString email = KInputDialog::getText(
i18n("Email Address"),
"<p><b>" + i18n("Please provide your email address.") + "</b></p>" +
"<p>" + i18n("It will only be used to contact you back if more information is needed about your comments, ask you how to reproduce the bugs you report, send bug corrections for you to test, etc.") + "</p>" +
"<p>" + i18n("The email address is optional. If you do not provide any, your comments will be sent anonymously.") + "</p>",
currentEmailAddress, &ok, kapp->activeWindow(), /*name=*/(const char*)0, &emailValidator);
enableBar();
if (ok)
setEmailAddress(email);
}
// FIXME: Should be moved to KAboutData? Cigogne will also need it.
bool LikeBack::isDevelopmentVersion(const QString &version)
{
return version.find("alpha", /*index=*/0, /*caseSensitive=*/false) != -1 ||
version.find("beta", /*index=*/0, /*caseSensitive=*/false) != -1 ||
version.find("rc", /*index=*/0, /*caseSensitive=*/false) != -1 ||
version.find("svn", /*index=*/0, /*caseSensitive=*/false) != -1 ||
version.find("cvs", /*index=*/0, /*caseSensitive=*/false) != -1;
}
/**
* Code from KBugReport::slotConfigureEmail() in kdeui/kbugreport.cpp:
*/
/*void LikeBack::beginFetchingEmail()
{
if (m_process)
return;
m_process = new KProcess();
*m_process << QString::fromLatin1("kcmshell") << QString::fromLatin1("kcm_useraccount");
connect( m_process, SIGNAL(processExited(KProcess*)), SLOT(fetchUserEmail()) );
if (!m_process->start()) {
kdDebug() << "Couldn't start kcmshell.." << endl;
delete m_process;
m_process = 0;
return;
}
// m_configureEmail->setEnabled(false);
}*/
/**
* Code from KBugReport::slotSetFrom() in kdeui/kbugreport.cpp:
*/
void LikeBack::fetchUserEmail()
{
// delete m_process;
// m_process = 0;
// m_configureEmail->setEnabled(true);
// ### KDE4: why oh why is KEmailSettings in kio?
KConfig emailConf( QString::fromLatin1("emaildefaults") );
// find out the default profile
emailConf.setGroup(QString::fromLatin1("Defaults"));
QString profile = QString::fromLatin1("PROFILE_");
profile += emailConf.readEntry(QString::fromLatin1("Profile"), QString::fromLatin1("Default"));
emailConf.setGroup(profile);
QString fromaddr = emailConf.readEntry(QString::fromLatin1("EmailAddress"));
if (fromaddr.isEmpty()) {
struct passwd *p;
p = getpwuid(getuid());
d->fetchedEmail = QString::fromLatin1(p->pw_name);
} else {
QString name = emailConf.readEntry(QString::fromLatin1("FullName"));
if (!name.isEmpty())
d->fetchedEmail = /*name + QString::fromLatin1(" <") +*/ fromaddr /*+ QString::fromLatin1(">")*/;
}
// m_from->setText( fromaddr );
}
/*******************************************/
/********** class LikeBackDialog: **********/
/*******************************************/
LikeBackDialog::LikeBackDialog(LikeBack::Button reason, const QString &initialComment, const QString &windowPath, const QString &context, LikeBack *likeBack)
: KDialogBase(KDialogBase::Swallow, i18n("Send a Comment to Developers"), KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Default,
KDialogBase::Ok, kapp->activeWindow(), /*name=*/"_likeback_feedback_window_", /*modal=*/true, /*separator=*/true)
, m_likeBack(likeBack)
, m_windowPath(windowPath)
, m_context(context)
{
// If no specific "reason" is provided, choose the first one:
if (reason == LikeBack::AllButtons) {
LikeBack::Button buttons = m_likeBack->buttons();
int firstButton = 0;
if (firstButton == 0 && (buttons & LikeBack::Like)) firstButton = LikeBack::Like;
if (firstButton == 0 && (buttons & LikeBack::Dislike)) firstButton = LikeBack::Dislike;
if (firstButton == 0 && (buttons & LikeBack::Bug)) firstButton = LikeBack::Bug;
if (firstButton == 0 && (buttons & LikeBack::Feature)) firstButton = LikeBack::Feature;
reason = (LikeBack::Button) firstButton;
}
// If no window path is provided, get the current active window path:
if (m_windowPath.isEmpty())
m_windowPath = LikeBack::activeWindowPath();
QWidget *page = new QWidget(this);
QVBoxLayout *pageLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
// The introduction message:
QLabel *introduction = new QLabel(introductionText(), page);
pageLayout->addWidget(introduction);
// The comment group:
m_group = new QButtonGroup(0);//i18n("Send Application Developers a Comment About:"), page);
QVGroupBox *box = new QVGroupBox(i18n("Send Application Developers a Comment About:"), page);
pageLayout->addWidget(box);
// The radio buttons:
QWidget *buttons = new QWidget(box);
QGridLayout *buttonsGrid = new QGridLayout(buttons, /*nbRows=*/4, /*nbColumns=*/2, /*margin=*/0, spacingHint());
if (m_likeBack->buttons() & LikeBack::Like) {
QPixmap likePixmap = kapp->iconLoader()->loadIcon("likeback_like", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true);
QLabel *likeIcon = new QLabel(buttons);
likeIcon->setPixmap(likePixmap);
likeIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QRadioButton *likeButton = new QRadioButton(i18n("Something you &like"), buttons);
buttonsGrid->addWidget(likeIcon, /*row=*/0, /*column=*/0);
buttonsGrid->addWidget(likeButton, /*row=*/0, /*column=*/1);
m_group->insert(likeButton, LikeBack::Like);
}
if (m_likeBack->buttons() & LikeBack::Dislike) {
QPixmap dislikePixmap = kapp->iconLoader()->loadIcon("likeback_dislike", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true);
QLabel *dislikeIcon = new QLabel(buttons);
dislikeIcon->setPixmap(dislikePixmap);
dislikeIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QRadioButton *dislikeButton = new QRadioButton(i18n("Something you &dislike"), buttons);
buttonsGrid->addWidget(dislikeIcon, /*row=*/1, /*column=*/0);
buttonsGrid->addWidget(dislikeButton, /*row=*/1, /*column=*/1);
m_group->insert(dislikeButton, LikeBack::Dislike);
}
if (m_likeBack->buttons() & LikeBack::Bug) {
QPixmap bugPixmap = kapp->iconLoader()->loadIcon("likeback_bug", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true);
QLabel *bugIcon = new QLabel(buttons);
bugIcon->setPixmap(bugPixmap);
bugIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QRadioButton *bugButton = new QRadioButton(i18n("An improper &behavior of this application"), buttons);
buttonsGrid->addWidget(bugIcon, /*row=*/2, /*column=*/0);
buttonsGrid->addWidget(bugButton, /*row=*/2, /*column=*/1);
m_group->insert(bugButton, LikeBack::Bug);
}
if (m_likeBack->buttons() & LikeBack::Feature) {
QPixmap featurePixmap = kapp->iconLoader()->loadIcon("likeback_feature", KIcon::NoGroup, 16, KIcon::DefaultState, 0L, true);
QLabel *featureIcon = new QLabel(buttons);
featureIcon->setPixmap(featurePixmap);
featureIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QRadioButton *featureButton = new QRadioButton(i18n("A new &feature you desire"), buttons);
buttonsGrid->addWidget(featureIcon, /*row=*/3, /*column=*/0);
buttonsGrid->addWidget(featureButton, /*row=*/3, /*column=*/1);
m_group->insert(featureButton, LikeBack::Feature);
}
m_group->setButton(reason);
// The comment text box:
m_comment = new QTextEdit(box);
m_comment->setTabChangesFocus(true);
m_comment->setTextFormat(QTextEdit::PlainText);
m_comment->setText(initialComment);
m_showButtons = new QCheckBox(i18n("Show comment buttons below &window titlebars"), page);
m_showButtons->setChecked(m_likeBack->userWantsToShowBar());
pageLayout->addWidget(m_showButtons);
connect( m_showButtons, SIGNAL(stateChanged(int)), this, SLOT(changeButtonBarVisible()) );
setButtonOK(KGuiItem(i18n("&Send Comment"), "mail_send"));
enableButtonOK(false);
connect( m_comment, SIGNAL(textChanged()), this, SLOT(commentChanged()) );
setButtonGuiItem(Default, KGuiItem(i18n("&Email Address..."), "mail_generic"));
resize(QSize(kapp->desktop()->width() * 1 / 2, kapp->desktop()->height() * 3 / 5).expandedTo(sizeHint()));
QAction *sendShortcut = new QAction(this);
sendShortcut->setAccel(QString("Ctrl+Return"));
connect( sendShortcut, SIGNAL(activated()), actionButton(Ok), SLOT(animateClick()) );
setMainWidget(page);
}
LikeBackDialog::~LikeBackDialog()
{
}
QString LikeBackDialog::introductionText()
{
QString text = "<p>" + i18n("Please provide a brief description of your opinion of %1.").arg(m_likeBack->aboutData()->programName()) + " ";
QString languagesMessage = "";
if (!m_likeBack->acceptedLocales().isEmpty() && !m_likeBack->acceptedLanguagesMessage().isEmpty()) {
languagesMessage = m_likeBack->acceptedLanguagesMessage();
QStringList locales = m_likeBack->acceptedLocales();
for (QStringList::Iterator it = locales.begin(); it != locales.end(); ++it) {
QString locale = *it;
if (KGlobal::locale()->language().startsWith(locale))
languagesMessage = "";
}
} else {
if (!KGlobal::locale()->language().startsWith("en"))
languagesMessage = i18n("Please write in English.");
}
if (!languagesMessage.isEmpty())
// TODO: Replace the URL with a localized one:
text += languagesMessage + " " +
i18n("You may be able to use an <a href=\"%1\">online translation tool</a>.")
.arg("http://www.google.com/language_tools?hl=" + KGlobal::locale()->language())
+ " ";
// If both "I Like" and "I Dislike" buttons are shown and one is clicked:
if ((m_likeBack->buttons() & LikeBack::Like) && (m_likeBack->buttons() & LikeBack::Dislike))
text += i18n("To make the comments you send more useful in improving this application, try to send the same amount of positive and negative comments.") + " ";
if (!(m_likeBack->buttons() & LikeBack::Feature))
text += i18n("Do <b>not</b> ask for new features: your requests will be ignored.");
return text;
}
void LikeBackDialog::polish()
{
KDialogBase::polish();
m_comment->setFocus();
}
void LikeBackDialog::slotDefault()
{
m_likeBack->askEmailAddress();
}
void LikeBackDialog::slotOk()
{
send();
}
void LikeBackDialog::changeButtonBarVisible()
{
m_likeBack->setUserWantsToShowBar(m_showButtons->isChecked());
}
void LikeBackDialog::commentChanged()
{
QPushButton *sendButton = actionButton(Ok);
sendButton->setEnabled(!m_comment->text().isEmpty());
}
void LikeBackDialog::send()
{
QString emailAddress = m_likeBack->emailAddress();
int reason = m_group->selectedId();
QString type = (reason == LikeBack::Like ? "Like" : (reason == LikeBack::Dislike ? "Dislike" : (reason == LikeBack::Bug ? "Bug" : "Feature")));
QString data =
"protocol=" + KURL::encode_string("1.0") + '&' +
"type=" + KURL::encode_string(type) + '&' +
"version=" + KURL::encode_string(m_likeBack->aboutData()->version()) + '&' +
"locale=" + KURL::encode_string(KGlobal::locale()->language()) + '&' +
"window=" + KURL::encode_string(m_windowPath) + '&' +
"context=" + KURL::encode_string(m_context) + '&' +
"comment=" + KURL::encode_string(m_comment->text()) + '&' +
"email=" + KURL::encode_string(emailAddress);
QHttp *http = new QHttp(m_likeBack->hostName(), m_likeBack->hostPort());
std::cout << "http://" << m_likeBack->hostName() << ":" << m_likeBack->hostPort() << m_likeBack->remotePath() << std::endl;
std::cout << data << std::endl;
connect( http, SIGNAL(requestFinished(int, bool)), this, SLOT(requestFinished(int, bool)) );
QHttpRequestHeader header("POST", m_likeBack->remotePath());
header.setValue("Host", m_likeBack->hostName());
header.setValue("Content-Type", "application/x-www-form-urlencoded");
http->setHost(m_likeBack->hostName());
http->request(header, data.utf8());
m_comment->setEnabled(false);
}
void LikeBackDialog::requestFinished(int /*id*/, bool error)
{
// TODO: Save to file if error (connection not present at the moment)
m_comment->setEnabled(true);
m_likeBack->disableBar();
if (error) {
KMessageBox::error(this, i18n("<p>Error while trying to send the report.</p><p>Please retry later.</p>"), i18n("Transfer Error"));
} else {
KMessageBox::information(
this,
i18n("<p>Your comment has been sent successfully. It will help improve the application.</p><p>Thanks for your time.</p>"),
i18n("Comment Sent")
);
close();
}
m_likeBack->enableBar();
KDialogBase::slotOk();
}
#include "likeback_private.moc.cpp"
#include "likeback.moc"

@ -0,0 +1,364 @@
/***************************************************************************
* Copyright (C) 2006 by Sebastien Laout *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library 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 Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#ifndef LIKEBACK_H
#define LIKEBACK_H
#include <qobject.h>
class KConfig;
class KAboutData;
class KAction;
class KActionCollection;
class LikeBackPrivate;
class LikeBackBar;
class LikeBackDialog;
/**
* @short System to Get Quick Feedback from Beta-Testers
*
* This system allows users to communicate theire liking of the application to its developers.
* Thus, developers know what theire users prefer of theire applications, what should be enhanced, etc.
*
* Basically, how does it work?
* Whenever the user notice something good he appreciate or something he do not like, do not understand, do not find polished...
* he can send a few short words to the developers to tell them what he like or do not like. It is only two or three clicks away.
* It is fast and efficient.
*
* This greatly lowers the communication barrier between the application developers and the application users.
* It makes the developers understand and satisfy better the needs of the users.
*
* The LikeBack system has 5 components:
* @li In the application: The comment dialog, where the user write a comment, select a type of comment, etc.
* @li In the application: The KAction to plug in the Help menu. This action displays the comment dialog.
* @li In the application: The button-bar, that floats bellow titlebar of every windows of the application, and let the user to quickly show the comment dialog.
* The button-bar can be hidden.
* @li On the server: A PHP script that collects every comments that users send. The LikeBack object should be configured to contact that server.
* @li On the server: The developer interface. It lists every comments that were sent, let you sort them, add remarks to them, and mark them as fixed or another status.
*
* Here is an example of code to call to quickly setup LikeBack on the client:
* @code
* // Instanciate the LikeBack system, and show the first-use information dialog if the button-bar is shown:
* LikeBack *likeBack = new LikeBack(LikeBack::AllButtons, LikeBack::isDevelopmentVersion(kapp->aboutData->version())); // Show button-bar only in beta-versions
* likeBack->setServer("myapp.kde.org", "/likeback/send.php");
* likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Please write in English or French."));
*
* // Comment the following line once you are sure all your windows have a name:
* likeBack->setWindowNamesListing(LikeBack::WarnUnnamedWindows);
*
* // This line should be called early in your KMainWindow constructor because it references actionCollection().
* // It should be called before createGUI() for the action to be plugged in the Help menu:
* likeBack->sendACommentAction(actionCollection());
* @endcode
*
* @see Visit http://basket.kde.org/likeback.php for more information, screenshots, a tutorial, hints, return of experiences, and to download the server-side developer interface...
* @author Sebastien Laout <slaout@linux62.org>
*/
class LikeBack : public QObject
{
Q_OBJECT
public:
/**
* Ids of every LikeBack buttons the button-bar can have.
* The four first values are each individual buttons you can enable or not.
* The next ones are combinations: all buttons at once, and the default set of buttons (Like, Dislike).
* Those values are used in the constructor, to set the allowed type of comments, and when triggering the comment dialog, to set the default checked type.
* @See The LikeBack constructor and execCommentDialog().
*/
enum Button {
Like = 0x01, /// The user select that option to report a positive experience he got with the application.
Dislike = 0x02, /// The user select that option to report a frustrating experience he got with the application.
Bug = 0x04, /// The user select that option to report a bug in the application.
Feature = 0x10, /// The user select that option to ask for a new feature he desire.
/// If not enabled, the user is explicitely informed she cannot ask for new features.
AllButtons = Like | Dislike | Bug | Feature, /// Usable in the constructor to enable every posible buttons.
DefaultButtons = Like | Dislike /// Usable in the constructor to enable only the recommended default set of buttons.
};
/**
* Flags letting LikeBack print out name and path of each window you show during execution, for debugging purpose.
* @See The method setWindowNamesListing() explains how to use those values.
*/
enum WindowListing {
NoListing = 0, /// Do not print out any window name. For release time.
WarnUnnamedWindows = 1, /// Each time the user option a window, print out a message if the window is unnamed. For development needs, to check windows.
AllWindows = 2 /// Print out the window hierarchy of each opened windows during execution. For development needs, to check every windows have an understandable name.
};
/**
* You only need to call the constructor once, typically in main.cpp.
* Even if you do not show the button-bar by default, you should instanciate LikeBack,
* to include its action in the Help menu of your application, to let the users send comments or activate the bar.
* @param buttons The types of comments you want to get. Determine which radio-buttons are shown in the comment dialog,
* and which ones are displayed in the button-bar. Default buttons do not show the Bug and Feature buttons because you are
* likely to already have a way to get bug and feature reports (most of the time, it is a bugs.kde.org account).
* If you do not have that, then use the value LikeBack::AllButtons to show every possible buttons.
* @param showBarByDefault Determines if the floating button-bar should also be shown, in addition to the action in the Help menu.
* Advise: to avoid getting too much noise, enable it only if it is a small application or a development release.
* Notes: This is only a default value, the user will be able to enable or disabled the bar afterward.
* The button-bar display is stored by version. On a new version, your default value will take effect again.
* This allow you to disable the button-bar once the version is stable enought to be released as final.
* @param config Set the configuration file where to store the user email address and if the button-bar should be shown.
* By default (null), the KApplication configuration object is used.
* @param aboutData Set the KAboutData instance used to get the application name and version. By default (null), the KApplication about data object is used.
* The application name is only used in the first-use information message.
* The version is used to store the button-bar visibility per version (can be shown in a development version but not in a final one...)
* and to send with the comment, so you can filter per version and know if a comment refers the latest version of the application or not.
*/
LikeBack(Button buttons = DefaultButtons, bool showBarByDefault = false, KConfig *config = 0, const KAboutData *aboutData = 0);
/**
* Destructor.
* Also hide the button-bar, if it was shown.
* Be careful, the KAction is deleted. Do not use it afterward, and take care to unplug it before destroying this LikeBack instance.
*/
~LikeBack();
/**
* This method is interesting while setting up the system for the first time.
* LikeBack send the current window name (and hierarchy) with the comment. This allows you to put the comments in theire context.
* So, of course, you are encouraged to give a name to your windows. It is done in the constructor of the widgets.
* This method allows to output the name of the current window to the standard output.
* So you can use the application, open all the windows, and when you see a warning, you know which window you should assign a name.
* @see The WindowListing flags for an enumeration and explaining of every possibilities.
* @Note If you do not name your windows, the name of the classes will be sent. So it is not that grave.
*/
void setWindowNamesListing(WindowListing windowListing);
/**
* @Returns The window listing flag.
* @see setWindowNamesListing()
*/
WindowListing windowNamesListing();
/**
* By default, only English comments are accepted. The user is informed she must write in this language by a sentence placed in the comment dialog.
* If you have people talking other languages in your development team, it can be interesting to call this method to define the accepted locales (languages),
* and provide a message to inform users. The developer interface on the server let developers view comments in theire locale.
* Note that no verification is done to check if the user used the right language, it would be impossible.
* The list of locales is there to make it possible to NOT show the message for users of the accepted languages.
* For instance, if you accept only English and French, and that the application run in a French environment,
* it is likely the user is French and will write comments using French. Telling him he should write in French is unnecessary and redundant.
* Passing an empty list and an empty string to the method will make LikeBack display the default message telling the user only English is accepted.
* Example of call you can quickly copy, paste and adapt:
* @code
* likeBack->setAcceptedLanguages(QStringList::split(";", "en;fr"), i18n("Please write in English or French."));
* @endcode
* @Note During tests, if you do not see the sentence, it is because you are running the application with an "accepted language": do not be surprised ;-)
* @param locales The list of locales where the message does not need to be shown. See TODO TODO for a list of available locales for you to choose.
* @param message The message to displays to the user to tell him what languages are accepted to write his comments.
*/
void setAcceptedLanguages(const QStringList &locales, const QString &message);
/**
* @Returns The list of accepted locales for the user to write comments.
* @see setAcceptedLanguages()
*/
QStringList acceptedLocales();
/**
* @Returns The message displayed to users who are not running the application in an accepted locale.
* @see setAcceptedLanguages()
*/
QString acceptedLanguagesMessage();
/**
* Set the path where LikeBack should send every comments.
* It is composed of the server host name, the path to the PHP script used to send comments, and optionnaly a port number if it is not 80.
* This call is mandatory for LikeBack to work.
* @param hostName The server host name to contact when sending comments. For instance "myapp.kde.org".
* @param remotePath The path to the send script on the server. For instance, "/likeback/send.php".
* @param hostPort Optionnal port used to contact the server using the HTTP protocol. By default, it is port 80.
*/
void setServer(const QString &hostName, const QString &remotePath, Q_UINT16 hostPort = 80);
/**
* @Returns The server host name to contact when sending comments.
* @see setServer()
*/
QString hostName();
/**
* @Returns The path to the send script on the server.
* @see setServer()
*/
QString remotePath();
/**
* @Returns The port used to contact the server using the HTTP protocol.
* @see setServer()
*/
Q_UINT16 hostPort();
/**
* Get the KAction letting user to show the comment dialog.
* You should plug it in your Help menu, just bellow the "Report a Bug" action, or replace it.
* Adding the action below "Report a Bug" or replacing "Report a Bug" depends on your application and if you have a Bugzilla account.
* If you do not have a Bugzilla account, LikeBack is a good way for your small application to get bug reports: remove "Report a Bug".
* For more information about how to configure LikeBack depending on your application size and settings, see the constructor documentation.
* @Note The action is named "likeback_send_a_comment". So you should add the following XML in the *ui.rc file of your application:
* @code
* <Action name="likeback_send_a_comment" />
* @endcode
*/
KAction* sendACommentAction(KActionCollection *parent = 0);
/**
* @Returns The path of the currently active window. Each windows are separated with "~~".
* Normally, you should not need to call this method since it is used to send the window path.
* But if you call execCommentDialog(), you could need to use it.
*/
static QString activeWindowPath();
/**
* @Returns The combination of buttons that are shown in the comment dialog and the button-bar.
*/
Button buttons();
/**
* @Returns true if the button-bar is currently enabled. Ie, if it has been re-enabled as many times as it has been disabled.
* @see The method disableBar() for more information on how enabling/disabling works.
*/
bool enabledBar();
public slots:
/**
* Temporarily disable the button-bar: it is hiden from the screen if it was shown.
* Does not affect anything if the user has not choosen to show the button-bar.
* @Note Calls to enableBar() and disableBar() are ref-counted.
* This means that the number of times disableBar() is called is memorized,
* and enableBar() will only have effect after it has been called as many times as disableBar() was called before.
* So, make sure to always call enableBar() the same number of times ou called disableBar().
* And please make sure to ALWAYS call disableBar() BEFORE enableBar().
* In the counter-case, another code could call disableBar() and EXCPECT the bar to be disabled. But it will not, because its call only canceled yours.
* @Note Sometimes, you will absolutely need to call enableBar() before disableBar().
* For instance, MyWindow::show() calls enableBar() and MyWindow::hide() calls disableBar().
* This is the trick used to show the LikeBack button-bar of a Kontact plugin only when the main widget of that plugin is active.
* In this case, call disableBar() at the begin of your program, so the disable count will never be negative.
* @Note If the bar is enabled, it does not mean the bar is shown. For that, the developer (using showBarByDefault in the construcor)
* or the user (by checking the checkbox in the comment dialog) have to explicitely show the bar.
*/
void disableBar();
/**
* Re-enable the button-bar one time.
* @see The method disableBar() for more information on how enabling/disabling works.
*/
void enableBar();
/**
* Show the first-use information dialog telling the user the meaning of the LikeBack system and giving examples of every comment types.
*/
void showInformationMessage();
/**
* Popup the comment dialog.
* With no parameter, it popups in the default configuration: the first type is checked, empty message, current window path, and empty context.
* You can use the following parameters to customize how it should appears:
* @param type Which radiobutton should be checked when poping up. AllButton, the default value, means the first available type will be checked.
* @param initialComment The text to put in the comment text area. Allows you to popup the dialog in some special circumstances,
* like to let the user report an internal error by populating the comment area with technical details useful for you to debug.
* @param windowPath The window path to send with the comment. If empty (the default), the current window path is took.
* Separate window names with "~~". For instance "MainWindow~~NewFile~~FileOpen".
* If you popup the dialog after an error occurred, you can put the error name in that field (if the window path has no sense in that context).
* When the dialog is popuped up from the sendACommentAction() KAction, this value is "HelpMenu", because there is no way to know if the user
* is commenting a thing he found/thinked about in a sub-dialog.
* @param context Not used for the moment. Will allow more fine-grained application status report.
*/
void execCommentDialog(Button type = AllButtons, const QString &initialComment = "", const QString &windowPath = "", const QString &context = "");
/**
* Popups the dialog for the user to set his email address.
* The popup will always be shown, even if the user already provided an email address.
*/
void askEmailAddress();
private:
LikeBackPrivate *d;
/**
* Get the user email address from KControl.
*/
void fetchUserEmail();
private slots:
/**
* Slot triggered by the "Help -> Send a Comment to Developers" KAction.
* It popups the comment dialog, and set the window path to "HelpMenuAction",
* because current window path has no meaning in that case.
*/
void execCommentDialogFromHelp();
public:
/**
* @Returns true if the user has enabled the LikeBack bar for this version.
*/
bool userWantsToShowBar();
/**
* Explicitely set if the floating button-bar should be shown or not.
* Tehorically, this choice should only be left to the user,
* and to the developers for the default value, already provided in the constructor.
*/
void setUserWantsToShowBar(bool showBar);
/**
* @Returns A pointer to the KAboutData used to determin the application name and version.
* @See The LikeBack constructor for more information.
*/
const KAboutData *aboutData();
/**
* @Returns A pointer to the KConfig used to store user configuration (email address, if the button-bar should be shown).
* @See The LikeBack constructor for more information.
*/
KConfig *config();
/**
* During the first comment sending, the user is invited to enter his email address for the developers to be able to contact him back.
* He is only asked once, or he can set or change it by using the bottom-left button in the comment dialog.
* @Returns true if the user has already configured his email address.
*/
bool emailAddressAlreadyProvided();
/**
* @Returns The email user address, or ask it to the user if he have not provided or ignored it.
* @Returns An empty string if the user cancelled the request dialog.
*/
QString emailAddress();
/**
* Define or re-define the user email address.
* LikeBack will not ask it again to the user, unless you set @p userProvided to false.
* Then, this call can be considered as setting the default email address, that the user should confirm later.
*/
void setEmailAddress(const QString &address, bool userProvided = true);
/**
* @Returns true if @p version is an Alpha, Beta, RC, SVN or CVS version.
* You can use this static method in the constructor to enable the button-bar by default only during beta-releases.
*/
static bool isDevelopmentVersion(const QString &version);
};
#endif // LIKEBACK_H

@ -0,0 +1,105 @@
/***************************************************************************
* Copyright (C) 2006 by Sebastien Laout *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library 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 Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#ifndef LIKEBACK_PRIVATE_H
#define LIKEBACK_PRIVATE_H
#include <kdialogbase.h>
#include <qtimer.h>
#include "likeback.h"
class QToolButton;
class QTextEdit;
class QCheckBox;
class QButtonGroup;
class Kaction;
class LikeBackPrivate
{
public:
LikeBackPrivate();
~LikeBackPrivate();
LikeBackBar *bar;
KConfig *config;
const KAboutData *aboutData;
LikeBack::Button buttons;
QString hostName;
QString remotePath;
Q_UINT16 hostPort;
QStringList acceptedLocales;
QString acceptedLanguagesMessage;
LikeBack::WindowListing windowListing;
bool showBarByDefault;
bool showBar;
int disabledCount;
QString fetchedEmail;
KAction *action;
};
class LikeBackBar : public QWidget
{
Q_OBJECT
public:
LikeBackBar(LikeBack *likeBack);
~LikeBackBar();
public slots:
void startTimer();
void stopTimer();
private slots:
void autoMove();
void clickedLike();
void clickedDislike();
void clickedBug();
void clickedFeature();
private:
LikeBack *m_likeBack;
QTimer m_timer;
QToolButton *m_likeButton;
QToolButton *m_dislikeButton;
QToolButton *m_bugButton;
QToolButton *m_featureButton;
};
class LikeBackDialog : public KDialogBase
{
Q_OBJECT
public:
LikeBackDialog(LikeBack::Button reason, const QString &initialComment, const QString &windowPath, const QString &context, LikeBack *likeBack);
~LikeBackDialog();
private:
LikeBack *m_likeBack;
QString m_windowPath;
QString m_context;
QButtonGroup *m_group;
QTextEdit *m_comment;
QCheckBox *m_showButtons;
QString introductionText();
private slots:
void polish();
void slotDefault();
void slotOk();
void changeButtonBarVisible();
void commentChanged();
void send();
void requestFinished(int id, bool error);
};
#endif // LIKEBACK_PRIVATE_H

@ -0,0 +1,695 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qlabel.h>
#include <kurl.h>
#include <qlayout.h>
#include <kiconloader.h>
#include <qcursor.h>
#include <klocale.h>
#include <qpushbutton.h>
#include <qcheckbox.h>
#include <qcombobox.h>
#include <qhgroupbox.h>
#include <qpainter.h>
#include <kglobalsettings.h>
#include <qstyle.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kdialogbase.h>
#include <kcmodule.h>
#include <kdebug.h>
#include "linklabel.h"
#include "variouswidgets.h"
#include "tools.h"
#include "global.h"
#include "kcolorcombo2.h"
#include "htmlexporter.h"
/** LinkLook */
LinkLook *LinkLook::soundLook = new LinkLook(/*useLinkColor=*/false, /*canPreview=*/false);
LinkLook *LinkLook::fileLook = new LinkLook(/*useLinkColor=*/false, /*canPreview=*/true);
LinkLook *LinkLook::localLinkLook = new LinkLook(/*useLinkColor=*/true, /*canPreview=*/true);
LinkLook *LinkLook::networkLinkLook = new LinkLook(/*useLinkColor=*/true, /*canPreview=*/false);
LinkLook *LinkLook::launcherLook = new LinkLook(/*useLinkColor=*/true, /*canPreview=*/false);
LinkLook::LinkLook(bool useLinkColor, bool canPreview)
{
m_useLinkColor = useLinkColor;
m_canPreview = canPreview;
m_iconSize = 0;
}
LinkLook::LinkLook(const LinkLook &other)
{
m_useLinkColor = other.useLinkColor();
m_canPreview = other.canPreview();
setLook( other.italic(), other.bold(), other.underlining(),
other.color(), other.hoverColor(),
other.iconSize(), other.preview() );
}
void LinkLook::setLook(bool italic, bool bold, int underlining,
QColor color, QColor hoverColor,
int iconSize, int preview)
{
m_italic = italic;
m_bold = bold;
m_underlining = underlining;
m_color = color;
m_hoverColor = hoverColor;
m_iconSize = iconSize;
m_preview = (canPreview() ? preview : None);
}
int LinkLook::previewSize() const
{
if (previewEnabled()) {
switch (preview()) {
default:
case None: return 0;
case IconSize: return iconSize();
case TwiceIconSize: return iconSize() * 2;
case ThreeIconSize: return iconSize() * 3;
}
} else
return 0;
}
QColor LinkLook::effectiveColor() const
{
if (m_color.isValid())
return m_color;
else
return defaultColor();
}
QColor LinkLook::effectiveHoverColor() const
{
if (m_hoverColor.isValid())
return m_hoverColor;
else
return defaultHoverColor();
}
QColor LinkLook::defaultColor() const
{
if (m_useLinkColor)
return KGlobalSettings::linkColor();
else
return KGlobalSettings::textColor();
}
QColor LinkLook::defaultHoverColor() const
{
return Qt::red;
}
LinkLook* LinkLook::lookForURL(const KURL &url)
{
return url.isLocalFile() ? localLinkLook : networkLinkLook;
}
QString LinkLook::toCSS(const QString &cssClass, const QColor &defaultTextColor) const
{
// Set the link class:
QString css = QString(" .%1 a { display: block; width: 100%;").arg(cssClass);
if (underlineOutside())
css += " text-decoration: underline;";
else
css += " text-decoration: none;";
if (m_italic == true)
css += " font-style: italic;";
if (m_bold == true)
css += " font-weight: bold;";
QColor textColor = (color().isValid() || m_useLinkColor ? effectiveColor() : defaultTextColor);
css += QString(" color: %1; }\n").arg(textColor.name());
// Set the hover state class:
QString hover;
if (m_underlining == OnMouseHover)
hover = "text-decoration: underline;";
else if (m_underlining == OnMouseOutside)
hover = "text-decoration: none;";
if (effectiveHoverColor() != effectiveColor()) {
if (!hover.isEmpty())
hover += " ";
hover += QString("color: %4;").arg(effectiveHoverColor().name());
}
// But include it only if it contain a different style than non-hover state:
if (!hover.isEmpty())
css += QString(" .%1 a:hover { %2 }\n").arg(cssClass, hover);
return css;
}
/** LinkLabel */
LinkLabel::LinkLabel(int hAlign, int vAlign, QWidget *parent, const char *name, WFlags f)
: QFrame(parent, name, f), m_isSelected(false), m_isHovered(false), m_look(0)
{
initLabel(hAlign, vAlign);
}
LinkLabel::LinkLabel(const QString &title, const QString &icon, LinkLook *look, int hAlign, int vAlign,
QWidget *parent, const char *name, WFlags f)
: QFrame(parent, name, f), m_isSelected(false), m_isHovered(false), m_look(0)
{
initLabel(hAlign, vAlign);
setLink(title, icon, look);
}
void LinkLabel::initLabel(int hAlign, int vAlign)
{
m_layout = new QBoxLayout(this, QBoxLayout::LeftToRight);
m_icon = new QLabel(this);
m_title = new QLabel(this);
m_spacer1 = new QSpacerItem(0, 0, QSizePolicy::Preferred/*Expanding*/, QSizePolicy::Preferred/*Expanding*/);
m_spacer2 = new QSpacerItem(0, 0, QSizePolicy::Preferred/*Expanding*/, QSizePolicy::Preferred/*Expanding*/);
m_hAlign = hAlign;
m_vAlign = vAlign;
m_title->setTextFormat(Qt::PlainText);
// DEGUB:
//m_icon->setPaletteBackgroundColor("lightblue");
//m_title->setPaletteBackgroundColor("lightyellow");
}
LinkLabel::~LinkLabel()
{
}
void LinkLabel::setLink(const QString &title, const QString &icon, LinkLook *look)
{
if (look)
m_look = look; // Needed for icon size
m_title->setText(title);
m_title->setShown( ! title.isEmpty() );
if (icon.isEmpty())
m_icon->clear();
else {
QPixmap pixmap = DesktopIcon(icon, m_look->iconSize(), m_look->iconSize(), kapp);
if (!pixmap.isNull())
m_icon->setPixmap(pixmap);
}
m_icon->setShown( ! icon.isEmpty() );
if (look)
setLook(look);
}
void LinkLabel::setLook(LinkLook *look) // FIXME: called externaly (so, without setLink()) it's buggy (icon not
{
m_look = look;
QFont font;
font.setBold(look->bold());
font.setUnderline(look->underlineOutside());
font.setItalic(look->italic());
m_title->setFont(font);
m_title->setPaletteForegroundColor( m_isSelected ? KApplication::palette().active().highlightedText() : look->effectiveColor() );
m_icon->setShown( m_icon->pixmap() && ! m_icon->pixmap()->isNull() );
setAlign(m_hAlign, m_vAlign);
}
void LinkLabel::setAlign(int hAlign, int vAlign)
{
m_hAlign = hAlign;
m_vAlign = vAlign;
if (!m_look)
return;
// Define alignment flags :
//FIXME TODO: Use directly flags !
int hFlag, vFlag, wBreak;
switch (hAlign) {
default:
case 0: hFlag = Qt::AlignLeft; break;
case 1: hFlag = Qt::AlignHCenter; break;
case 2: hFlag = Qt::AlignRight; break;
}
switch (vAlign) {
case 0: vFlag = Qt::AlignTop; break;
default:
case 1: vFlag = Qt::AlignVCenter; break;
case 2: vFlag = Qt::AlignBottom; break;
}
wBreak = Qt::WordBreak * (hAlign != 1);
// Clear the widget :
m_layout->removeItem(m_spacer1);
m_layout->remove(m_icon);
m_layout->remove(m_title);
m_layout->removeItem(m_spacer2);
// Otherwise, minimumSize will be incoherent (last size ? )
m_layout->setResizeMode(QLayout::Minimum);
// And re-populate the widget with the appropriates things and order
bool addSpacers = hAlign == 1;
m_layout->setDirection(QBoxLayout::LeftToRight);
//m_title->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum/*Expanding*/, 0, 0, false) );
m_icon->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred/*Expanding*/, 0, 0, false) );
m_spacer1->changeSize( 0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred/*Expanding*/ );
m_spacer2->changeSize( 0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred/*Expanding*/ );
m_icon->setAlignment( hFlag | vFlag );
m_title->setAlignment( hFlag | vFlag | wBreak );
if ( addSpacers && (vAlign != 0) ||
(m_title->text().isEmpty() && hAlign == 2) )
m_layout->addItem(m_spacer1);
if (hAlign == 2) { // If align at right, icon is at right
m_layout->addWidget(m_title);
m_layout->addWidget(m_icon);
} else {
m_layout->addWidget(m_icon);
m_layout->addWidget(m_title);
}
if ( addSpacers && (vAlign != 2) ||
(m_title->text().isEmpty() && hAlign == 0) )
m_layout->addItem(m_spacer2);
}
void LinkLabel::enterEvent(QEvent*)
{
m_isHovered = true;
if ( ! m_isSelected )
m_title->setPaletteForegroundColor(m_look->effectiveHoverColor());
QFont font = m_title->font();
font.setUnderline(m_look->underlineInside());
m_title->setFont(font);
}
void LinkLabel::leaveEvent(QEvent*)
{
m_isHovered = false;
if ( ! m_isSelected )
m_title->setPaletteForegroundColor(m_look->effectiveColor());
QFont font = m_title->font();
font.setUnderline(m_look->underlineOutside());
m_title->setFont(font);
}
void LinkLabel::setSelected(bool selected)
{
m_isSelected = selected;
if (selected)
m_title->setPaletteForegroundColor(KApplication::palette().active().highlightedText());
else if (m_isHovered)
m_title->setPaletteForegroundColor(m_look->effectiveHoverColor());
else
m_title->setPaletteForegroundColor(m_look->effectiveColor());
}
void LinkLabel::setPaletteBackgroundColor(const QColor &color)
{
QFrame::setPaletteBackgroundColor(color);
m_title->setPaletteBackgroundColor(color);
}
int LinkLabel::heightForWidth(int w) const
{
int iconS = (m_icon->isShown()) ? m_look->iconSize() : 0; // Icon size
int iconW = iconS; // Icon width to remove to w
int titleH = (m_title->isShown()) ? m_title->heightForWidth(w - iconW) : 0; // Title height
return (titleH >= iconS) ? titleH : iconS; // No margin for the moment !
}
QString LinkLabel::toHtml(const QString &imageName)
{
QString begin = "<font color=" + m_look->effectiveColor().name() + ">";
QString end = "</font>";
if (m_look->italic()) {
begin += "<i>";
end.prepend("</i>");
}
if (m_look->bold()) {
begin += "<b>";
end.prepend("</b>");
}
if (m_look->underlineOutside()) {
begin += "<u>";
end.prepend("</u>");
}
if (m_icon->pixmap()) {
QPixmap icon(*m_icon->pixmap());
begin.prepend("<img src=" + imageName + " style=\"vertical-align: middle\"> ");
QMimeSourceFactory::defaultFactory()->setPixmap(imageName, icon);
} else
QMimeSourceFactory::defaultFactory()->setData(imageName, 0L);
return begin + Tools::textToHTMLWithoutP(m_title->text()) + end;
}
/** class LinkDisplay
*/
LinkDisplay::LinkDisplay()
: m_title(), m_icon(), m_preview(), m_look(0), m_font(), m_minWidth(0), m_width(0), m_height(0)
{
}
void LinkDisplay::setLink(const QString &title, const QString &icon, LinkLook *look, const QFont &font)
{
setLink(title, icon, m_preview, look, font);
}
void LinkDisplay::setLink(const QString &title, const QString &icon, const QPixmap &preview, LinkLook *look, const QFont &font)
{
m_title = title;
m_icon = icon;
m_preview = preview;
m_look = look;
m_font = font;
// "Constants":
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
int LINK_MARGIN = BUTTON_MARGIN + 2;
// Recompute m_minWidth:
QRect textRect = QFontMetrics(labelFont(font, false)).boundingRect(0, 0, /*width=*/1, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::WordBreak, m_title);
int iconPreviewWidth = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.width() : 0));
m_minWidth = BUTTON_MARGIN - 1 + iconPreviewWidth + LINK_MARGIN + textRect.width();
// Recompute m_maxWidth:
textRect = QFontMetrics(labelFont(font, false)).boundingRect(0, 0, /*width=*/50000000, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::WordBreak, m_title);
m_maxWidth = BUTTON_MARGIN - 1 + iconPreviewWidth + LINK_MARGIN + textRect.width();
// Adjust m_width:
if (m_width < m_minWidth)
setWidth(m_minWidth);
// Recompute m_height:
m_height = heightForWidth(m_width);
}
void LinkDisplay::setWidth(int width)
{
if (width < m_minWidth)
width = m_minWidth;
if (width != m_width) {
m_width = width;
m_height = heightForWidth(m_width);
}
}
/** Paint on @p painter
* in (@p x, @p y, @p width, @p height)
* using @p colorGroup for the button drawing (if @p isHovered)
* and the LinkLook color() for the text,
* unless [the LinkLook !color.isValid() and it does not useLinkColor()] or [@p isDefaultColor is false]: in this case it will use @p colorGroup.text().
* It will draw the button if @p isIconButtonHovered.
*/
void LinkDisplay::paint(QPainter *painter, int x, int y, int width, int height, const QColorGroup &colorGroup,
bool isDefaultColor, bool isSelected, bool isHovered, bool isIconButtonHovered) const
{
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
int LINK_MARGIN = BUTTON_MARGIN + 2;
QPixmap pixmap;
// Load the preview...:
if (!isHovered && m_look->previewEnabled() && !m_preview.isNull())
pixmap = m_preview;
// ... Or the icon (if no preview or if the "Open" icon should be shown):
else {
int iconSize = m_look->iconSize();
QString iconName = (isHovered ? Global::openNoteIcon() : m_icon);
KIcon::States iconState = (isIconButtonHovered ? KIcon::ActiveState : KIcon::DefaultState);
pixmap = kapp->iconLoader()->loadIcon(iconName, KIcon::Desktop, iconSize, iconState, 0L, /*canReturnNull=*/false);
}
int iconPreviewWidth = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.width() : 0));
int pixmapX = (iconPreviewWidth - pixmap.width()) / 2;
int pixmapY = (height - pixmap.height()) / 2;
// Draw the button (if any) and the icon:
if (isHovered)
kapp->style().drawPrimitive(QStyle::PE_ButtonCommand, painter, QRect(-1, -1, iconPreviewWidth + 2*BUTTON_MARGIN, height + 2),
colorGroup, QStyle::Style_Enabled | (isIconButtonHovered ? QStyle::Style_MouseOver : 0));
painter->drawPixmap(x + BUTTON_MARGIN - 1 + pixmapX, y + pixmapY, pixmap);
// Figure out the text color:
if (isSelected)
painter->setPen(KGlobalSettings::highlightedTextColor());
else if (isIconButtonHovered)
painter->setPen(m_look->effectiveHoverColor());
else if (!isDefaultColor || (!m_look->color().isValid() && !m_look->useLinkColor())) // If the color is FORCED or if the link color default to the text color:
painter->setPen(colorGroup.text());
else
painter->setPen(m_look->effectiveColor());
// Draw the text:
painter->setFont(labelFont(m_font, isIconButtonHovered));
painter->drawText(x + BUTTON_MARGIN - 1 + iconPreviewWidth + LINK_MARGIN, y, width - BUTTON_MARGIN + 1 - iconPreviewWidth - LINK_MARGIN, height,
Qt::AlignAuto | Qt::AlignVCenter | Qt::WordBreak, m_title);
}
QPixmap LinkDisplay::feedbackPixmap(int width, int height, const QColorGroup &colorGroup, bool isDefaultColor)
{
int theWidth = QMIN(width, maxWidth());
int theHeight = QMIN(height, heightForWidth(theWidth));
QPixmap pixmap(theWidth, theHeight);
pixmap.fill(colorGroup.background());
QPainter painter(&pixmap);
paint(&painter, 0, 0, theWidth, theHeight, colorGroup, isDefaultColor,
/*isSelected=*/false, /*isHovered=*/false, /*isIconButtonHovered=*/false);
painter.end();
return pixmap;
}
bool LinkDisplay::iconButtonAt(const QPoint &pos) const
{
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
// int LINK_MARGIN = BUTTON_MARGIN + 2;
int iconPreviewWidth = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.width() : 0));
return pos.x() <= BUTTON_MARGIN - 1 + iconPreviewWidth + BUTTON_MARGIN;
}
QRect LinkDisplay::iconButtonRect() const
{
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
// int LINK_MARGIN = BUTTON_MARGIN + 2;
int iconPreviewWidth = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.width() : 0));
return QRect(0, 0, BUTTON_MARGIN - 1 + iconPreviewWidth + BUTTON_MARGIN, m_height);
}
QFont LinkDisplay::labelFont(QFont font, bool isIconButtonHovered) const
{
if (m_look->italic())
font.setItalic(true);
if (m_look->bold())
font.setBold(true);
if (isIconButtonHovered) {
if (m_look->underlineInside())
font.setUnderline(true);
} else {
if (m_look->underlineOutside())
font.setUnderline(true);
}
return font;
}
int LinkDisplay::heightForWidth(int width) const
{
int BUTTON_MARGIN = kapp->style().pixelMetric(QStyle::PM_ButtonMargin);
int LINK_MARGIN = BUTTON_MARGIN + 2;
int iconPreviewWidth = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.width() : 0));
int iconPreviewHeight = QMAX(m_look->iconSize(), (m_look->previewEnabled() ? m_preview.height() : 0));
QRect textRect = QFontMetrics(labelFont(m_font, false)).boundingRect(0, 0, width - BUTTON_MARGIN + 1 - iconPreviewWidth - LINK_MARGIN, 500000, Qt::AlignAuto | Qt::AlignTop | Qt::WordBreak, m_title);
return QMAX(textRect.height(), iconPreviewHeight + 2*BUTTON_MARGIN - 2);
}
QString LinkDisplay::toHtml(const QString &/*imageName*/) const
{
// TODO
return "";
}
QString LinkDisplay::toHtml(HTMLExporter *exporter, const KURL &url, const QString &title)
{
QString linkIcon;
if (m_look->previewEnabled() && !m_preview.isNull()) {
QString fileName = Tools::fileNameForNewFile("preview_" + url.fileName() + ".png", exporter->iconsFolderPath);
QString fullPath = exporter->iconsFolderPath + fileName;
m_preview.save(fullPath, "PNG");
linkIcon = QString("<img src=\"%1\" width=\"%2\" height=\"%3\" alt=\"\">")
.arg(exporter->iconsFolderName + fileName, QString::number(m_preview.width()), QString::number(m_preview.height()));
} else {
linkIcon = exporter->iconsFolderName + exporter->copyIcon(m_icon, m_look->iconSize());
linkIcon = QString("<img src=\"%1\" width=\"%2\" height=\"%3\" alt=\"\">")
.arg(linkIcon, QString::number(m_look->iconSize()), QString::number(m_look->iconSize()));
}
QString linkTitle = Tools::textToHTMLWithoutP(title.isEmpty() ? m_title : title);
return QString("<a href=\"%1\">%2 %3</a>").arg(url.prettyURL(), linkIcon, linkTitle);
}
/** LinkLookEditWidget **/
LinkLookEditWidget::LinkLookEditWidget(KCModule *module, const QString exTitle, const QString exIcon,
QWidget *parent, const char *name, WFlags fl)
: QWidget(parent, name, fl)
{
QLabel *label;
QVBoxLayout *layout = new QVBoxLayout(this, KDialogBase::marginHint(), KDialogBase::spacingHint());
m_italic = new QCheckBox(i18n("I&talic"), this);
layout->addWidget(m_italic);
m_bold = new QCheckBox(i18n("&Bold"), this);
layout->addWidget(m_bold);
QGridLayout *gl = new QGridLayout(layout, /*rows=*//*(look->canPreview() ? 5 : 4)*/5, /*columns=*//*3*/4);
gl->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 1, /*2*/3);
m_underlining = new QComboBox(false, this);
m_underlining->insertItem(i18n("Always"));
m_underlining->insertItem(i18n("Never"));
m_underlining->insertItem(i18n("On mouse hovering"));
m_underlining->insertItem(i18n("When mouse is outside"));
label = new QLabel(m_underlining, i18n("&Underline:"), this);
gl->addWidget(label, 0, 0);
gl->addWidget(m_underlining, 0, 1);
m_color = new KColorCombo2(QRgb(), this);
label = new QLabel(m_color, i18n("Colo&r:"), this);
gl->addWidget(label, 1, 0);
gl->addWidget(m_color, 1, 1);
m_hoverColor = new KColorCombo2(QRgb(), this);
label = new QLabel(m_hoverColor, i18n("&Mouse hover color:"), this);
gl->addWidget(label, 2, 0);
gl->addWidget(m_hoverColor, 2, 1);
QHBoxLayout *icoLay = new QHBoxLayout(/*parent=*/0L, /*margin=*/0, KDialogBase::spacingHint());
m_iconSize = new IconSizeCombo(false, this);
icoLay->addWidget(m_iconSize);
label = new QLabel(m_iconSize, i18n("&Icon size:"), this);
gl->addWidget(label, 3, 0);
gl->addItem( icoLay, 3, 1);
m_preview = new QComboBox(false, this);
m_preview->insertItem(i18n("None"));
m_preview->insertItem(i18n("Icon size"));
m_preview->insertItem(i18n("Twice the icon size"));
m_preview->insertItem(i18n("Three times the icon size"));
m_label = new QLabel(m_preview, i18n("&Preview:"), this);
m_hLabel = new HelpLabel(
i18n("You disabled preview but still see images?"),
i18n("<p>This is normal because there are several type of notes.<br>"
"This setting only applies to file and local link notes.<br>"
"The images you see are image notes, not file notes.<br>"
"File notes are generic documents, whereas image notes are pictures you can draw in.</p>"
"<p>When dropping files to baskets, %1 detects their type and shows you the content of the files.<br>"
"For instance, when dropping image or text files, image and text notes are created for them.<br>"
"For type of files %2 does not understand, they are shown as generic file notes with just an icon or file preview and a filename.</p>"
"<p>If you do not want the application to create notes depending on the content of the files you drop, "
"go to the \"General\" page and uncheck \"Image or animation\" in the \"View Content of Added Files for the Following Types\" group.</p>")
// TODO: Note: you can resize down maximum size of images...
.arg(kapp->aboutData()->programName(), kapp->aboutData()->programName()),
this);
gl->addWidget(m_label, 4, 0);
gl->addWidget(m_preview, 4, 1);
gl->addMultiCellWidget(m_hLabel, /*fromRow=*/5, /*toRow=*/5, /*fromCol=*/1, /*toCol*/2);
QGroupBox *gb = new QHGroupBox(i18n("Example"), this);
m_exLook = new LinkLook;
m_example = new LinkLabel(exTitle, exIcon, m_exLook, 1, 1, gb);
m_example->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_example->setCursor(QCursor(Qt::PointingHandCursor));
layout->addWidget(gb);
m_exTitle = exTitle;
m_exIcon = exIcon;
connect( m_italic, SIGNAL(stateChanged(int)), this, SLOT(slotChangeLook()) );
connect( m_bold, SIGNAL(stateChanged(int)), this, SLOT(slotChangeLook()) );
connect( m_underlining, SIGNAL(activated(int)), this, SLOT(slotChangeLook()) );
connect( m_color, SIGNAL(changed(const QColor&)), this, SLOT(slotChangeLook()) );
connect( m_hoverColor, SIGNAL(changed(const QColor&)), this, SLOT(slotChangeLook()) );
connect( m_iconSize, SIGNAL(activated(int)), this, SLOT(slotChangeLook()) );
connect( m_preview, SIGNAL(activated(int)), this, SLOT(slotChangeLook()) );
connect( m_italic, SIGNAL(stateChanged(int)), module, SLOT(changed()) );
connect( m_bold, SIGNAL(stateChanged(int)), module, SLOT(changed()) );
connect( m_underlining, SIGNAL(activated(int)), module, SLOT(changed()) );
connect( m_color, SIGNAL(changed(const QColor&)), module, SLOT(changed()) );
connect( m_hoverColor, SIGNAL(changed(const QColor&)), module, SLOT(changed()) );
connect( m_iconSize, SIGNAL(activated(int)), module, SLOT(changed()) );
connect( m_preview, SIGNAL(activated(int)), module, SLOT(changed()) );
}
void LinkLookEditWidget::set(LinkLook *look)
{
m_look = look;
m_italic->setChecked(look->italic());
m_bold->setChecked(look->bold());
m_underlining->setCurrentItem(look->underlining());
m_preview->setCurrentItem(look->preview());
m_color->setDefaultColor(m_look->defaultColor());
m_color->setColor(m_look->color());
m_hoverColor->setDefaultColor(m_look->defaultHoverColor());
m_hoverColor->setColor(m_look->hoverColor());
m_iconSize->setSize(look->iconSize());
m_exLook = new LinkLook(*look);
m_example->setLook(m_exLook);
if (!look->canPreview()) {
m_label->setEnabled(false);
m_hLabel->setEnabled(false);
m_preview->setEnabled(false);
}
slotChangeLook();
}
void LinkLookEditWidget::slotChangeLook()
{
saveToLook(m_exLook);
m_example->setLink(m_exTitle, m_exIcon, m_exLook); // and can't reload it at another size
}
LinkLookEditWidget::~LinkLookEditWidget()
{
}
void LinkLookEditWidget::saveChanges()
{
saveToLook(m_look);
}
void LinkLookEditWidget::saveToLook(LinkLook *look)
{
look->setLook( m_italic->isOn(), m_bold->isOn(), m_underlining->currentItem(),
m_color->color(), m_hoverColor->color(),
m_iconSize->iconSize(), (look->canPreview() ? m_preview->currentItem() : LinkLook::None) );
}
#include "linklabel.moc"

@ -0,0 +1,208 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef LINKLABEL_H
#define LINKLABEL_H
#include <qframe.h>
class QString;
class KURL;
class QColor;
class QLabel;
class QBoxLayout;
class QSpacerItem;
class QPushButton;
class QCheckBox;
class QComboBox;
class KColorCombo2;
class IconSizeCombo;
class HTMLExporter;
class HelpLabel;
class KCModule;
/** Store the style of links
* @author S<EFBFBD>astien Laot
*/
class LinkLook
{
public:
enum Underlining { Always = 0, Never, OnMouseHover, OnMouseOutside };
enum Preview { None = 0, IconSize, TwiceIconSize, ThreeIconSize };
LinkLook(bool useLinkColor = true, bool canPreview = true);
LinkLook(const LinkLook &other);
void setLook( bool italic, bool bold, int underlining,
QColor color, QColor hoverColor,
int iconSize, int preview /*= None*/ );
inline bool italic() const { return m_italic; }
inline bool bold() const { return m_bold; }
inline int underlining() const { return m_underlining; }
inline QColor color() const { return m_color; }
inline QColor hoverColor() const { return m_hoverColor; }
inline int iconSize() const { return m_iconSize; }
inline int preview() const { return m_preview; }
inline bool useLinkColor() const { return m_useLinkColor; }
inline bool canPreview() const { return m_canPreview; }
/* Helpping Functions */
bool underlineOutside() const { return underlining() == Always || underlining() == OnMouseOutside; }
bool underlineInside() const { return underlining() == Always || underlining() == OnMouseHover; }
bool previewEnabled() const { return canPreview() && preview() > None; }
int previewSize() const;
QColor effectiveColor() const;
QColor effectiveHoverColor() const;
QColor defaultColor() const;
QColor defaultHoverColor() const;
QString toCSS(const QString &cssClass, const QColor &defaultTextColor) const;
private:
bool m_italic;
bool m_bold;
int m_underlining;
QColor m_color;
QColor m_hoverColor;
int m_iconSize;
int m_preview;
bool m_useLinkColor;
bool m_canPreview;
public:
/* Global Looks */
static LinkLook *soundLook;
static LinkLook *fileLook;
static LinkLook *localLinkLook;
static LinkLook *networkLinkLook;
static LinkLook *launcherLook;
/* Static method to get a LinkLook from an URL */
static LinkLook* lookForURL(const KURL &url);
};
/** Used to represent links with icon and specific look
* Note : This label will appear blank while LinkLook willn't be set
* @author S<EFBFBD>astien Laot
*/
class LinkLabel : public QFrame
{
Q_OBJECT
public:
LinkLabel(int hAlign, int vAlign, QWidget *parent = 0, const char *name = 0, WFlags f = 0);
LinkLabel(const QString &title, const QString &icon, LinkLook *look, int hAlign, int vAlign,
QWidget *parent = 0, const char *name = 0, WFlags f = 0);
~LinkLabel();
public:
void setLink(const QString &title, const QString &icon, LinkLook *look = 0);
void setLook(LinkLook *look);
void setAlign(int hAlign, int vAlign);
void setSelected(bool selected);
void setPaletteBackgroundColor(const QColor &color);
int heightForWidth(int w = -1) const;
QString toHtml(const QString &imageName);
protected:
void initLabel(int hAlign, int vAlign);
void enterEvent(QEvent*);
void leaveEvent(QEvent*);
private:
QBoxLayout *m_layout;
QLabel *m_icon;
QLabel *m_title;
QSpacerItem *m_spacer1;
QSpacerItem *m_spacer2;
bool m_isSelected;
bool m_isHovered;
LinkLook *m_look;
int m_hAlign;
int m_vAlign;
};
/** THE NEW CLASS TO DISPLAY Links FOR THE NEW BASKET ENGINE.
* We should get ride of class LinkLabel soon.
* And LinkLabel will be entirely rewritten to use this LinkDisplay as the drawing primitives.
* @author S<EFBFBD>astien Laot
*/
class LinkDisplay
{
public:
LinkDisplay(); /// << Create a new empty unselected LinkDisplay. Please then call setLink() to make sense.
// Configure the link displayer:
void setLink(const QString &title, const QString &icon, LinkLook *look, const QFont &font); /// << Change the content and disposition. minWidth(), width() & height() can have changed. Keep the old preview (if any)
void setLink(const QString &title, const QString &icon, const QPixmap &preview, LinkLook *look, const QFont &font); /// << Idem but change the preview too (or remove it if it is invalid)
void setWidth(int width); /// << Set a new width. @see height() that will be computed.
// Get its properties:
int minWidth() const { return m_minWidth; } /// << @return the minimum width to display this link.
int maxWidth() const { return m_maxWidth; } /// << @return the maximum width to display this link.
int width() const { return m_width; } /// << @return the width of the link. It is never less than minWidth()!
int height() const { return m_height; } /// << @return the height if the link after having set it a width.
// And finaly, use it:
void paint(QPainter *painter, int x, int y, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered, bool isIconButtonHovered) const; /// << Draw the link on a painter. Set textColor to be !isValid() to use the LinkLook color. Otherwise it will use this color!
QPixmap feedbackPixmap(int width, int height, const QColorGroup &colorGroup, bool isDefaultColor); /// << @return the pixmap to put under the cursor while dragging this object.
// Eventually get some information about the link display:
bool iconButtonAt(const QPoint &pos) const; /// << @return true if the icon button is under point @p pos.
QRect iconButtonRect() const; /// << @return the rectangle of the icon button.
// Utility function:
QFont labelFont(QFont font, bool isIconButtonHovered) const; /// << @return the font for this link, according to parent font AND LinkLook!
int heightForWidth(int width) const; /// << @return the needed height to display the link in function of a width.
QString toHtml(const QString &imageName) const; /// << Convert the link to HTML code, using the LinkLook to style it.
QString toHtml(HTMLExporter *exporter, const KURL &url, const QString &title = "");
private:
QString m_title;
QString m_icon;
QPixmap m_preview;
LinkLook *m_look;
QFont m_font;
int m_minWidth;
int m_maxWidth;
int m_width;
int m_height;
};
/** A widget to edit a LinkLook, showing a live example to the user.
* @author S<EFBFBD>astien Laot
*/
class LinkLookEditWidget : public QWidget
{
Q_OBJECT
public:
LinkLookEditWidget(KCModule* module, const QString exTitle, const QString exIcon,
QWidget *parent = 0, const char *name = 0, WFlags fl = 0);
~LinkLookEditWidget();
void saveChanges();
void saveToLook(LinkLook *look);
void set(LinkLook *look);
private slots:
void slotChangeLook();
protected:
LinkLook *m_look;
QCheckBox *m_italic;
QCheckBox *m_bold;
QComboBox *m_underlining;
KColorCombo2 *m_color;
KColorCombo2 *m_hoverColor;
IconSizeCombo *m_iconSize;
QComboBox *m_preview;
LinkLook *m_exLook;
LinkLabel *m_example;
QString m_exTitle;
QString m_exIcon;
HelpLabel *m_hLabel;
QLabel *m_label;
};
#endif // LINKLABEL_H

@ -0,0 +1,115 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <stdlib.h>
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <kiconloader.h>
#include <qpixmap.h>
#include <klocale.h>
#include <kglobalaccel.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <kconfig.h> // TMP IN ALPHA 1
#include "application.h"
#include "backgroundmanager.h"
#include "mainwindow.h"
#include "settings.h"
#include "global.h"
#include "debugwindow.h"
#include "notedrag.h"
#include "basket.h"
#include "aboutdata.h"
#include "basket_options.h"
#include "backup.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* Thanks to JuK for this Application class */
/*#if KDE_IS_VERSION( 3, 1, 90 )
typedef KUniqueApplication Application; // KDE 3.2 and later already re-show the main window
#else
class Application : public KUniqueApplication
{
public:
Application() : KUniqueApplication(true, true, false) {}
virtual ~Application() {}
virtual int newInstance() {
if (win)
win->setActive(true);
return KUniqueApplication::newInstance();
}
};
#endif
*/
int main(int argc, char *argv[])
{
// KCmdLineArgs::init will modify argv[0] so we remember it:
const char *argv0 = (argc >= 1 ? argv[0] : "");
KCmdLineArgs::init(argc, argv, Global::about());
KCmdLineArgs::addCmdLineOptions(basket_options);
KUniqueApplication::addCmdLineOptions();
//KUniqueApplication app;
Application app;
Backup::figureOutBinaryPath(argv0, app);
/* Main Window */
MainWindow* win = new MainWindow();
Global::bnpView->handleCommandLine();
app.setMainWidget(win);
// if (!(Settings::useSystray() && KCmdLineArgs::parsedArgs() && KCmdLineArgs::parsedArgs()->isSet("start-hidden")))
// win->show();
if (Settings::useSystray()) {
// The user wanted to not show the window (but it is already hidden by default, so we do nothing):
if (KCmdLineArgs::parsedArgs() && KCmdLineArgs::parsedArgs()->isSet("start-hidden"))
;
// When the application is restored by KDE session, restore its state:
else if (app.isRestored())
win->setShown(!Settings::startDocked());
// Else, the application has been launched explicitely by the user (KMenu, keyboard shortcut...), so he need it, we show it:
else
win->show();
} else
// No system tray icon: always show:
win->show();
// Self-test of the presence of basketui.rc (the only requiered file after basket executable)
if (Global::bnpView->popupMenu("basket") == 0L)
// An error message will be show by BNPView::popupMenu()
return 1;
/* Go */
int result = app.exec();
//return result;
exit(result); // Do not clean up memory to not crash while deleting the KApplication, or do not hang up on KDE exit
}

@ -0,0 +1,345 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qtabwidget.h>
#include <qlayout.h>
#include <qtooltip.h>
#include <qcursor.h>
#include <qwhatsthis.h>
#include <qvaluelist.h>
#include <qregexp.h>
#include <qbuttongroup.h>
#include <kstringhandler.h>
#include <ksqueezedtextlabel.h>
#include <qpoint.h>
#include <qpixmap.h>
#include <qinputdialog.h>
#include <kpopupmenu.h>
#include <kiconloader.h>
#include <kiconeffect.h>
#include <qiconset.h>
#include <kaction.h>
#include <kapp.h>
#include <klocale.h>
#include <kmenubar.h>
#include <kedittoolbar.h>
#include <kdebug.h>
#include <qsignalmapper.h>
#include <qstringlist.h>
#include <qpainter.h>
#include <qstyle.h>
#include <kglobalsettings.h>
#include <kstandarddirs.h>
#include <qdir.h>
#include <qstringlist.h>
#include <kmessagebox.h>
#include <kstatusbar.h>
#include <qtimer.h>
#include <qaction.h>
#include <kstdaccel.h>
#include <kglobalaccel.h>
#include <kkeydialog.h>
#include <kpassivepopup.h>
#include <kconfig.h>
#include <kcolordialog.h>
#include <kaboutdata.h>
#include <kdeversion.h>
#include <qdesktopwidget.h>
#include <kwin.h>
#include <kprogress.h>
#include "mainwindow.h"
#include "basket.h"
#include "basketproperties.h"
#include "note.h"
#include "noteedit.h"
#include "settings.h"
#include "global.h"
//#include "addbasketwizard.h"
#include "newbasketdialog.h"
#include "basketfactory.h"
#include "popupmenu.h"
#include "xmlwork.h"
#include "debugwindow.h"
#include "notefactory.h"
#include "notedrag.h"
#include "tools.h"
#include "tag.h"
#include "formatimporter.h"
#include "softwareimporters.h"
#include "regiongrabber.h"
#include "password.h"
#include "bnpview.h"
#include "systemtray.h"
#include "clickablelabel.h"
#include "basketstatusbar.h"
#include <iostream>
#include <ksettings/dialog.h>
#include <kcmultidialog.h>
/** Container */
MainWindow::MainWindow(QWidget *parent, const char *name)
: KMainWindow(parent, name != 0 ? name : "MainWindow"), m_settings(0), m_quit(false)
{
BasketStatusBar* bar = new BasketStatusBar(statusBar());
m_baskets = new BNPView(this, "BNPViewApp", this, actionCollection(), bar);
setCentralWidget(m_baskets);
setupActions();
statusBar()->show();
statusBar()->setSizeGripEnabled(true);
setAutoSaveSettings(/*groupName=*/QString::fromLatin1("MainWindow"), /*saveWindowSize=*//*FIXME:false:Why was it false??*/true);
// m_actShowToolbar->setChecked( toolBar()->isShown() );
m_actShowStatusbar->setChecked( statusBar()->isShown() );
connect( m_baskets, SIGNAL(setWindowCaption(const QString &)), this, SLOT(setCaption(const QString &)));
// InlineEditors::instance()->richTextToolBar();
setStandardToolBarMenuEnabled(true);
createGUI("basketui.rc");
applyMainWindowSettings(KGlobal::config(), autoSaveGroup());
}
MainWindow::~MainWindow()
{
saveMainWindowSettings(KGlobal::config(), autoSaveGroup());
delete m_settings;
}
void MainWindow::setupActions()
{
actQuit = KStdAction::quit( this, SLOT(quit()), actionCollection() );
new KAction(i18n("Minimize"), "", 0,
this, SLOT(minimizeRestore()), actionCollection(), "minimizeRestore" );
/** Settings : ************************************************************/
// m_actShowToolbar = KStdAction::showToolbar( this, SLOT(toggleToolBar()), actionCollection());
m_actShowStatusbar = KStdAction::showStatusbar( this, SLOT(toggleStatusBar()), actionCollection());
// m_actShowToolbar->setCheckedState( KGuiItem(i18n("Hide &Toolbar")) );
(void) KStdAction::keyBindings( this, SLOT(showShortcutsSettingsDialog()), actionCollection() );
(void) KStdAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection() );
//KAction *actCfgNotifs = KStdAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection() );
//actCfgNotifs->setEnabled(false); // Not yet implemented !
actAppConfig = KStdAction::preferences( this, SLOT(showSettingsDialog()), actionCollection() );
}
/*void MainWindow::toggleToolBar()
{
if (toolBar()->isVisible())
toolBar()->hide();
else
toolBar()->show();
saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
}*/
void MainWindow::toggleStatusBar()
{
if (statusBar()->isVisible())
statusBar()->hide();
else
statusBar()->show();
saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
}
void MainWindow::configureToolbars()
{
saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
KEditToolbar dlg(actionCollection());
connect( &dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()) );
dlg.exec();
}
void MainWindow::configureNotifications()
{
// TODO
// KNotifyDialog *dialog = new KNotifyDialog(this, "KNotifyDialog", false);
// dialog->show();
}
void MainWindow::slotNewToolbarConfig() // This is called when OK or Apply is clicked
{
// ...if you use any action list, use plugActionList on each here...
createGUI("basketui.rc"); // TODO: Reconnect tags menu aboutToShow() ??
if (!Global::bnpView->isPart())
Global::bnpView->connectTagsMenu(); // The Tags menu was created again!
plugActionList( QString::fromLatin1("go_baskets_list"), actBasketsList);
applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
}
void MainWindow::showSettingsDialog()
{
if(m_settings == 0)
m_settings = new KSettings::Dialog(kapp->activeWindow());
if (Global::mainWindow()) {
m_settings->dialog()->showButton(KDialogBase::Help, false); // Not implemented!
m_settings->dialog()->showButton(KDialogBase::Default, false); // Not implemented!
m_settings->dialog()->exec();
} else
m_settings->show();
}
void MainWindow::showShortcutsSettingsDialog()
{
KKeyDialog::configure(actionCollection(), "basketui.rc");
//.setCaption(..)
//actionCollection()->writeSettings();
}
void MainWindow::polish()
{
bool shouldSave = false;
// If position and size has never been set, set nice ones:
// - Set size to sizeHint()
// - Keep the window manager placing the window where it want and save this
if (Settings::mainWindowSize().isEmpty()) {
// std::cout << "Main Window Position: Initial Set in show()" << std::endl;
int defaultWidth = kapp->desktop()->width() * 5 / 6;
int defaultHeight = kapp->desktop()->height() * 5 / 6;
resize(defaultWidth, defaultHeight); // sizeHint() is bad (too small) and we want the user to have a good default area size
shouldSave = true;
} else {
// std::cout << "Main Window Position: Recall in show(x="
// << Settings::mainWindowPosition().x() << ", y=" << Settings::mainWindowPosition().y()
// << ", width=" << Settings::mainWindowSize().width() << ", height=" << Settings::mainWindowSize().height()
// << ")" << std::endl;
//move(Settings::mainWindowPosition());
//resize(Settings::mainWindowSize());
}
KMainWindow::polish();
if (shouldSave) {
// std::cout << "Main Window Position: Save size and position in show(x="
// << pos().x() << ", y=" << pos().y()
// << ", width=" << size().width() << ", height=" << size().height()
// << ")" << std::endl;
Settings::setMainWindowPosition(pos());
Settings::setMainWindowSize(size());
Settings::saveConfig();
}
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
// std::cout << "Main Window Position: Save size in resizeEvent(width=" << size().width() << ", height=" << size().height() << ") ; isMaximized="
// << (isMaximized() ? "true" : "false") << std::endl;
Settings::setMainWindowSize(size());
Settings::saveConfig();
// Added to make it work (previous lines do not work):
//saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
KMainWindow::resizeEvent(event);
}
void MainWindow::moveEvent(QMoveEvent *event)
{
// std::cout << "Main Window Position: Save position in moveEvent(x=" << pos().x() << ", y=" << pos().y() << ")" << std::endl;
Settings::setMainWindowPosition(pos());
Settings::saveConfig();
// Added to make it work (previous lines do not work):
//saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
KMainWindow::moveEvent(event);
}
bool MainWindow::queryExit()
{
hide();
return true;
}
void MainWindow::quit()
{
m_quit = true;
close();
}
bool MainWindow::queryClose()
{
/* if (m_shuttingDown) // Set in askForQuit(): we don't have to ask again
return true;*/
if (kapp->sessionSaving()) {
Settings::setStartDocked(false); // If queryClose() is called it's because the window is shown
Settings::saveConfig();
return true;
}
if (Settings::useSystray() && !m_quit) {
Global::systemTray->displayCloseMessage(i18n("Basket"));
hide();
return false;
} else
return askForQuit();
}
bool MainWindow::askForQuit()
{
QString message = i18n("<p>Do you really want to quit %1?</p>").arg(kapp->aboutData()->programName());
if (Settings::useSystray())
message += i18n("<p>Notice that you do not have to quit the application before ending your KDE session. "
"If you end your session while the application is still running, the application will be reloaded the next time you log in.</p>");
int really = KMessageBox::warningContinueCancel( this, message, i18n("Quit Confirm"),
KStdGuiItem::quit(), "confirmQuitAsking" );
if (really == KMessageBox::Cancel)
{
m_quit = false;
return false;
}
return true;
}
void MainWindow::minimizeRestore()
{
if(isVisible())
hide();
else
show();
}
void MainWindow::changeActive()
{
#if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
kapp->updateUserTimestamp(); // If "activate on mouse hovering systray", or "on drag throught systray"
Global::systemTray->toggleActive();
#else
setActive( ! isActiveWindow() );
#endif
}
#include "mainwindow.moc"

@ -0,0 +1,107 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef CONTAINER_H
#define CONTAINER_H
#include <kmainwindow.h>
#include <qtabbar.h>
#include <qtabwidget.h>
#include <qlabel.h>
#include <ksystemtray.h>
#include <qptrlist.h>
#include <qpoint.h>
#include <qclipboard.h>
#include <kaction.h>
#include <qpixmap.h>
#include <qdesktopwidget.h>
#include <qtimer.h>
#include <qsplitter.h>
class QWidget;
class QPoint;
class KAction;
class KToggleAction;
class QPopupMenu;
class QSignalMapper;
class QStringList;
class QToolTipGroup;
class KPassivePopup;
class Basket;
class DecoratedBasket;
class Container;
class RegionGrabber;
class NoteSelection;
class BNPView;
class ClickableLabel;
namespace KSettings { class Dialog; };
/** The window that contain baskets, organized by tabs.
* @author S<EFBFBD>astien Laot
*/
class MainWindow : public KMainWindow
{
Q_OBJECT
public:
/** Construtor, initializer and destructor */
MainWindow(QWidget *parent = 0, const char *name = 0);
~MainWindow();
private:
void setupActions();
public slots:
bool askForQuit();
/** Settings **/
// void toggleToolBar();
void toggleStatusBar();
void showShortcutsSettingsDialog();
void configureToolbars();
void configureNotifications();
void showSettingsDialog();
void minimizeRestore();
void quit();
void changeActive();
void slotNewToolbarConfig();
protected:
bool queryExit();
bool queryClose();
virtual void resizeEvent(QResizeEvent*);
virtual void moveEvent(QMoveEvent*);
public:
void polish();
private:
// Settings actions :
// KToggleAction *m_actShowToolbar;
KToggleAction *m_actShowStatusbar;
KAction *actQuit;
KAction *actAppConfig;
QPtrList<KAction> actBasketsList;
private:
QVBoxLayout *m_layout;
BNPView *m_baskets;
bool m_startDocked;
KSettings::Dialog *m_settings;
bool m_quit;
};
#endif // CONTAINER_H

@ -0,0 +1,333 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kicondialog.h>
#include <qlineedit.h>
#include <kiconview.h>
#include <qlayout.h>
#include <qlabel.h>
#include <klocale.h>
#include <kglobalsettings.h>
#include <kpushbutton.h>
#include <kguiitem.h>
#include <kmessagebox.h>
#include <qsize.h>
#include <qpainter.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <kmainwindow.h>
#include "newbasketdialog.h"
#include "basketfactory.h"
#include "basket.h"
#include "basketlistview.h"
#include "variouswidgets.h"
#include "kcolorcombo2.h"
#include "tools.h"
#include "global.h"
#include "bnpview.h"
/** class SingleSelectionKIconView: */
SingleSelectionKIconView::SingleSelectionKIconView(QWidget *parent, const char *name, WFlags f)
: KIconView(parent, name, f), m_lastSelected(0)
{
connect( this, SIGNAL(selectionChanged(QIconViewItem*)), this, SLOT(slotSelectionChanged(QIconViewItem*)) );
connect( this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) );
}
QDragObject* SingleSelectionKIconView::dragObject()
{
return 0;
}
void SingleSelectionKIconView::slotSelectionChanged(QIconViewItem *item)
{
if (item)
m_lastSelected = item;
}
void SingleSelectionKIconView::slotSelectionChanged()
{
if (m_lastSelected && !m_lastSelected->isSelected())
m_lastSelected->setSelected(true);
}
/** class NewBasketDefaultProperties: */
NewBasketDefaultProperties::NewBasketDefaultProperties()
: icon("")
, backgroundImage("")
, backgroundColor()
, textColor()
, freeLayout(false)
, columnCount(1)
{
}
/** class NewBasketDialog: */
NewBasketDialog::NewBasketDialog(Basket *parentBasket, const NewBasketDefaultProperties &defaultProperties, QWidget *parent)
: KDialogBase(KDialogBase::Swallow, i18n("New Basket"), KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"NewBasket", /*modal=*/true, /*separator=*/true)
, m_defaultProperties(defaultProperties)
{
QWidget *page = new QWidget(this);
QVBoxLayout *topLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
// Icon, Name and Background Color:
QHBoxLayout *nameLayout = new QHBoxLayout(0, marginHint()*2/3, spacingHint());
m_icon = new KIconButton(page);
m_icon->setIconType(KIcon::NoGroup, KIcon::Action);
m_icon->setIconSize(16);
m_icon->setIcon(m_defaultProperties.icon.isEmpty() ? "basket" : m_defaultProperties.icon);
int size = QMAX(m_icon->sizeHint().width(), m_icon->sizeHint().height());
m_icon->setFixedSize(size, size); // Make it square!
QToolTip::add(m_icon, i18n("Icon"));
m_name = new QLineEdit(/*i18n("Basket"), */page);
m_name->setMinimumWidth(m_name->fontMetrics().maxWidth()*20);
connect( m_name, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)) );
enableButtonOK(false);
QToolTip::add(m_name, i18n("Name"));
m_backgroundColor = new KColorCombo2(QColor(), KGlobalSettings::baseColor(), page);
m_backgroundColor->setColor(QColor());
m_backgroundColor->setFixedSize(m_backgroundColor->sizeHint());
m_backgroundColor->setColor(m_defaultProperties.backgroundColor);
QToolTip::add(m_backgroundColor, i18n("Background color"));
nameLayout->addWidget(m_icon);
nameLayout->addWidget(m_name);
nameLayout->addWidget(m_backgroundColor);
topLayout->addLayout(nameLayout);
QHBoxLayout *layout = new QHBoxLayout(/*parent=*/0, /*margin=*/0, spacingHint());
KPushButton *button = new KPushButton( KGuiItem(i18n("&Manage Templates..."), "configure"), page );
connect( button, SIGNAL(clicked()), this, SLOT(manageTemplates()) );
button->hide();
// Compute the right template to use as the default:
QString defaultTemplate = "free";
if (!m_defaultProperties.freeLayout) {
if (m_defaultProperties.columnCount == 1)
defaultTemplate = "1column";
else if (m_defaultProperties.columnCount == 2)
defaultTemplate = "2columns";
else
defaultTemplate = "3columns";
}
// Empty:
// * * * * *
// Personnal:
// *To Do
// Professionnal:
// *Meeting Summary
// Hobbies:
// *
m_templates = new SingleSelectionKIconView(page);
m_templates->setItemsMovable(false);
m_templates->setMode(KIconView::Select);
m_templates->setGridX(m_templates->maxItemWidth());
KIconViewItem *lastTemplate = 0;
QPixmap icon(40, 53);
QPainter painter(&icon);
painter.fillRect(0, 0, icon.width(), icon.height(), KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, icon.width(), icon.height());
painter.end();
lastTemplate = new KIconViewItem(m_templates, lastTemplate, i18n("One column"), icon);
if (defaultTemplate == "1column")
m_templates->setSelected(lastTemplate, true);
painter.begin(&icon);
painter.fillRect(0, 0, icon.width(), icon.height(), KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, icon.width(), icon.height());
painter.drawLine(icon.width() / 2, 0, icon.width() / 2, icon.height());
painter.end();
lastTemplate = new KIconViewItem(m_templates, lastTemplate, i18n("Two columns"), icon);
if (defaultTemplate == "2columns")
m_templates->setSelected(lastTemplate, true);
painter.begin(&icon);
painter.fillRect(0, 0, icon.width(), icon.height(), KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, icon.width(), icon.height());
painter.drawLine(icon.width() / 3, 0, icon.width() / 3, icon.height());
painter.drawLine(icon.width() * 2 / 3, 0, icon.width() * 2 / 3, icon.height());
painter.end();
lastTemplate = new KIconViewItem(m_templates, lastTemplate, i18n("Three columns"), icon);
if (defaultTemplate == "3columns")
m_templates->setSelected(lastTemplate, true);
painter.begin(&icon);
painter.fillRect(0, 0, icon.width(), icon.height(), KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, icon.width(), icon.height());
painter.drawRect(icon.width() / 5, icon.width() / 5, icon.width() / 4, icon.height() / 8);
painter.drawRect(icon.width() * 2 / 5, icon.width() * 2 / 5, icon.width() / 4, icon.height() / 8);
painter.end();
lastTemplate = new KIconViewItem(m_templates, lastTemplate, i18n("Free"), icon);
if (defaultTemplate == "free")
m_templates->setSelected(lastTemplate, true);
/* painter.begin(&icon);
painter.fillRect(0, 0, icon.width(), icon.height(), KGlobalSettings::baseColor());
painter.setPen(KGlobalSettings::textColor());
painter.drawRect(0, 0, icon.width(), icon.height());
painter.drawRect(icon.width() * 2 / 5, icon.height() * 3 / 7, icon.width() / 5, icon.height() / 7);
painter.end();
lastTemplate = new KIconViewItem(m_templates, lastTemplate, i18n("Mind map"), icon);*/
m_templates->setMinimumHeight(topLayout->minimumSize().width() * 9 / 16);
QLabel *label = new QLabel(m_templates, i18n("&Template:"), page);
layout->addWidget(label, /*stretch=*/0, Qt::AlignBottom);
layout->addStretch();
layout->addWidget(button, /*stretch=*/0, Qt::AlignBottom);
topLayout->addLayout(layout);
topLayout->addWidget(m_templates);
layout = new QHBoxLayout(/*parent=*/0, /*margin=*/0, spacingHint());
m_createIn = new QComboBox(page);
m_createIn->insertItem(i18n("(Baskets)"));
label = new QLabel(m_createIn, i18n("C&reate in:"), page);
HelpLabel *helpLabel = new HelpLabel(i18n("How is it useful?"), i18n(
"<p>Creating baskets inside of other baskets to form a hierarchy allows you to be more organized by eg.:</p><ul>"
"<li>Grouping baskets by themes or topics;</li>"
"<li>Grouping baskets in folders for different projects;</li>"
"<li>Making sections with sub-baskets representing chapters or pages;</li>"
"<li>Making a group of baskets to export together (to eg. email them to people).</li></ul>"), page);
layout->addWidget(label);
layout->addWidget(m_createIn);
layout->addWidget(helpLabel);
layout->addStretch();
topLayout->addLayout(layout);
m_basketsMap.clear();
m_basketsMap.insert(/*index=*/0, /*basket=*/0L);
populateBasketsList(Global::bnpView->firstListViewItem(), /*indent=*/1, /*index=*/1);
connect( m_templates, SIGNAL(doubleClicked(QIconViewItem*)), this, SLOT(slotOk()) );
connect( m_templates, SIGNAL(returnPressed(QIconViewItem*)), this, SLOT(returnPressed()) );
if (parentBasket) {
int index = 0;
for (QMap<int, Basket*>::Iterator it = m_basketsMap.begin(); it != m_basketsMap.end(); ++it)
if (it.data() == parentBasket) {
index = it.key();
break;
}
if (index <= 0)
return;
if (m_createIn->currentItem() != index)
m_createIn->setCurrentItem(index);
}
setMainWidget(page);
}
void NewBasketDialog::returnPressed()
{
actionButton(KDialogBase::Ok)->animateClick();
}
int NewBasketDialog::populateBasketsList(QListViewItem *item, int indent, int index)
{
static const int ICON_SIZE = 16;
while (item) {
// Get the basket data:
Basket *basket = ((BasketListViewItem*)item)->basket();
QPixmap icon = kapp->iconLoader()->loadIcon(basket->icon(), KIcon::NoGroup, ICON_SIZE, KIcon::DefaultState, 0L, /*canReturnNull=*/false);
icon = Tools::indentPixmap(icon, indent, 2 * ICON_SIZE / 3);
// Append item to the list:
m_createIn->insertItem(icon, basket->basketName());
m_basketsMap.insert(index, basket);
++index;
// Append childs of item to the list:
index = populateBasketsList(item->firstChild(), indent + 1, index);
// Add next sibling basket:
item = item->nextSibling();
}
return index;
}
NewBasketDialog::~NewBasketDialog()
{
}
void NewBasketDialog::polish()
{
KDialogBase::polish();
m_name->setFocus();
}
void NewBasketDialog::nameChanged(const QString &newName)
{
enableButtonOK(!newName.isEmpty());
}
void NewBasketDialog::slotOk()
{
QIconViewItem *item = ((SingleSelectionKIconView*)m_templates)->selectedItem();
QString templateName;
if (item->text() == i18n("One column"))
templateName = "1column";
if (item->text() == i18n("Two columns"))
templateName = "2columns";
if (item->text() == i18n("Three columns"))
templateName = "3columns";
if (item->text() == i18n("Free-form"))
templateName = "free";
if (item->text() == i18n("Mind map"))
templateName = "mindmap";
Global::bnpView->closeAllEditors();
QString backgroundImage;
QColor textColor;
if (m_backgroundColor->color() == m_defaultProperties.backgroundColor) {
backgroundImage = m_defaultProperties.backgroundImage;
textColor = m_defaultProperties.textColor;
}
BasketFactory::newBasket(m_icon->icon(), m_name->text(), backgroundImage, m_backgroundColor->color(), textColor, templateName, m_basketsMap[m_createIn->currentItem()]);
if(Global::mainWindow()) Global::mainWindow()->show();
KDialogBase::slotOk();
}
void NewBasketDialog::manageTemplates()
{
KMessageBox::information(this, "Wait a minute! There is no template for now: they will come with time... :-D");
}
#include "newbasketdialog.moc"

@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NEWBASKETDIALOG_H
#define NEWBASKETDIALOG_H
#include <kdialogbase.h>
#include <kiconview.h>
#include <qmap.h>
class KIconButton;
class QLineEdit;
class QDragObject;
class QListViewItem;
class Basket;
class KColorCombo2;
/** The class KIconView allow to drag items. We don't want to, so we disable it.
* This class also unselect the selected item when the user right click an empty space. We don't want to, so we reselect it if that happens.
* @author Sébastien Laoût
*/
class SingleSelectionKIconView : public KIconView
{
Q_OBJECT
public:
SingleSelectionKIconView(QWidget *parent = 0, const char *name = 0, WFlags f = 0);
QDragObject* dragObject();
QIconViewItem* selectedItem() { return m_lastSelected; }
private slots:
void slotSelectionChanged(QIconViewItem *item);
void slotSelectionChanged();
private:
QIconViewItem *m_lastSelected;
};
/** Struct to store default properties of a new basket.
* When the dialog shows up, the @p icon is used, as well as the @p backgroundColor.
* A template is choosen depending on @p freeLayout and @p columnLayout.
* If @p columnLayout is too high, the template with the more columns will be chosen instead.
* If the user change the background color in the dialog, then @p backgroundImage and @p textColor will not be used!
* @author Sébastien Laoût
*/
struct NewBasketDefaultProperties
{
QString icon;
QString backgroundImage;
QColor backgroundColor;
QColor textColor;
bool freeLayout;
int columnCount;
NewBasketDefaultProperties();
};
/** The dialog to create a new basket from a template.
* @author Sébastien Laoût
*/
class NewBasketDialog : public KDialogBase
{
Q_OBJECT
public:
NewBasketDialog(Basket *parentBasket, const NewBasketDefaultProperties &defaultProperties, QWidget *parent = 0);
~NewBasketDialog();
void polish();
protected slots:
void slotOk();
void returnPressed();
void manageTemplates();
void nameChanged(const QString &newName);
private:
int populateBasketsList(QListViewItem *item, int indent, int index);
NewBasketDefaultProperties m_defaultProperties;
KIconButton *m_icon;
QLineEdit *m_name;
KColorCombo2 *m_backgroundColor;
KIconView *m_templates;
QComboBox *m_createIn;
QMap<int, Basket*> m_basketsMap;
};
#endif // NEWBASKETDIALOG_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,388 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NOTE_H
#define NOTE_H
#include <qstring.h>
#include <qpixmap.h>
#include <kpixmap.h>
#include <qdatetime.h>
#include "notecontent.h"
#include "tag.h"
class Basket;
class FilterData;
class HtmlExportData;
class NoteSelection;
class QPainter;
class QSimpleRichText;
/** Handle basket notes and groups!\n
* After creation, the note is a group. You should create a NoteContent with this Note
* as constructor parameter to transform it to a note with content. eg:
* @code
* Note *note = new Note(basket); // note is a group!
* new TextContent(note, fileName); // note is now a note with a text content!
* new ColorContent(note, Qt::red); // Should never be done!!!!! the old Content should be deleted...
* @endcode
* @author S<EFBFBD>astien Laot
*/
class Note
{
/// CONSTRUCTOR AND DESTRUCTOR:
public:
Note(Basket *parent);
~Note();
/// DOUBLY LINKED LIST:
private:
Note *m_prev;
Note *m_next;
public:
inline void setNext(Note *next) { m_next = next; }
inline void setPrev(Note *prev) { m_prev = prev; }
inline Note* next() { return m_next; }
inline Note* prev() { return m_prev; }
/// GEOMETRY MANAGEMENT:
private:
int m_x;
int m_y;
int m_width;
int m_height;
// int m_minContentWidth;
public:
void setWidth(int width);
void setWidthForceRelayout(int width);
void setInitialHeight(int height) { m_height = height; } /// << Do NEVER use it unless you know what you do!
void setX(int x);
void setY(int y);
void setXRecursivly(int x);
void setYRecursivly(int y);
inline int x() { return m_x; }
inline int y() { return m_y; }
inline int width() { return (isGroup() ? (isColumn() ? 0 : GROUP_WIDTH) : m_width); }
inline int height() { return m_height; }
inline int bottom() { return m_y + m_height - 1; }
QRect rect();
QRect resizerRect();
QRect visibleRect();
void relayoutAt(int x, int y, bool animate);
int contentX();
int minWidth();
int minRight();
void unsetWidth();
void requestRelayout();
void setHeight(int height) { m_height = height; } /// << DO NEVER USE IT!!! Only available when moving notes, groups should be recreated with the exact same state as before!
/// FREE AND COLUMN LAYOUTS MANAGEMENT:
private:
int m_groupWidth;
public:
int groupWidth();
void setGroupWidth(int width);
int rightLimit();
int finalRightLimit();
bool isFree();
bool isColumn();
bool hasResizer();
int resizerHeight();
/// GROUPS MANAGEMENT:
private:
bool m_isFolded;
Note *m_firstChild;
Note *m_parentNote;
public:
inline bool isGroup() { return m_content == 0L; }
inline bool isFolded() { return m_isFolded; }
inline Note* firstChild() { return m_firstChild; }
inline Note* parentNote() { return m_parentNote; }
/*inline*/ bool showSubNotes();// { return !m_isFolded || !m_collapseFinished; }
inline void setParentNote(Note *note) { m_parentNote = note; }
inline void setFirstChild(Note *note) { m_firstChild = note; }
bool isShown();
void toggleFolded(bool animate);
Note* noteAt(int x, int y);
Note* firstRealChild();
Note* lastRealChild();
Note* lastChild();
Note* lastSibling();
int yExpander();
bool isAfter(Note *note);
bool contains(Note *note);
/// NOTES VARIOUS PROPERTIES: // CONTENT MANAGEMENT?
private:
Basket *m_basket;
NoteContent *m_content;
QDateTime m_addedDate;
QDateTime m_lastModificationDate;
public:
inline Basket* basket() { return m_basket; }
inline NoteContent* content() { return m_content; }
inline void setAddedDate(const QDateTime &dateTime) { m_addedDate = dateTime; }
inline void setLastModificationDate(const QDateTime &dateTime) { m_lastModificationDate = dateTime; }
inline void setParentBasket(Basket *basket) { m_basket = basket; }
QDateTime addedDate() { return m_addedDate; }
QDateTime lastModificationDate() { return m_lastModificationDate; }
QString addedStringDate();
QString lastModificationStringDate();
QString toText(const QString &cuttedFullPath);
bool saveAgain();
void deleteChilds();
protected:
void setContent(NoteContent *content);
friend class NoteContent;
friend class AnimationContent;
/// DRAWING:
private:
QPixmap m_bufferedPixmap;
KPixmap m_bufferedSelectionPixmap;
public:
void draw(QPainter *painter, const QRect &clipRect);
void drawBufferOnScreen(QPainter *painter, const QPixmap &contentPixmap);
static void getGradientColors(const QColor &originalBackground, QColor *colorTop, QColor *colorBottom);
static void drawExpander(QPainter *painter, int x, int y, const QColor &background, bool expand, Basket *basket);
void drawHandle( QPainter *painter, int x, int y, int width, int height, const QColor &background, const QColor &foreground);
void drawResizer( QPainter *painter, int x, int y, int width, int height, const QColor &background, const QColor &foreground, bool rounded);
void drawRoundings(QPainter *painter, int x, int y, int type, int width = 0, int height = 0);
void unbufferizeAll();
void bufferizeSelectionPixmap();
inline void unbufferize() { m_bufferedPixmap.resize(0, 0); m_bufferedSelectionPixmap.resize(0, 0); }
inline bool isBufferized() { return !m_bufferedPixmap.isNull(); }
void recomputeBlankRects(QValueList<QRect> &blankAreas);
static void drawInactiveResizer(QPainter *painter, int x, int y, int height, const QColor &background, bool column);
/// VISIBLE AREAS COMPUTATION:
private:
QValueList<QRect> m_areas;
bool m_computedAreas;
bool m_onTop;
void recomputeAreas();
bool recomputeAreas(Note *note, bool noteIsAfterThis);
public:
void setOnTop(bool onTop);
inline bool isOnTop() { return m_onTop; }
bool isEditing();
/// MANAGE ANIMATION:
private:
int m_deltaX;
int m_deltaY;
int m_deltaHeight;
bool m_collapseFinished;
bool m_expandingFinished;
public:
inline int deltaX() { return m_deltaX; }
inline int deltaY() { return m_deltaY; }
inline int deltaHeight() { return m_deltaHeight; }
inline int finalX() { return m_x + m_deltaX; }
inline int finalY() { return m_y + m_deltaY; }
inline int finalHeight() { return m_height + m_deltaHeight; }
inline int finalBottom() { return finalY() + finalHeight() - 1; }
inline void cancelAnimation() { m_deltaX = 0; m_deltaY = 0; m_deltaHeight = 0; }
inline bool expandingOrCollapsing() { return !m_collapseFinished || !m_expandingFinished; }
void addAnimation(int deltaX, int deltaY, int deltaHeight = 0);
void setFinalPosition(int x, int y); /// << Convenient method for addAnimation()
bool advance();
void initAnimationLoad();
void setRecursivelyUnder(Note *under, bool animate);
/// USER INTERACTION:
public:
enum Zone { None = 0,
Handle, TagsArrow, Custom0, /*CustomContent1, CustomContent2, */Content, Link,
TopInsert, TopGroup, BottomInsert, BottomGroup, BottomColumn,
Resizer,
Group, GroupExpander,
Emblem0 }; // Emblem0 should be at end, because we add 1 to get Emblem1, 2 to get Emblem2...
inline void setHovered(bool hovered) { m_hovered = hovered; unbufferize(); }
void setHoveredZone(Zone zone);
inline bool hovered() { return m_hovered; }
inline Zone hoveredZone() { return m_hoveredZone; }
Zone zoneAt(const QPoint &pos, bool toAdd = false);
QRect zoneRect(Zone zone, const QPoint &pos);
void setCursor(Zone zone);
QString linkAt(const QPoint &pos);
private:
bool m_hovered;
Zone m_hoveredZone;
/// SELECTION:
public:
NoteSelection* selectedNotes();
void setSelected(bool selected);
void setSelectedRecursivly(bool selected);
void invertSelectionRecursivly();
void selectIn(const QRect &rect, bool invertSelection, bool unselectOthers = true);
void setFocused(bool focused);
inline bool isFocused() { return m_focused; }
inline bool isSelected() { return m_selected; }
bool allSelected();
void resetWasInLastSelectionRect();
void unselectAllBut(Note *toSelect);
void invertSelectionOf(Note *toSelect);
Note* theSelectedNote();
private:
bool m_focused;
bool m_selected;
bool m_wasInLastSelectionRect;
/// TAGS:
private:
State::List m_states;
State m_computedState;
int m_emblemsCount;
bool m_haveInvisibleTags;
public:
/*const */State::List& states() const;
inline int emblemsCount() { return m_emblemsCount; }
void addState(State *state, bool orReplace = true);
void addTag(Tag *tag);
void removeState(State *state);
void removeTag(Tag *tag);
void removeAllTags();
void addTagToSelectedNotes(Tag *tag);
void removeTagFromSelectedNotes(Tag *tag);
void removeAllTagsFromSelectedNotes();
void addStateToSelectedNotes(State *state, bool orReplace = true);
void changeStateOfSelectedNotes(State *state);
bool selectedNotesHaveTags();
void inheritTagsOf(Note *note);
bool hasTag(Tag *tag);
bool hasState(State *state);
State* stateOfTag(Tag *tag);
State* stateForEmblemNumber(int number);
bool stateForTagFromSelectedNotes(Tag *tag, State **state);
void recomputeStyle();
void recomputeAllStyles();
bool removedStates(const QValueList<State*> &deletedStates);
QFont font(); // Computed!
QColor backgroundColor(); // Computed!
QColor textColor(); // Computed!
/// FILTERING:
private:
bool m_matching;
public:
bool computeMatching(const FilterData &data);
int newFilter(const FilterData &data);
bool matching() { return m_matching; }
/// ADDED:
public:
void deleteSelectedNotes(bool deleteFilesToo = true);
int count();
int countDirectChilds();
QString fullPath();
Note* noteForFullPath(const QString &path);
void update();
void linkLookChanged();
void usedStates(QValueList<State*> &states);
void listUsedTags(QValueList<Tag*> &list);
Note* nextInStack();
Note* prevInStack();
Note* nextShownInStack();
Note* prevShownInStack();
Note* parentPrimaryNote(); // TODO: There are places in the code where this methods is hand-copied / hand-inlined instead of called.
Note* firstSelected();
Note* lastSelected();
Note* selectedGroup();
void groupIn(Note *group);
bool tryExpandParent();
bool tryFoldParent();
int distanceOnLeftRight(Note *note, int side);
int distanceOnTopBottom(Note *note, int side);
bool convertTexts();
void debug();
/// SPEED OPTIMIZATION
public:
void finishLazyLoad();
public:
// Values are provided here as info:
// Please see Settings::setBigNotes() to know whats values are assigned.
static int NOTE_MARGIN /*= 2*/;
static int INSERTION_HEIGHT /*= 5*/;
static int EXPANDER_WIDTH /*= 9*/;
static int EXPANDER_HEIGHT /*= 9*/;
static int GROUP_WIDTH /*= 2*NOTE_MARGIN + EXPANDER_WIDTH*/;
static int HANDLE_WIDTH /*= GROUP_WIDTH*/;
static int RESIZER_WIDTH /*= GROUP_WIDTH*/;
static int TAG_ARROW_WIDTH /*= 5*/;
static int EMBLEM_SIZE /*= 16*/;
static int MIN_HEIGHT /*= 2*NOTE_MARGIN + EMBLEM_SIZE*/;
};
/*class InsertionData
{
public:
enum Type { Free = 0, NoteRelative, ColumnBottom };
Type type;
InsertionData(int _x, int _y)
: type(Free),
x(_x), y(_y),
note(0), group(false), onTop(false),
column(0)
{}
int x;
int y;
InsertionData(Note *_note, bool _group, bool _onTop)
: type(NoteRelative),
x(0), y(0),
note(_note), group(_group), onTop(_onTop),
column(0)
{}
Note *note;
bool group;
bool onTop;
InsertionData(Note *_column)
: type(NoteRelative),
x(0), y(0),
note(0), group(false), onTop(false),
column(_column)
{}
Note *column;
};*/
#endif // NOTE_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,603 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NOTECONTENT_H
#define NOTECONTENT_H
#include <qobject.h>
#include <qstring.h>
#include <qsimplerichtext.h>
#include <qpixmap.h>
#include <qmovie.h>
#include <qcolor.h>
#include <kurl.h>
#include "linklabel.h"
class QDomDocument;
class QDomElement;
class QPainter;
class QWidget;
class QPoint;
class QRect;
class QStringList;
class KMultipleDrag;
class KFileItem;
namespace KIO { class PreviewJob; }
class Note;
class Basket;
class FilterData;
class HtmlExporter;
/** A list of numeric identifier for each note type.
* Declare a varible with the type NoteType::Id and assign a value like NoteType::Text...
* @author S<EFBFBD>astien Laot
*/
namespace NoteType
{
enum Id { Group = 255, Text = 1, Html, Image, Animation, Sound, File, Link, Launcher, Color, Unknown }; // Always positive
}
/** Abstract base class for every content type of basket note.
* It's a base class to represent those types: Text, Html, Image, Animation, Sound, File, Link, Launcher, Color, Unknown.
* @author S<EFBFBD>astien Laot
*/
class NoteContent // TODO: Mark some methods as const! and some (like typeName() as static!
{
public:
// Constructor and destructor:
NoteContent(Note *parent, const QString &fileName = ""); /// << Constructor. Inherited notes should call it to initialize the parent note.
virtual ~NoteContent() {} /// << Virtual destructor. Reimplement it if you should destroy some data your custom types.
// Simple Abstract Generic Methods:
virtual NoteType::Id type() = 0; /// << @return the internal number that identify that note type.
virtual QString typeName() = 0; /// << @return the translated type name to display in the user interface.
virtual QString lowerTypeName() = 0; /// << @return the type name in lowercase without space, for eg. saving.
virtual QString toText(const QString &cuttedFullPath); /// << @return a plain text equivalent of the content.
virtual QString toHtml(const QString &imageName, const QString &cuttedFullPath) = 0; /// << @return an HTML text equivalent of the content. @param imageName Save image in this Qt ressource.
virtual QPixmap toPixmap() { return QPixmap(); } /// << @return an image equivalent of the content.
virtual void toLink(KURL *url, QString *title, const QString &cuttedFullPath); /// << Set the link to the content. By default, it set them to fullPath() if useFile().
virtual bool useFile() = 0; /// << @return true if it use a file to store the content.
virtual bool canBeSavedAs() = 0; /// << @return true if the content can be saved as a file by the user.
virtual QString saveAsFilters() = 0; /// << @return the filters for the user to choose a file destination to save the note as.
virtual bool match(const FilterData &data) = 0; /// << @return true if the content match the filter criterias.
// Complexe Abstract Generic Methods:
virtual void exportToHTML(HTMLExporter *exporter, int indent) = 0; /// << Export the note in an HTML file.
virtual QString cssClass() = 0; /// << @return the CSS class of the note when exported to HTML
virtual int setWidthAndGetHeight(int width) = 0; /// << Relayout content with @p width (never less than minWidth()). @return its new height.
virtual void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered) = 0; /// << Paint the content on @p painter, at coordinate (0, 0) and with the size (@p width, @p height).
virtual bool loadFromFile(bool /*lazyLoad*/) { return false; } /// << Load the content from the file. The default implementation does nothing. @see fileName().
virtual bool finishLazyLoad() { return false; } /// << Load what was not loaded by loadFromFile() if it was lazy-loaded
virtual bool saveToFile() { return false; } /// << Save the content to the file. The default implementation does nothing. @see fileName().
virtual QString linkAt(const QPoint &/*pos*/) { return ""; } /// << @return the link anchor at position @p pos or "" if there is no link.
virtual void saveToNode(QDomDocument &doc, QDomElement &content); /// << Save the note in the basket XML file. By default it store the filename if a file is used.
virtual void fontChanged() = 0; /// << If your content display textual data, called when the font have changed (from tags or basket font)
virtual void linkLookChanged() {} /// << If your content use LinkDisplay with preview enabled, reload the preview (can have changed size)
virtual QString editToolTipText() = 0; /// << @return "Edit this [text|image|...]" to put in the tooltip for the note's content zone.
virtual void toolTipInfos(QStringList */*keys*/, QStringList */*values*/) {} /// << Get "key: value" couples to put in the tooltip for the note's content zone.
// Custom Zones: /// Implement this if you want to store custom data.
virtual int zoneAt(const QPoint &/*pos*/) { return 0; } /// << If your note-type have custom zones, @return the zone at @p pos or 0 if it's not a custom zone!
virtual QRect zoneRect(int zone, const QPoint &/*pos*/); /// << Idem, @return the rect of the custom zone
virtual QString zoneTip(int /*zone*/) { return ""; } /// << Idem, @return the toolTip of the custom zone
virtual void setCursor(QWidget */*widget*/, int /*zone*/) {} /// << Idem, set the mouse cursor for widget @p widget when it is over zone @p zone!
virtual void setHoveredZone(int /*oldZone*/, int /*newZone*/) {} /// << If your note type need some feedback, you get notified of hovering changes here.
virtual QString statusBarMessage(int /*zone*/) { return ""; } /// << @return the statusBar message to show for zone @p zone, or "" if nothing special have to be said.
// Drag and Drop Content:
virtual void serialize(QDataStream &/*stream*/) {} /// << Serialize the content in a QDragObject. If it consists of a file, it can be serialized for you.
virtual bool shouldSerializeFile() { return useFile(); } /// << @return true if the dragging process should serialize the filename (and move the file if cutting).
virtual void addAlternateDragObjects(KMultipleDrag*/*dragObj*/) {} /// << If you offer more than toText/Html/Image/Link(), this will be called if this is the only selected.
virtual QPixmap feedbackPixmap(int width, int height) = 0; /// << @return the pixmap to put under the cursor while dragging this object.
virtual bool needSpaceForFeedbackPixmap() { return false; } /// << @return true if a space must be inserted before and after the DND feedback pixmap.
// Content Edition:
virtual int xEditorIndent() { return 0; } /// << If the editor should be indented (eg. to not cover an icon), return the number of pixels.
// Open Content or File:
virtual KURL urlToOpen(bool /*with*/); /// << @return the URL to open the note, or an invalid KURL if it's not openable. If @p with if false, it's a normal "Open". If it's true, it's for an "Open with..." action. The default implementation return the fullPath() if the note useFile() and nothing if not.
enum OpenMessage {
OpenOne, /// << Message to send to the statusbar when opening this note.
OpenSeveral, /// << Message to send to the statusbar when opening several notes of this type.
OpenOneWith, /// << Message to send to the statusbar when doing "Open With..." on this note.
OpenSeveralWith, /// << Message to send to the statusbar when doing "Open With..." several notes of this type.
OpenOneWithDialog, /// << Prompt-message of the "Open With..." dialog for this note.
OpenSeveralWithDialog /// << Prompt-message of the "Open With..." dialog for several notes of this type.
};
virtual QString messageWhenOpenning(OpenMessage /*where*/) { return QString(); } /// << @return the message to display according to @p where or nothing if it can't be done. @see OpenMessage describing the nature of the message that should be returned... The default implementation return an empty string. NOTE: If urlToOpen() is invalid and messageWhenOpenning() is not empty, then the user will be prompted to edit the note (with the message returned by messageWhenOpenning()) for eg. being able to edit URL of a link if it's empty when opening it...
virtual QString customOpenCommand() { return QString(); } /// << Reimplement this if your urlToOpen() should be opened with another application instead of the default KDE one. This choice should be left to the users in the setting (choice to use a custom app or not, and which app).
// Common File Management: /// (and do save changes) and optionnaly hide the toolbar.
virtual void setFileName(const QString &fileName); /// << Set the filename. Reimplement it if you eg. want to update the view when the filename is changed.
bool trySetFileName(const QString &fileName); /// << Set the new filename and return true. Can fail and return false if a file with this fileName already exists.
QString fullPath(); /// << Get the absolute path of the file where this content is stored on disk.
QString fileName() { return m_fileName; } /// << Get the file name where this content is stored (relative to the basket folder). @see fullPath().
int minWidth() { return m_minWidth; } /// << Get the minimum width for this content.
Note *note() { return m_note; } /// << Get the note managing this content.
Basket *basket(); /// << Get the basket containing the note managing this content.
public:
void setEdited(); /// << Mark the note as edited NOW: change the "last modification time and time" AND save the basket to XML file.
protected:
void contentChanged(int newMinWidth); /// << When the content has changed, inherited classes should call this to specify its new minimum size and trigger a basket relayout.
private:
Note *m_note;
QString m_fileName;
int m_minWidth;
public:
static const int FEEDBACK_DARKING;
};
/** Real implementation of plain text notes:
* @author S<EFBFBD>astien Laot
*/
class TextContent : public NoteContent
{
public:
// Constructor and destructor:
TextContent(Note *parent, const QString &fileName, bool lazyLoad = false);
~TextContent();
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toText(const QString &/*cuttedFullPath*/);
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool lazyLoad);
bool finishLazyLoad();
bool saveToFile();
QString linkAt(const QPoint &pos);
void fontChanged();
QString editToolTipText();
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
// QString customOpenCommand();
// Content-Specific Methods:
void setText(const QString &text, bool lazyLoad = false); /// << Change the text note-content and relayout the note.
QString text() { return m_text; } /// << @return the text note-content.
protected:
QString m_text;
QSimpleRichText *m_simpleRichText;
};
/** Real implementation of rich text (HTML) notes:
* @author S<EFBFBD>astien Laot
*/
class HtmlContent : public NoteContent
{
public:
// Constructor and destructor:
HtmlContent(Note *parent, const QString &fileName, bool lazyLoad = false);
~HtmlContent();
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toText(const QString &/*cuttedFullPath*/);
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool lazyLoad);
bool finishLazyLoad();
bool saveToFile();
QString linkAt(const QPoint &pos);
void fontChanged();
QString editToolTipText();
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
QString customOpenCommand();
// Content-Specific Methods:
void setHtml(const QString &html, bool lazyLoad = false); /// << Change the HTML note-content and relayout the note.
QString html() { return m_html; } /// << @return the HTML note-content.
protected:
QString m_html;
QString m_textEquivalent; //OPTIM_FILTER
QSimpleRichText *m_simpleRichText;
};
/** Real implementation of image notes:
* @author S<EFBFBD>astien Laot
*/
class ImageContent : public NoteContent
{
public:
// Constructor and destructor:
ImageContent(Note *parent, const QString &fileName, bool lazyLoad = false);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
QPixmap toPixmap();
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool lazyLoad);
bool finishLazyLoad();
bool saveToFile();
void fontChanged();
QString editToolTipText();
void toolTipInfos(QStringList *keys, QStringList *values);
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
bool needSpaceForFeedbackPixmap() { return true; }
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
QString customOpenCommand();
// Content-Specific Methods:
void setPixmap(const QPixmap &pixmap); /// << Change the pixmap note-content and relayout the note.
QPixmap pixmap() { return m_pixmap; } /// << @return the pixmap note-content.
protected:
QPixmap m_pixmap;
char *m_format;
};
/** Real implementation of animated image (GIF, MNG) notes:
* @author S<EFBFBD>astien Laot
*/
class AnimationContent : public QObject, public NoteContent // QObject to be able to receive QMovie signals
{
Q_OBJECT
public:
// Constructor and destructor:
AnimationContent(Note *parent, const QString &fileName, bool lazyLoad = false);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
QPixmap toPixmap();
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
void fontChanged();
QString editToolTipText();
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
bool needSpaceForFeedbackPixmap() { return true; }
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool lazyLoad);
bool finishLazyLoad();
bool saveToFile();
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
QString customOpenCommand();
// Content-Specific Methods:
bool setMovie(const QMovie &movie); /// << Change the movie note-content and relayout the note.
QMovie movie() { return m_movie; } /// << @return the movie note-content.
protected slots:
void movieUpdated(const QRect&);
void movieResized(const QSize&);
void movieStatus(int status);
protected:
QMovie m_movie;
int m_oldStatus;
static int INVALID_STATUS;
};
/** Real implementation of file notes:
* @author S<EFBFBD>astien Laot
*/
class FileContent : public QObject, public NoteContent
{
Q_OBJECT
public:
// Constructor and destructor:
FileContent(Note *parent, const QString &fileName);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool /*lazyLoad*/);
void fontChanged();
void linkLookChanged();
QString editToolTipText();
void toolTipInfos(QStringList *keys, QStringList *values);
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
// Custom Zones:
int zoneAt(const QPoint &pos);
QRect zoneRect(int zone, const QPoint &/*pos*/);
QString zoneTip(int zone);
void setCursor(QWidget *widget, int zone);
// Content Edition:
int xEditorIndent();
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
// Content-Specific Methods:
void setFileName(const QString &fileName); /// << Reimplemented to be able to relayout the note.
virtual LinkLook* linkLook() { return LinkLook::fileLook; }
protected:
LinkDisplay m_linkDisplay;
// File Preview Management:
protected slots:
void newPreview(const KFileItem*, const QPixmap &preview);
void removePreview(const KFileItem*);
void startFetchingUrlPreview();
protected:
KIO::PreviewJob *m_previewJob;
};
/** Real implementation of sound notes:
* @author S<EFBFBD>astien Laot
*/
class SoundContent : public FileContent // A sound is a file with just a bit different user interaction
{
Q_OBJECT
public:
// Constructor and destructor:
SoundContent(Note *parent, const QString &fileName);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
QString editToolTipText();
// Complexe Generic Methods:
QString cssClass();
// Custom Zones:
QString zoneTip(int zone);
void setHoveredZone(int oldZone, int newZone);
// Open Content or File:
QString messageWhenOpenning(OpenMessage where);
QString customOpenCommand();
// Content-Specific Methods:
LinkLook* linkLook() { return LinkLook::soundLook; }
};
/** Real implementation of link notes:
* @author S<EFBFBD>astien Laot
*/
class LinkContent : public QObject, public NoteContent
{
Q_OBJECT
public:
// Constructor and destructor:
LinkContent(Note *parent, const KURL &url, const QString &title, const QString &icon, bool autoTitle, bool autoIcon);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toText(const QString &/*cuttedFullPath*/);
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
void toLink(KURL *url, QString *title, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
void saveToNode(QDomDocument &doc, QDomElement &content);
void fontChanged();
void linkLookChanged();
QString editToolTipText();
void toolTipInfos(QStringList *keys, QStringList *values);
// Drag and Drop Content:
void serialize(QDataStream &stream);
QPixmap feedbackPixmap(int width, int height);
// Custom Zones:
int zoneAt(const QPoint &pos);
QRect zoneRect(int zone, const QPoint &/*pos*/);
QString zoneTip(int zone);
void setCursor(QWidget *widget, int zone);
QString statusBarMessage(int zone);
// Open Content or File:
KURL urlToOpen(bool /*with*/);
QString messageWhenOpenning(OpenMessage where);
// Content-Specific Methods:
void setLink(const KURL &url, const QString &title, const QString &icon, bool autoTitle, bool autoIcon); /// << Change the link and relayout the note.
KURL url() { return m_url; } /// << @return the URL of the link note-content.
QString title() { return m_title; } /// << @return the displayed title of the link note-content.
QString icon() { return m_icon; } /// << @return the displayed icon of the link note-content.
bool autoTitle() { return m_autoTitle; } /// << @return if the title is auto-computed from the URL.
bool autoIcon() { return m_autoIcon; } /// << @return if the icon is auto-computed from the URL.
protected:
KURL m_url;
QString m_title;
QString m_icon;
bool m_autoTitle;
bool m_autoIcon;
LinkDisplay m_linkDisplay;
// File Preview Management:
protected slots:
void newPreview(const KFileItem*, const QPixmap &preview);
void removePreview(const KFileItem*);
void startFetchingUrlPreview();
protected:
KIO::PreviewJob *m_previewJob;
};
/** Real implementation of launcher notes:
* @author S<EFBFBD>astien Laot
*/
class LauncherContent : public NoteContent
{
public:
// Constructor and destructor:
LauncherContent(Note *parent, const QString &fileName);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
void toLink(KURL *url, QString *title, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool /*lazyLoad*/);
void fontChanged();
QString editToolTipText();
void toolTipInfos(QStringList *keys, QStringList *values);
// Drag and Drop Content:
QPixmap feedbackPixmap(int width, int height);
// Custom Zones:
int zoneAt(const QPoint &pos);
QRect zoneRect(int zone, const QPoint &/*pos*/);
QString zoneTip(int zone);
void setCursor(QWidget *widget, int zone);
// Open Content or File:
KURL urlToOpen(bool with);
QString messageWhenOpenning(OpenMessage where);
// Content-Specific Methods:
void setLauncher(const QString &name, const QString &icon, const QString &exec); /// << Change the launcher note-content and relayout the note. Normally called by loadFromFile (no save done).
QString name() { return m_name; } /// << @return the URL of the launcher note-content.
QString icon() { return m_icon; } /// << @return the displayed icon of the launcher note-content.
QString exec() { return m_exec; } /// << @return the execute command line of the launcher note-content.
// TODO: KService *service() ??? And store everything in thta service ?
protected:
QString m_name; // TODO: Store them in linkDisplay to gain place (idem for Link notes)
QString m_icon;
QString m_exec;
LinkDisplay m_linkDisplay;
};
/** Real implementation of color notes:
* @author S<EFBFBD>astien Laot
*/
class ColorContent : public NoteContent
{
public:
// Constructor and destructor:
ColorContent(Note *parent, const QColor &color);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toText(const QString &/*cuttedFullPath*/);
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
void saveToNode(QDomDocument &doc, QDomElement &content);
void fontChanged();
QString editToolTipText();
void toolTipInfos(QStringList *keys, QStringList *values);
// Drag and Drop Content:
void serialize(QDataStream &stream);
QPixmap feedbackPixmap(int width, int height);
bool needSpaceForFeedbackPixmap() { return true; }
void addAlternateDragObjects(KMultipleDrag *dragObject);
// Content-Specific Methods:
void setColor(const QColor &color); /// << Change the color note-content and relayout the note.
QColor color() { return m_color; } /// << @return the color note-content.
protected:
QColor m_color;
static const int RECT_MARGIN;
};
/** Real implementation of unknown MIME-types dropped notes:
* @author S<EFBFBD>astien Laot
*/
class UnknownContent : public NoteContent
{
public:
// Constructor and destructor:
UnknownContent(Note *parent, const QString &fileName);
// Simple Generic Methods:
NoteType::Id type();
QString typeName();
QString lowerTypeName();
QString toText(const QString &/*cuttedFullPath*/);
QString toHtml(const QString &imageName, const QString &cuttedFullPath);
void toLink(KURL *url, QString *title, const QString &cuttedFullPath);
bool useFile();
bool canBeSavedAs();
QString saveAsFilters();
bool match(const FilterData &data);
// Complexe Generic Methods:
void exportToHTML(HTMLExporter *exporter, int indent);
QString cssClass();
int setWidthAndGetHeight(int width);
void paint(QPainter *painter, int width, int height, const QColorGroup &colorGroup, bool isDefaultColor, bool isSelected, bool isHovered);
bool loadFromFile(bool /*lazyLoad*/);
void fontChanged();
QString editToolTipText();
// Drag and Drop Content:
bool shouldSerializeFile() { return false; }
void addAlternateDragObjects(KMultipleDrag *dragObject);
QPixmap feedbackPixmap(int width, int height);
bool needSpaceForFeedbackPixmap() { return true; }
// Open Content or File:
KURL urlToOpen(bool /*with*/) { return KURL(); }
// Content-Specific Methods:
QString mimeTypes() { return m_mimeTypes; } /// << @return the list of MIME types this note-content contains.
protected:
QString m_mimeTypes;
static const int DECORATION_MARGIN;
};
void NoteFactory__loadNode(const QDomElement &content, const QString &lowerTypeName, Note *parent, bool lazyLoad);
#endif // NOTECONTENT_H

@ -0,0 +1,593 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qdragobject.h>
#include <qdir.h>
#include <qpainter.h>
#include <qtextcodec.h>
#include <qbuffer.h>
#include <kurldrag.h>
#include <kdeversion.h>
#include <kapplication.h>
#include <qdesktopwidget.h>
#include "basket.h"
#include "notedrag.h"
#include "notefactory.h"
#include "tools.h"
#include "global.h"
#include <iostream>
/** NoteDrag */
const char * NoteDrag::NOTE_MIME_STRING = "application/x-basket-note";
void NoteDrag::createAndEmptyCuttingTmpFolder()
{
Tools::deleteRecursively(Global::tempCutFolder());
QDir dir;
dir.mkdir(Global::tempCutFolder());
}
QDragObject* NoteDrag::dragObject(NoteSelection *noteList, bool cutting, QWidget *source)
{
if (noteList->count() <= 0)
return 0;
// The MimeSource:
KMultipleDrag *multipleDrag = new KMultipleDrag(source);
// Make sure the temporary folder exists and is empty (we delete previously moved file(s) (if exists)
// since we override the content of the clipboard and previous file willn't be accessable anymore):
createAndEmptyCuttingTmpFolder();
// The "Native Format" Serialization:
QBuffer buffer;
if (buffer.open(IO_WriteOnly)) {
QDataStream stream(&buffer);
// First append a pointer to the basket:
stream << (Q_UINT64)(noteList->firstStacked()->note->basket());
// Then a list of pointers to all notes, and parent groups:
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked())
stream << (Q_UINT64)(node->note);
QValueList<Note*> groups = noteList->parentGroups();
for (QValueList<Note*>::iterator it = groups.begin(); it != groups.end(); ++it)
stream << (Q_UINT64)(*it);
stream << (Q_UINT64)0;
// And finally the notes themselves:
serializeNotes(noteList, stream, cutting);
// Append the object:
buffer.close();
QStoredDrag *dragObject = new QStoredDrag(NOTE_MIME_STRING, source);
dragObject->setEncodedData(buffer.buffer());
multipleDrag->addDragObject(dragObject);
}
// The "Other Flavours" Serialization:
serializeText( noteList, multipleDrag );
serializeHtml( noteList, multipleDrag );
serializeImage( noteList, multipleDrag );
serializeLinks( noteList, multipleDrag, cutting );
// The Alternate Flavours:
if (noteList->count() == 1)
noteList->firstStacked()->note->content()->addAlternateDragObjects(multipleDrag);
// If it is a drag, and not a copy/cut, add the feedback pixmap:
if (source)
setFeedbackPixmap(noteList, multipleDrag);
return multipleDrag;
}
void NoteDrag::serializeNotes(NoteSelection *noteList, QDataStream &stream, bool cutting)
{
for (NoteSelection *node = noteList; node; node = node->next) {
stream << (Q_UINT64)(node->note);
if (node->firstChild) {
stream << (Q_UINT64)(NoteType::Group) << (Q_UINT64)(node->note->groupWidth()) << (Q_UINT64)(node->note->isFolded());
serializeNotes(node->firstChild, stream, cutting);
} else {
NoteContent *content = node->note->content();
stream << (Q_UINT64)(content->type()) << (Q_UINT64)(node->note->groupWidth());
// Serialize file name, and move the file to a temporary place if the note is to be cuttted.
// If note does not have file name, we append empty string to be able to easily decode the notes later:
stream << content->fileName();
if (content->shouldSerializeFile()) {
if (cutting) {
// Move file in a temporary place:
QString fullPath = Global::tempCutFolder() + Tools::fileNameForNewFile(content->fileName(), Global::tempCutFolder());
KIO::move(KURL(content->fullPath()), KURL(fullPath), /*showProgressInfo=*/false);
node->fullPath = fullPath;
stream << fullPath;
} else
stream << content->fullPath();
} else
stream << QString("");
stream << content->note()->addedDate() << content->note()->lastModificationDate();
content->serialize(stream);
State::List states = node->note->states();
for (State::List::Iterator it = states.begin(); it != states.end(); ++it)
stream << (Q_UINT64)(*it);
stream << (Q_UINT64)0;
}
}
stream << (Q_UINT64)0; // Mark the end of the notes in this group/hierarchy.
}
void NoteDrag::serializeText(NoteSelection *noteList, KMultipleDrag *multipleDrag)
{
QString textEquivalent;
QString text;
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
text = node->note->toText(node->fullPath); // note->toText() and not note->content()->toText() because the first one will also export the tags as text.
if (!text.isEmpty())
textEquivalent += (!textEquivalent.isEmpty() ? "\n" : "") + text;
}
if (!textEquivalent.isEmpty())
multipleDrag->addDragObject( new QTextDrag(textEquivalent) );
}
void NoteDrag::serializeHtml(NoteSelection *noteList, KMultipleDrag *multipleDrag)
{
QString htmlEquivalent;
QString html;
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
html = node->note->content()->toHtml("", node->fullPath);
if (!html.isEmpty())
htmlEquivalent += (!htmlEquivalent.isEmpty() ? "<br>\n" : "") + html;
}
if (!htmlEquivalent.isEmpty()) {
// Add HTML flavour:
QTextDrag *htmlDrag = new QTextDrag(htmlEquivalent);
htmlDrag->setSubtype("html");
multipleDrag->addDragObject(htmlDrag);
// But also QTextEdit flavour, to be able to paste several notes to a text edit:
QByteArray byteArray = ("<!--StartFragment--><p>" + htmlEquivalent).local8Bit();
QStoredDrag *richTextDrag = new QStoredDrag("application/x-qrichtext");
richTextDrag->setEncodedData(byteArray);
multipleDrag->addDragObject(richTextDrag);
}
}
void NoteDrag::serializeImage(NoteSelection *noteList, KMultipleDrag *multipleDrag)
{
QValueList<QPixmap> pixmaps;
QPixmap pixmap;
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
pixmap = node->note->content()->toPixmap();
if (!pixmap.isNull())
pixmaps.append(pixmap);
}
if (!pixmaps.isEmpty()) {
QPixmap pixmapEquivalent;
if (pixmaps.count() == 1)
pixmapEquivalent = pixmaps[0];
else {
// Search the total size:
int height = 0;
int width = 0;
for (QValueList<QPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) {
height += (*it).height();
if ((*it).width() > width)
width = (*it).width();
}
// Create the image by painting all image into one big image:
pixmapEquivalent.resize(width, height);
pixmapEquivalent.fill(Qt::white);
QPainter painter(&pixmapEquivalent);
height = 0;
for (QValueList<QPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) {
painter.drawPixmap(0, height, *it);
height += (*it).height();
}
}
QImageDrag *imageDrag = new QImageDrag(pixmapEquivalent.convertToImage());
multipleDrag->addDragObject(imageDrag);
}
}
void NoteDrag::serializeLinks(NoteSelection *noteList, KMultipleDrag *multipleDrag, bool cutting)
{
KURL::List urls;
QStringList titles;
KURL url;
QString title;
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
node->note->content()->toLink(&url, &title, node->fullPath);
if (!url.isEmpty()) {
urls.append(url);
titles.append(title);
}
}
if (!urls.isEmpty()) {
// First, the standard text/uri-list MIME format:
#if KDE_IS_VERSION( 3, 3, 90 )
KURLDrag *urlsDrag = new KURLDrag(urls);
// ONLY export as text/uri-list, and not as text/plain* as we wil do that better ourself
urlsDrag->setExportAsText(false);
multipleDrag->addDragObject(urlsDrag);
#else
KURLDrag2 *urlsDrag = new KURLDrag2(urls);
QByteArray byteArray = urlsDrag->encodedData2("text/uri-list");
QStoredDrag *uriListDrag = new QStoredDrag("text/uri-list");
uriListDrag->setEncodedData(byteArray);
multipleDrag->addDragObject(uriListDrag);
delete urlsDrag;
#endif
// Then, also provide it in the Mozilla proprietary format (that also allow to add titles to URLs):
// A version for Mozilla applications (convert to "theUrl\ntheTitle", into UTF-16):
// FIXME: Does Mozilla support the drag of several URLs at once?
// FIXME: If no, only provide that if theire is only ONE URL.
QString xMozUrl;
for (uint i = 0; i < urls.count(); ++i)
xMozUrl += (xMozUrl.isEmpty() ? "" : "\n") + urls[i].prettyURL() + "\n" + titles[i];
/* Code for only one: ===============
xMozUrl = note->title() + "\n" + note->url().prettyURL();*/
QByteArray baMozUrl;
QTextStream stream(baMozUrl, IO_WriteOnly);
stream.setEncoding(QTextStream::RawUnicode); // It's UTF16 (aka UCS2), but with the first two order bytes
stream << xMozUrl;
QStoredDrag *xMozUrlDrag = new QStoredDrag("text/x-moz-url");
xMozUrlDrag->setEncodedData(baMozUrl);
multipleDrag->addDragObject(xMozUrlDrag);
if (cutting) {
QByteArray arrayCut(2);
QStoredDrag *storedDragCut = new QStoredDrag("application/x-kde-cutselection");
arrayCut[0] = '1';
arrayCut[1] = 0;
storedDragCut->setEncodedData(arrayCut);
multipleDrag->addDragObject(storedDragCut);
}
}
}
void NoteDrag::setFeedbackPixmap(NoteSelection *noteList, KMultipleDrag *multipleDrag)
{
QPixmap pixmap = feedbackPixmap(noteList);
if (!pixmap.isNull())
multipleDrag->setPixmap(pixmap, QPoint(-8, -8));
}
QPixmap NoteDrag::feedbackPixmap(NoteSelection *noteList)
{
if (noteList == 0)
return QPixmap();
static const int MARGIN = 2;
static const int SPACING = 1;
QColor textColor = noteList->firstStacked()->note->basket()->textColor();
QColor backgroundColor = noteList->firstStacked()->note->basket()->backgroundColor().dark(NoteContent::FEEDBACK_DARKING);
QValueList<QPixmap> pixmaps;
QValueList<QColor> backgrounds;
QValueList<bool> spaces;
QPixmap pixmap;
int height = 0;
int width = 0;
int i = 0;
bool elipsisImage = false;
QColor bgColor;
bool needSpace;
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked(), ++i) {
if (elipsisImage) {
pixmap = QPixmap(7, 2);
pixmap.fill(backgroundColor);
QPainter painter(&pixmap);
painter.setPen(textColor);
painter.drawPoint(1, 1);
painter.drawPoint(3, 1);
painter.drawPoint(5, 1);
painter.end();
bgColor = node->note->basket()->backgroundColor();
needSpace = false;
} else {
pixmap = node->note->content()->feedbackPixmap(/*maxWidth=*/kapp->desktop()->width() / 2, /*maxHeight=*/96);
bgColor = node->note->backgroundColor();
needSpace = node->note->content()->needSpaceForFeedbackPixmap();
}
if (!pixmap.isNull()) {
if (pixmap.width() > width)
width = pixmap.width();
pixmaps.append(pixmap);
backgrounds.append(bgColor);
spaces.append(needSpace);
height += (i > 0 && needSpace ? 1 : 0) + pixmap.height() + SPACING + (needSpace ? 1 : 0);
if (elipsisImage)
break;
if (height > kapp->desktop()->height() / 2)
elipsisImage = true;
}
}
if (!pixmaps.isEmpty()) {
QPixmap result(MARGIN + width + MARGIN, MARGIN + height - SPACING + MARGIN - (spaces.last() ? 1 : 0));
QPainter painter(&result);
// Draw all the images:
height = MARGIN;
QValueList<QPixmap>::iterator it;
QValueList<QColor>::iterator it2;
QValueList<bool>::iterator it3;
int i = 0;
for (it = pixmaps.begin(), it2 = backgrounds.begin(), it3 = spaces.begin(); it != pixmaps.end(); ++it, ++it2, ++it3, ++i) {
if (i != 0 && (*it3)) {
painter.fillRect(MARGIN, height, result.width() - 2 * MARGIN, SPACING, (*it2).dark(NoteContent::FEEDBACK_DARKING));
++height;
}
painter.drawPixmap(MARGIN, height, *it);
if ((*it).width() < width)
painter.fillRect(MARGIN + (*it).width(), height, width - (*it).width(), (*it).height(), (*it2).dark(NoteContent::FEEDBACK_DARKING));
if (*it3) {
painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, (*it2).dark(NoteContent::FEEDBACK_DARKING));
++height;
}
painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, Tools::mixColor(textColor, backgroundColor));
height += (*it).height() + SPACING;
}
// Draw the border:
painter.setPen(textColor);
painter.drawLine(0, 0, result.width() - 1, 0);
painter.drawLine(0, 0, 0, result.height() - 1);
painter.drawLine(0, result.height() - 1, result.width() - 1, result.height() - 1);
painter.drawLine(result.width() - 1, 0, result.width() - 1, result.height() - 1);
// Draw the "lightly rounded" border:
painter.setPen(Tools::mixColor(textColor, backgroundColor));
painter.drawPoint(0, 0);
painter.drawPoint(0, result.height() - 1);
painter.drawPoint(result.width() - 1, result.height() - 1);
painter.drawPoint(result.width() - 1, 0);
// Draw the background in the margin (the inside will be painted above, anyway):
painter.setPen(backgroundColor);
painter.drawLine(1, 1, result.width() - 2, 1);
painter.drawLine(1, 1, 1, result.height() - 2);
painter.drawLine(1, result.height() - 2, result.width() - 2, result.height() - 2);
painter.drawLine(result.width() - 2, 1, result.width() - 2, result.height() - 2);
// And assign the feedback pixmap to the drag object:
//multipleDrag->setPixmap(result, QPoint(-8, -8));
return result;
}
return QPixmap();
}
bool NoteDrag::canDecode(QMimeSource *source)
{
return source->provides(NOTE_MIME_STRING);
}
Basket* NoteDrag::basketOf(QMimeSource *source)
{
QBuffer buffer(source->encodedData(NOTE_MIME_STRING));
if (buffer.open(IO_ReadOnly)) {
QDataStream stream(&buffer);
// Get the parent basket:
Q_UINT64 basketPointer;
stream >> (Q_UINT64&)basketPointer;
return (Basket*)basketPointer;
} else
return 0;
}
QValueList<Note*> NoteDrag::notesOf(QMimeSource *source)
{
QBuffer buffer(source->encodedData(NOTE_MIME_STRING));
if (buffer.open(IO_ReadOnly)) {
QDataStream stream(&buffer);
// Get the parent basket:
Q_UINT64 basketPointer;
stream >> (Q_UINT64&)basketPointer;
// Get the note list:
Q_UINT64 notePointer;
QValueList<Note*> notes;
do {
stream >> notePointer;
if (notePointer != 0)
notes.append((Note*)notePointer);
} while (notePointer);
// Done:
return notes;
} else
return QValueList<Note*>();
}
Note* NoteDrag::decode(QMimeSource *source, Basket *parent, bool moveFiles, bool moveNotes)
{
QBuffer buffer(source->encodedData(NOTE_MIME_STRING));
if (buffer.open(IO_ReadOnly)) {
QDataStream stream(&buffer);
// Get the parent basket:
Q_UINT64 basketPointer;
stream >> (Q_UINT64&)basketPointer;
Basket *basket = (Basket*)basketPointer;
// Get the note list:
Q_UINT64 notePointer;
QValueList<Note*> notes;
do {
stream >> notePointer;
if (notePointer != 0)
notes.append((Note*)notePointer);
} while (notePointer);
// Decode the note hierarchy:
Note *hierarchy = decodeHierarchy(stream, parent, moveFiles, moveNotes, basket);
// In case we moved notes from one basket to another, save the source basket where notes were removed:
basket->filterAgainDelayed(); // Delayed, because if a note is moved to the same basket, the note is not at its
basket->save(); // new position yet, and the call to ensureNoteVisible would make the interface flicker!!
return hierarchy;
} else
return 0;
}
Note* NoteDrag::decodeHierarchy(QDataStream &stream, Basket *parent, bool moveFiles, bool moveNotes, Basket *originalBasket)
{
Q_UINT64 notePointer;
Q_UINT64 type;
QString fileName;
QString fullPath;
QDateTime addedDate;
QDateTime lastModificationDate;
Note *firstNote = 0; // TODO: class NoteTreeChunk
Note *lastInserted = 0;
do {
stream >> notePointer;
if (notePointer == 0)
return firstNote;
Note *oldNote = (Note*)notePointer;
Note *note = 0;
Q_UINT64 groupWidth;
stream >> type >> groupWidth;
if (type == NoteType::Group) {
note = new Note(parent);
note->setGroupWidth(groupWidth);
Q_UINT64 isFolded;
stream >> isFolded;
if (isFolded)
note->toggleFolded(/*animate=*/false);
if (moveNotes) {
note->setX(oldNote->x()); // We don't move groups but re-create them (every childs can to not be selected)
note->setY(oldNote->y()); // We just set the position of the copied group so the animation seems as if the group is the same as (or a copy of) the old.
note->setHeight(oldNote->height()); // Idem: the only use of Note::setHeight()
}
Note* childs = decodeHierarchy(stream, parent, moveFiles, moveNotes, originalBasket);
if (childs) {
for (Note *n = childs; n; n = n->next())
n->setParentNote(note);
note->setFirstChild(childs);
}
} else {
stream >> fileName >> fullPath >> addedDate >> lastModificationDate;
if (moveNotes) {
originalBasket->unplugNote(oldNote);
note = oldNote;
if (note->basket() != parent) {
QString newFileName = NoteFactory::createFileForNewNote(parent, "", fileName);
note->content()->setFileName(newFileName);
KIO::FileCopyJob *copyJob = KIO::file_move(KURL(fullPath), KURL(parent->fullPath() + newFileName),
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
parent->connect( copyJob, SIGNAL(result(KIO::Job *)),
parent, SLOT(slotCopyingDone2(KIO::Job *)) );
}
note->setGroupWidth(groupWidth);
note->setParentNote(0);
note->setPrev(0);
note->setNext(0);
note->setParentBasket(parent);
NoteFactory::consumeContent(stream, (NoteType::Id)type);
} else if ( (note = NoteFactory::decodeContent(stream, (NoteType::Id)type, parent)) ) {
note->setGroupWidth(groupWidth);
note->setAddedDate(addedDate);
note->setLastModificationDate(lastModificationDate);
} else if (!fileName.isEmpty()) {
// Here we are CREATING a new EMPTY file, so the name is RESERVED
// (while dropping several files at once a filename cannot be used by two of them).
// Later on, file_copy/file_move will copy/move the file to the new location.
QString newFileName = NoteFactory::createFileForNewNote(parent, "", fileName);
note = NoteFactory::loadFile(newFileName, (NoteType::Id)type, parent);
KIO::FileCopyJob *copyJob;
if (moveFiles)
copyJob = KIO::file_move(KURL(fullPath), KURL(parent->fullPath() + newFileName),
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
else
copyJob = KIO::file_copy(KURL(fullPath), KURL(parent->fullPath() + newFileName),
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
parent->connect( copyJob, SIGNAL(result(KIO::Job *)),
parent, SLOT(slotCopyingDone2(KIO::Job *)) );
note->setGroupWidth(groupWidth);
note->setAddedDate(addedDate);
note->setLastModificationDate(lastModificationDate);
}
}
// Retreive the states (tags) and assign them to the note:
if (note && note->content()) {
Q_UINT64 statePointer;
do {
stream >> statePointer;
if (statePointer)
note->addState((State*)statePointer);
} while (statePointer);
}
// Now that we have created the note, insert it:
if (note) {
if (!firstNote)
firstNote = note;
else {
lastInserted->setNext(note);
note->setPrev(lastInserted);
}
lastInserted = note;
}
} while (true);
// We've done: return!
return firstNote;
}
/** ExtendedTextDrag */
bool ExtendedTextDrag::decode(const QMimeSource *e, QString &str)
{
QCString subtype("plain");
return decode(e, str, subtype);
}
bool ExtendedTextDrag::decode(const QMimeSource *e, QString &str, QCString &subtype)
{
// Get the string:
bool ok = QTextDrag::decode(e, str, subtype);
// Test if it was a UTF-16 string (from eg. Mozilla):
if (str.length() >= 2) {
if ((str[0] == 0xFF && str[1] == 0xFE) || (str[0] == 0xFE && str[1] == 0xFF)) {
QByteArray utf16 = e->encodedData(QString("text/" + subtype).local8Bit());
str = QTextCodec::codecForName("utf16")->toUnicode(utf16);
return true;
}
}
// Test if it was empty (sometimes, from GNOME or Mozilla)
if (str.length() == 0 && subtype == "plain") {
if (e->provides("UTF8_STRING")) {
QByteArray utf8 = e->encodedData("UTF8_STRING");
str = QTextCodec::codecForName("utf8")->toUnicode(utf8);
return true;
}
if (e->provides("text/unicode")) { // FIXME: It's UTF-16 without order bytes!!!
QByteArray utf16 = e->encodedData("text/unicode");
str = QTextCodec::codecForName("utf16")->toUnicode(utf16);
return true;
}
if (e->provides("TEXT")) { // local encoding
QByteArray text = e->encodedData("TEXT");
str = QString(text);
return true;
}
if (e->provides("COMPOUND_TEXT")) { // local encoding
QByteArray text = e->encodedData("COMPOUND_TEXT");
str = QString(text);
return true;
}
}
return ok;
}
#include "notedrag.moc"

@ -0,0 +1,103 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NOTEDRAG_H
#define NOTEDRAG_H
#include <qstring.h>
#include <qdragobject.h>
#include <qdatastream.h>
#include <qpixmap.h>
#include <qvaluelist.h>
#include <kmultipledrag.h>
class QDataStream;
class Basket;
class Note;
class NoteSelection;
/** Dragging/Copying/Cutting Scenario:
* - User select some notes and cut them;
* - NoteDrag::toMultipleDrag() is called with a tree of the selected notes (see Basket::toSelectionTree()):
* - This method create a new KMultipleDrag object, create a stream,
* - And then browse all notes and call the virtual Note::serialize() with the stream as parameter for them to serialize theire content in the "native format".
* - This give the MIME type "application/x-basket-note" that will be used by the application to paste the notes exactly as they were.
* - Then the method try to set alterante formats for the dragged objects:
* - It call successively toText() for each notes and stack up the result so theire is ONE big text flavour to add to the KMultipleDrag object
* - It do the same with toHtml(), toImage() and toLink() to have those flavours as well, if possible...
* - If there is only ONE copied note, addAlternateDragObjects() is called on it, so that Unknown objects can be dragged "as is".
* - It's OK for the flavours. The method finally set the drag feedback pixmap by asking every selected notes to draw the content to a small pixmap.
* - The pixmaps are joined to one big pixmap (but it should not exceed a defined size) and a border is drawn on this image.
*
* Pasting/Dropping Scenario:
*
* @author Sébastien Laoût
*/
class NoteDrag
{
protected:
static void serializeNotes( NoteSelection *noteList, QDataStream &stream, bool cutting );
static void serializeText( NoteSelection *noteList, KMultipleDrag *multipleDrag );
static void serializeHtml( NoteSelection *noteList, KMultipleDrag *multipleDrag );
static void serializeImage( NoteSelection *noteList, KMultipleDrag *multipleDrag );
static void serializeLinks( NoteSelection *noteList, KMultipleDrag *multipleDrag, bool cutting );
static void setFeedbackPixmap( NoteSelection *noteList, KMultipleDrag *multipleDrag );
static Note* decodeHierarchy(QDataStream &stream, Basket *parent, bool moveFiles, bool moveNotes, Basket *originalBasket);
public:
static QPixmap feedbackPixmap(NoteSelection *noteList);
static QDragObject* dragObject(NoteSelection *noteList, bool cutting, QWidget *source = 0);
static bool canDecode(QMimeSource *source);
static Note* decode(QMimeSource *source, Basket *parent, bool moveFiles, bool moveNotes);
static Basket* basketOf(QMimeSource *source);
static QValueList<Note*> notesOf(QMimeSource *source);
static void createAndEmptyCuttingTmpFolder();
static const char *NOTE_MIME_STRING;
};
/** QTextDrag with capabilities to drop GNOME and Mozilla texts
* as well as UTF-16 texts even if it was supposed to be encoded
* with local encoding!
* @author Sébastien Laoût
*/
class ExtendedTextDrag : public QTextDrag
{
Q_OBJECT
public:
static bool decode(const QMimeSource *e, QString &str);
static bool decode(const QMimeSource *e, QString &str, QCString &subtype);
};
// Support KDE 3.3 and older PROTECTED KURLDrag::encodedData()!
#include <kurldrag.h>
class KURLDrag2 : public KURLDrag
{
Q_OBJECT
public:
KURLDrag2(const KURL::List &urls) : KURLDrag(urls) {}
QByteArray encodedData2(const char *mime) const
{
return encodedData(mime);
}
};
#endif // NOTEDRAG_H

@ -0,0 +1,916 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qlabel.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <klineedit.h>
#include <kurlrequester.h>
#include <kicondialog.h>
#include <kcolordialog.h>
#include <kservice.h>
#include <kconfig.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kmainwindow.h>
#include <ktoolbar.h>
#include <kaction.h>
#include <kurifilter.h>
#include <kdebug.h>
#include <kstdaction.h>
#include <kglobalsettings.h>
#include "noteedit.h"
#include "notecontent.h"
// Use Tools::
#include "notefactory.h"
#include "note.h"
#include "basket.h"
#include "settings.h"
#include "tools.h"
#include "variouswidgets.h"
#include "focusedwidgets.h"
#include <iostream>
/** class NoteEditor: */
NoteEditor::NoteEditor(NoteContent *noteContent)
{
m_isEmpty = false;
m_canceled = false;
m_widget = 0;
m_textEdit = 0;
m_lineEdit = 0;
m_noteContent = noteContent;
}
Note* NoteEditor::note()
{
return m_noteContent->note();
}
NoteEditor* NoteEditor::editNoteContent(NoteContent *noteContent, QWidget *parent)
{
TextContent *textContent = dynamic_cast<TextContent*>(noteContent);
if (textContent)
return new TextEditor(textContent, parent);
HtmlContent *htmlContent = dynamic_cast<HtmlContent*>(noteContent);
if (htmlContent)
return new HtmlEditor(htmlContent, parent);
ImageContent *imageContent = dynamic_cast<ImageContent*>(noteContent);
if (imageContent)
return new ImageEditor(imageContent, parent);
AnimationContent *animationContent = dynamic_cast<AnimationContent*>(noteContent);
if (animationContent)
return new AnimationEditor(animationContent, parent);
FileContent *fileContent = dynamic_cast<FileContent*>(noteContent); // Same for SoundContent
if (fileContent)
return new FileEditor(fileContent, parent);
LinkContent *linkContent = dynamic_cast<LinkContent*>(noteContent);
if (linkContent)
return new LinkEditor(linkContent, parent);
LauncherContent *launcherContent = dynamic_cast<LauncherContent*>(noteContent);
if (launcherContent)
return new LauncherEditor(launcherContent, parent);
ColorContent *colorContent = dynamic_cast<ColorContent*>(noteContent);
if (colorContent)
return new ColorEditor(colorContent, parent);
UnknownContent *unknownContent = dynamic_cast<UnknownContent*>(noteContent);
if (unknownContent)
return new UnknownEditor(unknownContent, parent);
return 0;
}
void NoteEditor::setInlineEditor(QWidget *inlineEditor)
{
m_widget = inlineEditor;
m_textEdit = 0;
m_lineEdit = 0;
KTextEdit *textEdit = dynamic_cast<KTextEdit*>(inlineEditor);
if (textEdit)
m_textEdit = textEdit;
else {
QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(inlineEditor);
if (lineEdit)
m_lineEdit = lineEdit;
}
}
#include <iostream>
/** class TextEditor: */
TextEditor::TextEditor(TextContent *textContent, QWidget *parent)
: NoteEditor(textContent), m_textContent(textContent)
{
FocusedTextEdit *textEdit = new FocusedTextEdit(/*disableUpdatesOnKeyPress=*/true, parent);
textEdit->setLineWidth(0);
textEdit->setMidLineWidth(0);
textEdit->setTextFormat(Qt::PlainText);
textEdit->setPaletteBackgroundColor(note()->backgroundColor());
textEdit->setPaletteForegroundColor(note()->textColor());
textEdit->setFont(note()->font());
textEdit->setHScrollBarMode(QScrollView::AlwaysOff);
if (Settings::spellCheckTextNotes())
textEdit->setCheckSpellingEnabled(true);
textEdit->setText(m_textContent->text());
textEdit->moveCursor(KTextEdit::MoveEnd, false); // FIXME: Sometimes, the cursor flicker at ends before being positionned where clicked (because kapp->processEvents() I think)
textEdit->verticalScrollBar()->setCursor(Qt::ArrowCursor);
setInlineEditor(textEdit);
connect( textEdit, SIGNAL(escapePressed()), this, SIGNAL(askValidation()) );
connect( textEdit, SIGNAL(mouseEntered()), this, SIGNAL(mouseEnteredEditorWidget()) );
connect( textEdit, SIGNAL(cursorPositionChanged(int, int)), textContent->note()->basket(), SLOT(editorCursorPositionChanged()) );
// In case it is a very big note, the top is displayed and Enter is pressed: the cursor is on bottom, we should enure it visible:
QTimer::singleShot( 0, textContent->note()->basket(), SLOT(editorCursorPositionChanged()) );
}
TextEditor::~TextEditor()
{
delete widget(); // TODO: delete that in validate(), so we can remove one method
}
void TextEditor::autoSave(bool toFileToo)
{
bool autoSpellCheck = true;
if (toFileToo) {
if (Settings::spellCheckTextNotes() != textEdit()->checkSpellingEnabled()) {
Settings::setSpellCheckTextNotes(textEdit()->checkSpellingEnabled());
Settings::saveConfig();
}
autoSpellCheck = textEdit()->checkSpellingEnabled();
textEdit()->setCheckSpellingEnabled(false);
}
m_textContent->setText(textEdit()->text());
if (toFileToo) {
m_textContent->saveToFile();
m_textContent->setEdited();
textEdit()->setCheckSpellingEnabled(autoSpellCheck);
}
}
void TextEditor::validate()
{
if (Settings::spellCheckTextNotes() != textEdit()->checkSpellingEnabled()) {
Settings::setSpellCheckTextNotes(textEdit()->checkSpellingEnabled());
Settings::saveConfig();
}
textEdit()->setCheckSpellingEnabled(false);
if (textEdit()->text().isEmpty())
setEmpty();
m_textContent->setText(textEdit()->text());
m_textContent->saveToFile();
m_textContent->setEdited();
// delete widget();
}
/** class HtmlEditor: */
HtmlEditor::HtmlEditor(HtmlContent *htmlContent, QWidget *parent)
: NoteEditor(htmlContent), m_htmlContent(htmlContent)
{
FocusedTextEdit *textEdit = new FocusedTextEdit(/*disableUpdatesOnKeyPress=*/true, parent);
textEdit->setLineWidth(0);
textEdit->setMidLineWidth(0);
textEdit->setTextFormat(Qt::RichText);
textEdit->setAutoFormatting(Settings::autoBullet() ? QTextEdit::AutoAll : QTextEdit::AutoNone);
textEdit->setPaletteBackgroundColor(note()->backgroundColor());
textEdit->setPaletteForegroundColor(note()->textColor());
textEdit->setFont(note()->font());
textEdit->setHScrollBarMode(QScrollView::AlwaysOff);
textEdit->setText(m_htmlContent->html());
textEdit->moveCursor(KTextEdit::MoveEnd, false);
textEdit->verticalScrollBar()->setCursor(Qt::ArrowCursor);
setInlineEditor(textEdit);
connect( textEdit, SIGNAL(mouseEntered()), this, SIGNAL(mouseEnteredEditorWidget()) );
connect( textEdit, SIGNAL(escapePressed()), this, SIGNAL(askValidation()) );
connect( InlineEditors::instance()->richTextFont, SIGNAL(textChanged(const QString&)), textEdit, SLOT(setFamily(const QString&)) );
connect( InlineEditors::instance()->richTextFontSize, SIGNAL(sizeChanged(int)), textEdit, SLOT(setPointSize(int)) );
connect( InlineEditors::instance()->richTextColor, SIGNAL(activated(const QColor&)), textEdit, SLOT(setColor(const QColor&)) );
connect( InlineEditors::instance()->richTextFont, SIGNAL(escapePressed()), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextFont, SIGNAL(returnPressed2()), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextFont, SIGNAL(activated(int)), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextFontSize, SIGNAL(escapePressed()), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextFontSize, SIGNAL(returnPressed2()), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextFontSize, SIGNAL(activated(int)), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextColor, SIGNAL(escapePressed()), textEdit, SLOT(setFocus()) );
connect( InlineEditors::instance()->richTextColor, SIGNAL(returnPressed2()), textEdit, SLOT(setFocus()) );
connect( textEdit, SIGNAL(cursorPositionChanged(int, int)), this, SLOT(cursorPositionChanged()) );
connect( textEdit, SIGNAL(clicked(int, int)), this, SLOT(cursorPositionChanged()) );
connect( textEdit, SIGNAL(currentFontChanged(const QFont&)), this, SLOT(fontChanged(const QFont&)) );
// connect( textEdit, SIGNAL(currentVerticalAlignmentChanged(VerticalAlignment)), this, SLOT(slotVerticalAlignmentChanged()) );
connect( InlineEditors::instance()->richTextBold, SIGNAL(toggled(bool)), textEdit, SLOT(setBold(bool)) );
connect( InlineEditors::instance()->richTextItalic, SIGNAL(toggled(bool)), textEdit, SLOT(setItalic(bool)) );
connect( InlineEditors::instance()->richTextUnderline, SIGNAL(toggled(bool)), textEdit, SLOT(setUnderline(bool)) );
//REMOVE:
//connect( InlineEditors::instance()->richTextBold, SIGNAL(activated()), this, SLOT(setBold()) );
//connect( InlineEditors::instance()->richTextItalic, SIGNAL(activated()), this, SLOT(setItalic()) );
//connect( InlineEditors::instance()->richTextUnderline, SIGNAL(activated()), this, SLOT(setUnderline()) );
connect( InlineEditors::instance()->richTextLeft, SIGNAL(activated()), this, SLOT(setLeft()) );
connect( InlineEditors::instance()->richTextCenter, SIGNAL(activated()), this, SLOT(setCentered()) );
connect( InlineEditors::instance()->richTextRight, SIGNAL(activated()), this, SLOT(setRight()) );
connect( InlineEditors::instance()->richTextJustified, SIGNAL(activated()), this, SLOT(setBlock()) );
// InlineEditors::instance()->richTextToolBar()->show();
cursorPositionChanged();
fontChanged(textEdit->currentFont());
//QTimer::singleShot( 0, this, SLOT(cursorPositionChanged()) );
InlineEditors::instance()->enableRichTextToolBar();
connect( InlineEditors::instance()->richTextUndo, SIGNAL(activated()), textEdit, SLOT(undo()) );
connect( InlineEditors::instance()->richTextRedo, SIGNAL(activated()), textEdit, SLOT(redo()) );
connect( textEdit, SIGNAL(undoAvailable(bool)), InlineEditors::instance()->richTextUndo, SLOT(setEnabled(bool)) );
connect( textEdit, SIGNAL(redoAvailable(bool)), InlineEditors::instance()->richTextRedo, SLOT(setEnabled(bool)) );
connect( textEdit, SIGNAL(textChanged()), this, SLOT(textChanged()));
InlineEditors::instance()->richTextUndo->setEnabled(false);
InlineEditors::instance()->richTextRedo->setEnabled(false);
connect( textEdit, SIGNAL(cursorPositionChanged(int, int)), htmlContent->note()->basket(), SLOT(editorCursorPositionChanged()) );
// In case it is a very big note, the top is displayed and Enter is pressed: the cursor is on bottom, we should enure it visible:
QTimer::singleShot( 0, htmlContent->note()->basket(), SLOT(editorCursorPositionChanged()) );
}
void HtmlEditor::cursorPositionChanged()
{
InlineEditors::instance()->richTextFont->setCurrentFont( textEdit()->currentFont().family() );
if (InlineEditors::instance()->richTextColor->color() != textEdit()->color())
InlineEditors::instance()->richTextColor->setColor( textEdit()->color() );
InlineEditors::instance()->richTextBold->setChecked( textEdit()->bold() );
InlineEditors::instance()->richTextItalic->setChecked( textEdit()->italic() );
InlineEditors::instance()->richTextUnderline->setChecked( textEdit()->underline() );
switch (textEdit()->alignment()) {
default:
case 1/*Qt::AlignLeft*/: InlineEditors::instance()->richTextLeft->setChecked(true); break;
case 4/*Qt::AlignCenter*/: InlineEditors::instance()->richTextCenter->setChecked(true); break;
case 2/*Qt::AlignRight*/: InlineEditors::instance()->richTextRight->setChecked(true); break;
case -8/*Qt::AlignJustify*/: InlineEditors::instance()->richTextJustified->setChecked(true); break;
}
}
void HtmlEditor::textChanged()
{
// The following is a workaround for an apparent Qt bug.
// When I start typing in a textEdit, the undo&redo actions are not enabled until I click
// or move the cursor - probably, the signal undoAvailable() is not emitted.
// So, I had to intervene and do that manually.
InlineEditors::instance()->richTextUndo->setEnabled(textEdit()->isUndoAvailable());
InlineEditors::instance()->richTextRedo->setEnabled(textEdit()->isRedoAvailable());
}
void HtmlEditor::fontChanged(const QFont &font)
{
InlineEditors::instance()->richTextFontSize->setFontSize(font.pointSize());
}
/*void HtmlEditor::slotVe<rticalAlignmentChanged(QTextEdit::VerticalAlignment align)
{
QTextEdit::VerticalAlignment align = textEdit()
switch (align) {
case KTextEdit::AlignSuperScript:
InlineEditors::instance()->richTextSuper->setChecked(true);
InlineEditors::instance()->richTextSub->setChecked(false);
break;
case KTextEdit::AlignSubScript:
InlineEditors::instance()->richTextSuper->setChecked(false);
InlineEditors::instance()->richTextSub->setChecked(true);
break;
default:
InlineEditors::instance()->richTextSuper->setChecked(false);
InlineEditors::instance()->richTextSub->setChecked(false);
}
NoteHtmlEditor::buttonToggled(int id) :
case 106:
if (isOn && m_toolbar->isButtonOn(107))
m_toolbar->setButton(107, false);
m_text->setVerticalAlignment(isOn ? KTextEdit::AlignSuperScript : KTextEdit::AlignNormal);
break;
case 107:
if (isOn && m_toolbar->isButtonOn(106))
m_toolbar->setButton(106, false);
m_text->setVerticalAlignment(isOn ? KTextEdit::AlignSubScript : KTextEdit::AlignNormal);
break;
}*/
// REMOVE: These functions are unused - it's now done by direct connection to textEdit
//void HtmlEditor::setBold() { textEdit()->setBold( InlineEditors::instance()->richTextBold->isChecked() ); }
//void HtmlEditor::setItalic() { textEdit()->setItalic( InlineEditors::instance()->richTextItalic->isChecked() ); }
//void HtmlEditor::setUnderline() { textEdit()->setUnderline( InlineEditors::instance()->richTextUnderline->isChecked() ); }
void HtmlEditor::setLeft() { textEdit()->setAlignment(Qt::AlignLeft); }
void HtmlEditor::setCentered() { textEdit()->setAlignment(Qt::AlignCenter); }
void HtmlEditor::setRight() { textEdit()->setAlignment(Qt::AlignRight); }
void HtmlEditor::setBlock() { textEdit()->setAlignment(Qt::AlignJustify); }
HtmlEditor::~HtmlEditor()
{
delete widget();
}
void HtmlEditor::autoSave(bool toFileToo)
{
m_htmlContent->setHtml(textEdit()->text());
if (toFileToo) {
m_htmlContent->saveToFile();
m_htmlContent->setEdited();
}
}
void HtmlEditor::validate()
{
if (Tools::htmlToText(textEdit()->text()).isEmpty())
setEmpty();
m_htmlContent->setHtml(textEdit()->text());
m_htmlContent->saveToFile();
m_htmlContent->setEdited();
disconnect();
widget()->disconnect();
if (InlineEditors::instance())
{
InlineEditors::instance()->disableRichTextToolBar();
// if (InlineEditors::instance()->richTextToolBar())
// InlineEditors::instance()->richTextToolBar()->hide();
}
delete widget();
setInlineEditor(0);
}
/** class ImageEditor: */
ImageEditor::ImageEditor(ImageContent *imageContent, QWidget *parent)
: NoteEditor(imageContent)
{
int choice = KMessageBox::questionYesNo(parent, i18n(
"Images can not be edited here at the moment (the next version of BasKet Note Pads will include an image editor).\n"
"Do you want to open it with an application that understand it?"),
i18n("Edit Image Note"),
KStdGuiItem::open(),
KStdGuiItem::cancel());
if (choice == KMessageBox::Yes)
note()->basket()->noteOpen(note());
}
/** class AnimationEditor: */
AnimationEditor::AnimationEditor(AnimationContent *animationContent, QWidget *parent)
: NoteEditor(animationContent)
{
int choice = KMessageBox::questionYesNo(parent, i18n(
"This animated image can not be edited here.\n"
"Do you want to open it with an application that understands it?"),
i18n("Edit Animation Note"),
KStdGuiItem::open(),
KStdGuiItem::cancel());
if (choice == KMessageBox::Yes)
note()->basket()->noteOpen(note());
}
/** class FileEditor: */
FileEditor::FileEditor(FileContent *fileContent, QWidget *parent)
: NoteEditor(fileContent), m_fileContent(fileContent)
{
FocusedLineEdit *lineEdit = new FocusedLineEdit(parent);
lineEdit->setLineWidth(0);
lineEdit->setMidLineWidth(0);
lineEdit->setPaletteBackgroundColor(note()->backgroundColor());
lineEdit->setPaletteForegroundColor(note()->textColor());
lineEdit->setFont(note()->font());
lineEdit->setText(m_fileContent->fileName());
lineEdit->selectAll();
setInlineEditor(lineEdit);
connect( lineEdit, SIGNAL(returnPressed()), this, SIGNAL(askValidation()) );
connect( lineEdit, SIGNAL(escapePressed()), this, SIGNAL(askValidation()) );
connect( lineEdit, SIGNAL(mouseEntered()), this, SIGNAL(mouseEnteredEditorWidget()) );
}
FileEditor::~FileEditor()
{
delete widget();
}
void FileEditor::autoSave(bool toFileToo)
{
// FIXME: How to detect cancel?
if (toFileToo && !lineEdit()->text().isEmpty() && m_fileContent->trySetFileName(lineEdit()->text())) {
m_fileContent->setFileName(lineEdit()->text());
m_fileContent->setEdited();
}
}
void FileEditor::validate()
{
autoSave(/*toFileToo=*/true);
}
/** class LinkEditor: */
LinkEditor::LinkEditor(LinkContent *linkContent, QWidget *parent)
: NoteEditor(linkContent)
{
LinkEditDialog dialog(linkContent, parent);
if (dialog.exec() == QDialog::Rejected)
cancel();
if (linkContent->url().isEmpty() && linkContent->title().isEmpty())
setEmpty();
}
/** class LauncherEditor: */
LauncherEditor::LauncherEditor(LauncherContent *launcherContent, QWidget *parent)
: NoteEditor(launcherContent)
{
LauncherEditDialog dialog(launcherContent, parent);
if (dialog.exec() == QDialog::Rejected)
cancel();
if (launcherContent->name().isEmpty() && launcherContent->exec().isEmpty())
setEmpty();
}
/** class ColorEditor: */
ColorEditor::ColorEditor(ColorContent *colorContent, QWidget *parent)
: NoteEditor(colorContent)
{
KColorDialog dialog(parent, /*name=*/"EditColor", /*modal=*/true);
dialog.setColor(colorContent->color());
dialog.setCaption(i18n("Edit Color Note"));
if (dialog.exec() == QDialog::Accepted) {
if (dialog.color() != colorContent->color()) {
colorContent->setColor(dialog.color());
colorContent->setEdited();
}
} else
cancel();
/* This code don't allow to set a caption to the dialog:
QColor color = colorContent()->color();
if (KColorDialog::getColor(color, parent) == QDialog::Accepted && color != m_color) {
colorContent()->setColor(color);
setEdited();
}*/
}
/** class UnknownEditor: */
UnknownEditor::UnknownEditor(UnknownContent *unknownContent, QWidget *parent)
: NoteEditor(unknownContent)
{
KMessageBox::information(parent, i18n(
"The type of this note is unknown and can not be edited here.\n"
"You however can drag or copy the note into an application that understands it."),
i18n("Edit Unknown Note"));
}
/*********************************************************************/
/** class DebuggedLineEdit: */
DebuggedLineEdit::DebuggedLineEdit(const QString &text, QWidget *parent)
: QLineEdit(text, parent)
{
}
DebuggedLineEdit::~DebuggedLineEdit()
{
}
void DebuggedLineEdit::keyPressEvent(QKeyEvent *event)
{
QString oldText = text();
QLineEdit::keyPressEvent(event);
if (oldText != text())
emit textChanged(text());
}
/** class LinkEditDialog: */
LinkEditDialog::LinkEditDialog(LinkContent *contentNote, QWidget *parent/*, QKeyEvent *ke*/)
: KDialogBase(KDialogBase::Plain, i18n("Edit Link Note"), KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"EditLink", /*modal=*/true, /*separator=*/true),
m_noteContent(contentNote)
{
QWidget *page = plainPage();
QGridLayout *layout = new QGridLayout(page, /*nRows=*/4, /*nCols=*/2, /*margin=*/0, spacingHint());
m_url = new KURLRequester(m_noteContent->url().url(), page);
QWidget *wid1 = new QWidget(page);
QHBoxLayout *titleLay = new QHBoxLayout(wid1, /*margin=*/0, spacingHint());
m_title = new DebuggedLineEdit(m_noteContent->title(), wid1);
m_autoTitle = new QPushButton(i18n("Auto"), wid1);
m_autoTitle->setToggleButton(true);
m_autoTitle->setOn(m_noteContent->autoTitle());
titleLay->addWidget(m_title);
titleLay->addWidget(m_autoTitle);
QWidget *wid = new QWidget(page);
QHBoxLayout *hLay = new QHBoxLayout(wid, /*margin=*/0, spacingHint());
m_icon = new KIconButton(wid);
QLabel *label3 = new QLabel(m_icon, i18n("&Icon:"), page);
KURL filteredURL = NoteFactory::filteredURL(KURL(m_url->lineEdit()->text()));//KURIFilter::self()->filteredURI(KURL(m_url->lineEdit()->text()));
m_icon->setIconType(KIcon::NoGroup, KIcon::MimeType);
m_icon->setIconSize(LinkLook::lookForURL(filteredURL)->iconSize());
m_autoIcon = new QPushButton(i18n("Auto"), wid); // Create before to know size here:
/* Icon button: */
m_icon->setIcon(m_noteContent->icon());
int minSize = m_autoIcon->sizeHint().height();
// Make the icon button at least the same heigh than the other buttons for a better alignment (nicer to the eyes):
if (m_icon->sizeHint().height() < minSize)
m_icon->setFixedSize(minSize, minSize);
else
m_icon->setFixedSize(m_icon->sizeHint().height(), m_icon->sizeHint().height()); // Make it square
/* Auto button: */
m_autoIcon->setToggleButton(true);
m_autoIcon->setOn(m_noteContent->autoIcon());
hLay->addWidget(m_icon);
hLay->addWidget(m_autoIcon);
hLay->addStretch();
m_url->lineEdit()->setMinimumWidth(m_url->lineEdit()->fontMetrics().maxWidth()*20);
m_title->setMinimumWidth(m_title->fontMetrics().maxWidth()*20);
//m_url->setShowLocalProtocol(true);
QLabel *label1 = new QLabel(m_url, i18n("Ta&rget:"), page);
QLabel *label2 = new QLabel(m_title, i18n("&Title:"), page);
layout->addWidget(label1, 0, 0, Qt::AlignVCenter);
layout->addWidget(label2, 1, 0, Qt::AlignVCenter);
layout->addWidget(label3, 2, 0, Qt::AlignVCenter);
layout->addWidget(m_url, 0, 1, Qt::AlignVCenter);
layout->addWidget(wid1, 1, 1, Qt::AlignVCenter);
layout->addWidget(wid, 2, 1, Qt::AlignVCenter);
m_isAutoModified = false;
connect( m_url, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&)) );
connect( m_title, SIGNAL(textChanged(const QString&)), this, SLOT(doNotAutoTitle(const QString&)) );
connect( m_icon, SIGNAL(iconChanged(QString)) , this, SLOT(doNotAutoIcon(QString)) );
connect( m_autoTitle, SIGNAL(clicked()), this, SLOT(guessTitle()) );
connect( m_autoIcon, SIGNAL(clicked()), this, SLOT(guessIcon()) );
QWidget *stretchWidget = new QWidget(page);
stretchWidget->setSizePolicy(QSizePolicy(/*hor=*/QSizePolicy::Fixed, /*ver=*/QSizePolicy::Expanding, /*hStretch=*/1, /*vStretch=*/255)); // Make it fill ALL vertical space
layout->addWidget(stretchWidget, 3, 1, Qt::AlignVCenter);
urlChanged("");
// if (ke)
// kapp->postEvent(m_url->lineEdit(), ke);
}
LinkEditDialog::~LinkEditDialog()
{
}
void LinkEditDialog::polish()
{
KDialogBase::polish();
if (m_url->lineEdit()->text().isEmpty()) {
m_url->setFocus();
m_url->lineEdit()->end(false);
} else {
m_title->setFocus();
m_title->end(false);
}
}
void LinkEditDialog::urlChanged(const QString&)
{
m_isAutoModified = true;
// guessTitle();
// guessIcon();
// Optimization (filter only once):
KURL filteredURL = NoteFactory::filteredURL(KURL(m_url->url()));//KURIFilter::self()->filteredURI(KURL(m_url->url()));
if (m_autoIcon->isOn())
m_icon->setIcon(NoteFactory::iconForURL(filteredURL));
if (m_autoTitle->isOn()) {
m_title->setText(NoteFactory::titleForURL(filteredURL));
m_autoTitle->setOn(true); // Because the setText() will disable it!
}
}
void LinkEditDialog::doNotAutoTitle(const QString&)
{
if (m_isAutoModified)
m_isAutoModified = false;
else
m_autoTitle->setOn(false);
}
void LinkEditDialog::doNotAutoIcon(QString)
{
m_autoIcon->setOn(false);
}
void LinkEditDialog::guessIcon()
{
if (m_autoIcon->isOn()) {
KURL filteredURL = NoteFactory::filteredURL(KURL(m_url->url()));//KURIFilter::self()->filteredURI(KURL(m_url->url()));
m_icon->setIcon(NoteFactory::iconForURL(filteredURL));
}
}
void LinkEditDialog::guessTitle()
{
if (m_autoTitle->isOn()) {
KURL filteredURL = NoteFactory::filteredURL(KURL(m_url->url()));//KURIFilter::self()->filteredURI(KURL(m_url->url()));
m_title->setText(NoteFactory::titleForURL(filteredURL));
m_autoTitle->setOn(true); // Because the setText() will disable it!
}
}
void LinkEditDialog::slotOk()
{
KURL filteredURL = NoteFactory::filteredURL(KURL(m_url->url()));//KURIFilter::self()->filteredURI(KURL(m_url->url()));
m_noteContent->setLink(filteredURL, m_title->text(), m_icon->icon(), m_autoTitle->isOn(), m_autoIcon->isOn());
m_noteContent->setEdited();
/* Change icon size if link look have changed */
LinkLook *linkLook = LinkLook::lookForURL(filteredURL);
QString icon = m_icon->icon(); // When we change size, icon isn't changed and keep it's old size
m_icon->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); // Reset size policy
m_icon->setIconSize(linkLook->iconSize()); // So I store it's name and reload it after size change !
m_icon->setIcon(icon);
int minSize = m_autoIcon->sizeHint().height();
// Make the icon button at least the same heigh than the other buttons for a better alignment (nicer to the eyes):
if (m_icon->sizeHint().height() < minSize)
m_icon->setFixedSize(minSize, minSize);
else
m_icon->setFixedSize(m_icon->sizeHint().height(), m_icon->sizeHint().height()); // Make it square
KDialogBase::slotOk();
}
/** class LauncherEditDialog: */
LauncherEditDialog::LauncherEditDialog(LauncherContent *contentNote, QWidget *parent)
: KDialogBase(KDialogBase::Plain, i18n("Edit Launcher Note"), KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"EditLauncher", /*modal=*/true, /*separator=*/true),
m_noteContent(contentNote)
{
QWidget *page = plainPage();
QGridLayout *layout = new QGridLayout(page, /*nRows=*/4, /*nCols=*/2, /*margin=*/0, spacingHint());
KService service(contentNote->fullPath());
m_command = new RunCommandRequester(service.exec(), i18n("Choose a command to run:"), page);
m_name = new QLineEdit(service.name(), page);
QWidget *wid = new QWidget(page);
QHBoxLayout *hLay = new QHBoxLayout(wid, /*margin=*/0, spacingHint());
m_icon = new KIconButton(wid);
QLabel *label = new QLabel(m_icon, i18n("&Icon:"), page);
m_icon->setIconType(KIcon::NoGroup, KIcon::Application);
m_icon->setIconSize(LinkLook::launcherLook->iconSize());
QPushButton *guessButton = new QPushButton(i18n("&Guess"), wid);
/* Icon button: */
m_icon->setIcon(service.icon());
int minSize = guessButton->sizeHint().height();
// Make the icon button at least the same heigh than the other buttons for a better alignment (nicer to the eyes):
if (m_icon->sizeHint().height() < minSize)
m_icon->setFixedSize(minSize, minSize);
else
m_icon->setFixedSize(m_icon->sizeHint().height(), m_icon->sizeHint().height()); // Make it square
/* Guess button: */
hLay->addWidget(m_icon);
hLay->addWidget(guessButton);
hLay->addStretch();
m_command->lineEdit()->setMinimumWidth(m_command->lineEdit()->fontMetrics().maxWidth()*20);
QLabel *label1 = new QLabel(m_command->lineEdit(), i18n("Comman&d:"), page);
QLabel *label2 = new QLabel(m_name, i18n("&Name:"), page);
layout->addWidget(label1, 0, 0, Qt::AlignVCenter);
layout->addWidget(label2, 1, 0, Qt::AlignVCenter);
layout->addWidget(label, 2, 0, Qt::AlignVCenter);
layout->addWidget(m_command, 0, 1, Qt::AlignVCenter);
layout->addWidget(m_name, 1, 1, Qt::AlignVCenter);
layout->addWidget(wid, 2, 1, Qt::AlignVCenter);
QWidget *stretchWidget = new QWidget(page);
stretchWidget->setSizePolicy(QSizePolicy(/*hor=*/QSizePolicy::Fixed, /*ver=*/QSizePolicy::Expanding, /*hStretch=*/1, /*vStretch=*/255)); // Make it fill ALL vertical space
layout->addWidget(stretchWidget, 3, 1, Qt::AlignVCenter);
connect( guessButton, SIGNAL(clicked()), this, SLOT(guessIcon()) );
}
LauncherEditDialog::~LauncherEditDialog()
{
}
void LauncherEditDialog::polish()
{
KDialogBase::polish();
if (m_command->runCommand().isEmpty()) {
m_command->lineEdit()->setFocus();
m_command->lineEdit()->end(false);
} else {
m_name->setFocus();
m_name->end(false);
}
}
void LauncherEditDialog::slotOk()
{
// TODO: Remember if a string has been modified AND IS DIFFERENT FROM THE ORIGINAL!
KConfig conf(m_noteContent->fullPath());
conf.setGroup("Desktop Entry");
conf.writeEntry("Exec", m_command->runCommand());
conf.writeEntry("Name", m_name->text());
conf.writeEntry("Icon", m_icon->icon());
// Just for faster feedback: conf object will save to disk (and then m_note->loadContent() called)
m_noteContent->setLauncher(m_name->text(), m_icon->icon(), m_command->runCommand());
m_noteContent->setEdited();
KDialogBase::slotOk();
}
void LauncherEditDialog::guessIcon()
{
m_icon->setIcon( NoteFactory::iconForCommand(m_command->runCommand()) );
}
/** class InlineEditors: */
InlineEditors::InlineEditors()
{
}
InlineEditors::~InlineEditors()
{
}
InlineEditors* InlineEditors::instance()
{
static InlineEditors *instance = 0;
if (!instance)
instance = new InlineEditors();
return instance;
}
void InlineEditors::initToolBars(KActionCollection *actionCollection)
{
QFont defaultFont;
QColor textColor = (Global::bnpView && Global::bnpView->currentBasket() ?
Global::bnpView->currentBasket()->textColor() :
KGlobalSettings::textColor());
// Init the RichTextEditor Toolbar:
richTextFont = new FocusedFontCombo(Global::mainWindow());
richTextFont->setFixedWidth(richTextFont->sizeHint().width() * 2 / 3);
richTextFont->setCurrentFont(defaultFont.family());
KWidgetAction *action = new KWidgetAction(richTextFont, i18n("Font"), Qt::Key_F6,
/*receiver=*/0, /*slot=*/"", actionCollection, "richtext_font");
richTextFontSize = new FontSizeCombo(/*rw=*/true, Global::mainWindow());
richTextFontSize->setFontSize(defaultFont.pointSize());
action = new KWidgetAction(richTextFontSize, i18n("Font Size"), Qt::Key_F7,
/*receiver=*/0, /*slot=*/"", actionCollection, "richtext_font_size");
richTextColor = new FocusedColorCombo(Global::mainWindow());
richTextColor->setFixedWidth(richTextColor->sizeHint().height() * 2);
richTextColor->setColor(textColor);
action = new KWidgetAction(richTextColor, i18n("Color"), KShortcut(), 0, SLOT(), actionCollection, "richtext_color");
richTextBold = new KToggleAction( i18n("Bold"), "text_bold", "Ctrl+B", actionCollection, "richtext_bold" );
richTextItalic = new KToggleAction( i18n("Italic"), "text_italic", "Ctrl+I", actionCollection, "richtext_italic" );
richTextUnderline = new KToggleAction( i18n("Underline"), "text_under", "Ctrl+U", actionCollection, "richtext_underline" );
// richTextSuper = new KToggleAction( i18n("Superscript"), "text_super", "", actionCollection, "richtext_super" );
// richTextSub = new KToggleAction( i18n("Subscript"), "text_sub", "", actionCollection, "richtext_sub" );
richTextLeft = new KToggleAction( i18n("Align Left"), "text_left", "", actionCollection, "richtext_left" );
richTextCenter = new KToggleAction( i18n("Centered"), "text_center", "", actionCollection, "richtext_center" );
richTextRight = new KToggleAction( i18n("Align Right"), "text_right", "", actionCollection, "richtext_right" );
richTextJustified = new KToggleAction( i18n("Justified"), "text_block", "", actionCollection, "richtext_block" );
richTextLeft->setExclusiveGroup("rt_justify");
richTextCenter->setExclusiveGroup("rt_justify");
richTextRight->setExclusiveGroup("rt_justify");
richTextJustified->setExclusiveGroup("rt_justify");
richTextUndo = new KAction( i18n("Undo"), "undo", "", actionCollection, "richtext_undo");
richTextRedo = new KAction( i18n("Redo"), "redo", "", actionCollection, "richtext_redo");
disableRichTextToolBar();
}
KToolBar* InlineEditors::richTextToolBar()
{
if (Global::mainWindow()) {
Global::mainWindow()->toolBar(); // Make sure we create the main toolbar FIRST, so it will be on top of the edit toolbar!
return Global::mainWindow()->toolBar("richTextEditToolBar");
} else
return 0;
}
void InlineEditors::enableRichTextToolBar()
{
richTextFont->setEnabled(true);
richTextFontSize->setEnabled(true);
richTextColor->setEnabled(true);
richTextBold->setEnabled(true);
richTextItalic->setEnabled(true);
richTextUnderline->setEnabled(true);
richTextLeft->setEnabled(true);
richTextCenter->setEnabled(true);
richTextRight->setEnabled(true);
richTextJustified->setEnabled(true);
richTextUndo->setEnabled(true);
richTextRedo->setEnabled(true);
}
void InlineEditors::disableRichTextToolBar()
{
disconnect(richTextFont);
disconnect(richTextFontSize);
disconnect(richTextColor);
disconnect(richTextBold);
disconnect(richTextItalic);
disconnect(richTextUnderline);
disconnect(richTextLeft);
disconnect(richTextCenter);
disconnect(richTextRight);
disconnect(richTextJustified);
disconnect(richTextUndo);
disconnect(richTextRedo);
richTextFont->setEnabled(false);
richTextFontSize->setEnabled(false);
richTextColor->setEnabled(false);
richTextBold->setEnabled(false);
richTextItalic->setEnabled(false);
richTextUnderline->setEnabled(false);
richTextLeft->setEnabled(false);
richTextCenter->setEnabled(false);
richTextRight->setEnabled(false);
richTextJustified->setEnabled(false);
richTextUndo->setEnabled(false);
richTextRedo->setEnabled(false);
// Return to a "proper" state:
QFont defaultFont;
QColor textColor = (Global::bnpView && Global::bnpView->currentBasket() ?
Global::bnpView->currentBasket()->textColor() :
KGlobalSettings::textColor());
richTextFont->setCurrentFont(defaultFont.family());
richTextFontSize->setFontSize(defaultFont.pointSize());
richTextColor->setColor(textColor);
richTextBold->setChecked(false);
richTextItalic->setChecked(false);
richTextUnderline->setChecked(false);
richTextLeft->setChecked(false);
richTextCenter->setChecked(false);
richTextRight->setChecked(false);
richTextJustified->setChecked(false);
}
#include "noteedit.moc"

@ -0,0 +1,289 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NOTEEDIT_H
#define NOTEEDIT_H
#include <kdialogbase.h>
#include <qtextedit.h>
#include <qlineedit.h>
class QWidget;
//class QLineEdit;
class QPushButton;
class KIconButton;
class KURLRequester;
class KTextEdit;
class KMainWindow;
class KTooolBar;
class KToggleAction;
class FontSizeCombo;
class Note;
class RunCommandRequester;
class FocusedFontCombo;
class FocusedColorCombo;
#include "notecontent.h"
/** The base class for every note editors.
* Scenario:
* The Basket class calls NoteEditor::editNoteContent() with the NoteContent to edit.
* This method create the good child NoteEditor depending
* on the note content type and return it to the Basket.
* This custom NoteEditor have two choices regarding what to do in its constructor:
* - Display a dialog and then call cancel() if the user canceled the dialog;
* - Create an inline editor and call setInlineEditor() with that editor as parameter.
* When the user exit the edition, validate() is called by the Basket.
* You should then call setEmpty() is the user cleared the content.
* The custom editor SHOULD call the NoteEditor constructor.
* If the user cleared the content OR if the user canceled the dialog whereas he/she
* JUST ADDED the note, then the note will be deleted by the Basket.
*/
class NoteEditor : public QObject
{
Q_OBJECT
public:
NoteEditor(NoteContent *noteContent);
bool isEmpty() { return m_isEmpty; }
bool canceled() { return m_canceled; }
bool isInline() { return m_widget != 0; }
QWidget* widget() { return m_widget; }
KTextEdit* textEdit() { return m_textEdit; }
QLineEdit* lineEdit() { return m_lineEdit; }
private:
bool m_isEmpty;
bool m_canceled;
QWidget *m_widget;
KTextEdit *m_textEdit;
QLineEdit *m_lineEdit;
NoteContent *m_noteContent;
public:
NoteContent* noteContent() { return m_noteContent; }
Note* note();
protected:
void setEmpty() { m_isEmpty = true; }
void cancel() { m_canceled = true; }
void setInlineEditor(QWidget *inlineEditor);
public:
virtual void validate() {}
virtual void autoSave(bool /*toFileToo*/) {} // Same as validate(), but does not precede editor close and is triggered either while the editor widget changed size or after 3 seconds of inactivity.
signals:
void askValidation();
void mouseEnteredEditorWidget();
public:
static NoteEditor* editNoteContent(NoteContent *noteContent, QWidget *parent);
};
class TextEditor : public NoteEditor
{
Q_OBJECT
public:
TextEditor(TextContent *textContent, QWidget *parent);
~TextEditor();
void validate();
void autoSave(bool toFileToo);
protected:
TextContent *m_textContent;
};
class HtmlEditor : public NoteEditor
{
Q_OBJECT
public:
HtmlEditor(HtmlContent *htmlContent, QWidget *parent);
~HtmlEditor();
void validate();
void autoSave(bool toFileToo);
protected:
HtmlContent *m_htmlContent;
public slots:
void cursorPositionChanged();
void textChanged();
void fontChanged(const QFont &font);
protected slots:
// void slotVerticalAlignmentChanged(QTextEdit::VerticalAlignment align);
// void setBold();
// void setItalic();
// void setUnderline();
void setLeft();
void setCentered();
void setRight();
void setBlock();
};
class ImageEditor : public NoteEditor
{
Q_OBJECT
public:
ImageEditor(ImageContent *imageContent, QWidget *parent);
};
class AnimationEditor : public NoteEditor
{
Q_OBJECT
public:
AnimationEditor(AnimationContent *animationContent, QWidget *parent);
};
class FileEditor : public NoteEditor
{
Q_OBJECT
public:
FileEditor(FileContent *fileContent, QWidget *parent);
~FileEditor();
void validate();
void autoSave(bool toFileToo);
protected:
FileContent *m_fileContent;
};
class LinkEditor : public NoteEditor
{
Q_OBJECT
public:
LinkEditor(LinkContent *linkContent, QWidget *parent);
};
class LauncherEditor : public NoteEditor
{
Q_OBJECT
public:
LauncherEditor(LauncherContent *launcherContent, QWidget *parent);
};
class ColorEditor : public NoteEditor
{
Q_OBJECT
public:
ColorEditor(ColorContent *colorContent, QWidget *parent);
};
class UnknownEditor : public NoteEditor
{
Q_OBJECT
public:
UnknownEditor(UnknownContent *unknownContent, QWidget *parent);
};
/** QLineEdit behavior:
* Create a new QLineEdit with a text, then the user select a part of it and press ONE letter key.
* The signal textChanged() is not emitted!
* This class correct that!
*/
class DebuggedLineEdit : public QLineEdit
{
Q_OBJECT
public:
DebuggedLineEdit(const QString &text, QWidget *parent = 0);
~DebuggedLineEdit();
protected:
void keyPressEvent(QKeyEvent *event);
};
/** The dialog to edit Link Note content.
* @author S<EFBFBD>astien Laot
*/
class LinkEditDialog : public KDialogBase
{
Q_OBJECT
public:
LinkEditDialog(LinkContent *contentNote, QWidget *parent = 0);
~LinkEditDialog();
void polish();
protected slots:
void slotOk();
void urlChanged(const QString&);
void doNotAutoTitle(const QString&);
void doNotAutoIcon(QString);
void guessTitle();
void guessIcon();
private:
LinkContent *m_noteContent;
bool m_isAutoModified;
KURLRequester *m_url;
QLineEdit *m_title;
KIconButton *m_icon;
QPushButton *m_autoTitle;
QPushButton *m_autoIcon;
};
/** The dialog to edit Launcher Note content.
* @author S<EFBFBD>astien Laot
*/
class LauncherEditDialog : public KDialogBase
{
Q_OBJECT
public:
LauncherEditDialog(LauncherContent *contentNote, QWidget *parent = 0);
~LauncherEditDialog();
void polish();
protected slots:
void slotOk();
void guessIcon();
private:
LauncherContent *m_noteContent;
RunCommandRequester *m_command;
QLineEdit *m_name;
KIconButton *m_icon;
};
/** This class manage toolbars for the inline editors.
* The toolbars should be created once at the application startup,
* then KXMLGUI can manage them and save theire state and position...
* @author S<EFBFBD>astien Laot
*/
class InlineEditors : public QObject
{
Q_OBJECT
public:
InlineEditors();
~InlineEditors();
void initToolBars(KActionCollection *actionCollection);
static InlineEditors* instance();
public:
// Rich Text ToolBar:
KToolBar* richTextToolBar();
void enableRichTextToolBar();
void disableRichTextToolBar();
FocusedFontCombo *richTextFont;
FontSizeCombo *richTextFontSize;
FocusedColorCombo *richTextColor;
KToggleAction *richTextBold;
KToggleAction *richTextItalic;
KToggleAction *richTextUnderline;
// KToggleAction *richTextSuper;
// KToggleAction *richTextSub;
KToggleAction *richTextLeft;
KToggleAction *richTextCenter;
KToggleAction *richTextRight;
KToggleAction *richTextJustified;
KAction *richTextUndo;
KAction *richTextRedo;
};
#endif // NOTEEDIT_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,96 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NOTEFACTORY_H
#define NOTEFACTORY_H
#include <qevent.h>
#include <kurl.h>
#include <qstringlist.h>
class QString;
class QPixmap;
class QColor;
class Basket;
class Note;
enum NoteType::Id;
/** Factory class to create (new, drop, past) or load BasketIem, and eventuelly save them (?)
* @author Sébastien Laoût
*/
namespace NoteFactory
{
/** Functions to create a new note from a content.
* Content, if any, is saved to file but the note is not insterted in the basket, and the basket is not saved.
* Return 0 if the note has not been successfully created.
* In some cases, the returned note can be a group containing several notes or the first note of a chained list.
* The method Basket::TODO() can insert several grouped or chained notes without problem.
*/
Note* createNoteText( const QString &text, Basket *parent, bool reallyPlainText = false);
Note* createNoteHtml( const QString &html, Basket *parent);
Note* createNoteLink( const KURL &url, Basket *parent);
Note* createNoteLink( const KURL &url, const QString &title, Basket *parent);
Note* createNoteImage( const QPixmap &image, Basket *parent);
Note* createNoteColor( const QColor &color, Basket *parent);
Note* createNoteFromText( const QString &content, Basket *parent); // Find automatically the type from the text meaning // TODO: Return Note::List?
Note* createNoteLauncher( const KURL &url, Basket *parent);
Note* createNoteLauncher( const QString &command, const QString &name, const QString &icon, Basket *parent);
Note* createNoteUnknown( QMimeSource *source, Basket *parent);
/** Functions to create derived notes from a content */
Note* createNoteLinkOrLauncher( const KURL &url, Basket *parent);
Note* copyFileAndLoad( const KURL &url, Basket *parent);
Note* moveFileAndLoad( const KURL &url, Basket *parent);
Note* loadFile( const QString &fileName, Basket *parent); /// << Determine the content of the file (the file SHOULD exists) and return a note of the good type.
Note* loadFile( const QString &fileName, NoteType::Id type, Basket *parent ); /// << Create a note of type @p type. The file is not obliged to exist.
/** Functions to create a new note from a drop or past event */
Note* dropNote(QMimeSource *source, Basket *parent,
bool fromDrop = false, QDropEvent::Action action = QDropEvent::Copy, Note *noteSource = 0);
bool movingNotesInTheSameBasket(QMimeSource *source, Basket *parent, QDropEvent::Action action);
Note* dropURLs(KURL::List urls, Basket *parent, QDropEvent::Action action, bool fromDrop);
Note* decodeContent(QDataStream &stream, NoteType::Id type, Basket *parent); /// << Decode the @p stream to a note or return 0 if a general loadFile() is sufficient.
void consumeContent(QDataStream &stream, NoteType::Id type); /// << Decode the @p stream to a note or return 0 if a general loadFile() is sufficient.
/** Functions to create a note file but not load it in a note object */
QString createNoteLauncherFile(const QString &command, const QString &name, const QString &icon, Basket *parent);
/** Other useful functions */
NoteType::Id typeForURL(const KURL &url, Basket *parent);
bool maybeText(const KURL &url);
bool maybeHtml(const KURL &url);
bool maybeImageOrAnimation(const KURL &url);
bool maybeAnimation(const KURL &url);
bool maybeSound(const KURL &url);
bool maybeLauncher(const KURL &url);
QString fileNameForNewNote(Basket *parent, const QString &wantedName);
QString createFileForNewNote(Basket *parent, const QString &extension, const QString &wantedName = "");
KURL filteredURL(const KURL &url);
QString titleForURL(const KURL &url);
QString iconForURL(const KURL &url);
QString iconForCommand(const QString &command);
bool isIconExist(const QString &icon);
QStringList textToURLList(const QString &text); // @Return { url1, title1, url2, title2, url3, title3... }
/** Insert GUI menu */
Note* createEmptyNote( NoteType::Id type, Basket *parent ); // Insert empty if of type Note::Type
Note* importKMenuLauncher(Basket *parent);
Note* importIcon(Basket *parent);
Note* importFileContent(Basket *parent);
}
#endif // NOTEFACTORY_H

@ -0,0 +1,113 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "password.h"
#ifdef HAVE_LIBGPGME
#include <qlayout.h>
#include <qtoolbutton.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kgpgme.h>
#include <basket.h>
PasswordDlg::PasswordDlg(QWidget *parent, const char *name)
:KDialogBase(Plain, i18n("Password Protection"), Ok|Cancel, Ok,
parent, name, /*modal=*/true, /*separator=*/true), w(0)
{
QHBoxLayout* toplayout = new QHBoxLayout(plainPage(), 0, 0);
w = new Password(plainPage());
toplayout->addWidget(w, 1);
}
PasswordDlg::~PasswordDlg()
{
delete w;
}
void PasswordDlg::slotOk()
{
int n = type();
if(n == Basket::PrivateKeyEncryption && key().isEmpty())
KMessageBox::error(w, i18n("No private key selected."));
else
KDialogBase::slotOk();
}
QString PasswordDlg::key() const
{
QString s = w->keyCombo->currentText();
if(s.length() < 16)
return "";
int n = s.findRev(' ');
if(n < 0)
return "";
return s.mid(n+1);
}
int PasswordDlg::type() const
{
return w->buttonGroup->selectedId();
}
void PasswordDlg::setKey(const QString& key)
{
for(int i = 0; i < w->keyCombo->count(); ++i)
{
if(w->keyCombo->text(i).find(key) >= 0)
{
w->keyCombo->setCurrentItem(i);
return;
}
}
}
void PasswordDlg::setType(int type)
{
w->buttonGroup->setButton(type);
}
Password::Password(QWidget *parent, const char *name)
: PasswordLayout(parent, name)
{
KGpgMe gpg;
KGpgKeyList list = gpg.keys(true);
for(KGpgKeyList::iterator it = list.begin(); it != list.end(); ++it) {
QString name = gpg.checkForUtf8((*it).name);
keyCombo->insertItem(QString("%1 <%2> %3").arg(name).arg((*it).email).arg((*it).id));
}
publicPrivateRadioButton->setEnabled(keyCombo->count() > 0);
keyCombo->setEnabled(keyCombo->count() > 0);
}
Password::~Password()
{
}
#include "password.moc"
#endif

@ -0,0 +1,65 @@
/***************************************************************************
* Copyright (C) 2006 by Petri Damsten *
* damu@iki.fi *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef PASSWORD_H
#define PASSWORD_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_LIBGPGME
#include <passwordlayout.h>
#include <kdialogbase.h>
/**
@author Petri Damsten <damu@iki.fi>
*/
class Password : public PasswordLayout
{
Q_OBJECT
public:
Password(QWidget *parent, const char *name = 0);
~Password();
};
class PasswordDlg : public KDialogBase
{
Q_OBJECT
public:
PasswordDlg(QWidget *parent, const char *name = 0);
~PasswordDlg();
QString key() const;
int type() const;
void setKey(const QString& key);
void setType(int type);
protected slots:
virtual void slotOk();
private:
Password* w;
};
#endif // HAVE_LIBGPGME
#endif // PASSWORD_H

@ -0,0 +1,122 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>PasswordLayout</class>
<widget class="QWidget">
<property name="name">
<cstring>PasswordLayout</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>314</width>
<height>69</height>
</rect>
</property>
<property name="caption">
<string>Password Protection</string>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QButtonGroup">
<property name="name">
<cstring>buttonGroup</cstring>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="title">
<string></string>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="margin">
<number>0</number>
</property>
<widget class="QRadioButton">
<property name="name">
<cstring>noPasswordRadioButton</cstring>
</property>
<property name="text">
<string>&amp;No protection</string>
</property>
<property name="accel">
<string>Alt+N</string>
</property>
</widget>
<widget class="QRadioButton">
<property name="name">
<cstring>passwordRadioButton</cstring>
</property>
<property name="text">
<string>Protect basket with a &amp;password</string>
</property>
<property name="accel">
<string>Alt+P</string>
</property>
</widget>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout2</cstring>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QRadioButton">
<property name="name">
<cstring>publicPrivateRadioButton</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Protect basket with private &amp;key:</string>
</property>
<property name="accel">
<string>Alt+K</string>
</property>
</widget>
<widget class="QComboBox">
<property name="name">
<cstring>keyCombo</cstring>
</property>
</widget>
</hbox>
</widget>
</vbox>
</widget>
<spacer>
<property name="name">
<cstring>spacer</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>6</height>
</size>
</property>
</spacer>
</vbox>
</widget>
<slots>
<slot access="private">changeKey()</slot>
<slot access="private">clearKey()</slot>
</slots>
<layoutdefaults spacing="0" margin="0"/>
<layoutfunctions spacing="KDialog::spacingHint"/>
</UI>

@ -0,0 +1,151 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kapplication.h>
#include <qdesktopwidget.h>
#include <qpopupmenu.h>
#include <qrect.h>
#include "popupmenu.h"
#if KDE_IS_VERSION( 3, 2, 90 ) // KDE 3.3.x
#define MENU_Y_OFFSET 1
#else
#define MENU_Y_OFFSET 2
#endif
/** NOTE 1 : This implementation forget BIDI support (eg RightToLeft languages
* expect to try to popup the menu first at bottom-right
* and not at bottom-left.
* NOTE 2 : This implementation do not support virtual desktop with more than
* one screen. Pehrapse QPopupMenu solve it by itself but I can't
* try : I have only one screen.
* => Have those methods directly in Qt (or KDE) would be a great benefits !
*/
void PopupMenu::execAtRectCenter(QPopupMenu &menu, const QRect &rect)
{
// Compute point where to popup the menu that should be centered :
QSize menuSize = menu.sizeHint();
QSize menuHalfSize = menuSize / 2;
QPoint point = rect.center() - QPoint(menuHalfSize.width(), menuHalfSize.height());
// Very strange : menu.exec(point) do that clipping (but not when exec() by mouse !!! ) :
// If menu is partially out of the screen, move it :
/* int desktopWidth = kapp->desktop()->width();
int desktopHeight = kapp->desktop()->height();
if (point.x() + menuSize.width() > desktopWidth) point.setX(desktopWidth - menuSize.width());
if (point.y() + menuSize.height() - 2 > desktopHeight) point.setY(desktopHeight - menuSize.height() + 2);
if (point.x() < 0) point.setX(0);
if (point.y() < 0) point.setY(0);*/
// And show the menu :
menu.exec( point + QPoint(0, MENU_Y_OFFSET) ); // Stupid offset (Qt bug ?) : we should show the menus 2 pixels more bottom !
}
// Needed on debug to draw the passed global rectangle :
//#include <qpainter.h>
//#include <qpen.h>
void PopupMenu::execAtRectBottom(QPopupMenu &menu, const QRect &rect, bool centered)
{
QSize menuSize = menu.sizeHint() - QSize(1, 1); // A size is [1..n] => We want two lengths that are [0..(n-1)]
int desktopWidth = kapp->desktop()->width(); // to be compared/added/substracted with QRects/QPoints...
int desktopHeight = kapp->desktop()->height();
/** Paint the rect on the screen (desktop).
* For test purpose only (to be sure the passed rectangle is right).
* Comment this (and the qpainter and qpen includes) for a non-debug version.
*/
/*QPainter paint(kapp->desktop(), kapp->desktop(), true);
paint.setPen( QPen(Qt::black, 1) );
paint.drawRect(rect);
paint.end();*/
// rect.bottomLeft() and rect.bottomRight() must be VISIBLE :
// show the menu 1 pixel more BOTTOM (add 1 in Y) :
QPoint point = rect.bottomLeft() + QPoint(0, 1);
if (point.y() + menuSize.height() < desktopHeight) { // First try at bottom
if (centered)
point = QPoint( rect.center().x() - menuSize.width() / 2, point.y() );
else if (point.x() + menuSize.width() < desktopWidth) // Then, try at bottom-left
/*point is already set*/;
else // Overwise, at bottom-right
point = rect.bottomRight() - QPoint(menuSize.width(), - 1);
// Idem : rect.topLeft() and rect.topRight() must be VISIBLE :
// show the menu 1 pixel more TOP (substract 1 in Y) :
} else { // Overwize, try at top
if (centered)
point = QPoint( rect.center().x() - menuSize.width() / 2, rect.top() - menuSize.height() - 1 );
else if (point.x() + menuSize.width() < desktopWidth) // Then, try at top-left
point = rect.topLeft() - QPoint(0, menuSize.height() + 1);
else // Overwise, at top-right
point = rect.topRight() - QPoint(menuSize.width(), menuSize.height() + 1);
}
// No need to clip : it will be done by menu.exec(...)
// And show the menu :
menu.exec( point + QPoint(0, MENU_Y_OFFSET) ); // Stupid offset (Qt bug ?) : we should show the menus 2 pixels more bottom !
}
void PopupMenu::execAtRectRight(QPopupMenu &menu, const QRect &rect, bool centered)
{
QSize menuSize = menu.sizeHint() - QSize(1, 1); // A size is [1..n] => We want two lengths that are [0..(n-1)]
int desktopWidth = kapp->desktop()->width(); // to be compared/added/substracted with QRects/QPoints...
int desktopHeight = kapp->desktop()->height();
/** Paint the rect on the screen (desktop).
* For test purpose only (to be sure the passed rectangle is right).
* Comment this (and the qpainter and qpen includes) for a non-debug version.
*/
/*QPainter paint(kapp->desktop(), kapp->desktop(), true);
paint.setPen( QPen(Qt::black, 1) );
paint.drawRect(rect);
paint.end();*/
// rect.topRight() and rect.topLeft() must be VISIBLE :
// show the menu 1 pixel more RIGHT (add 1 in X) :
QPoint point = rect.topRight() + QPoint(1, 0);
if (point.x() + menuSize.width() < desktopWidth) { // First try at right
if (centered)
point = QPoint( point.x(), rect.center().y() - menuSize.height() / 2 );
else if (point.y() + menuSize.height() < desktopHeight) // Then, try at top-right
/*point is already set*/;
else // Overwise, at top-left
point = rect.bottomRight() - QPoint(-1, menuSize.height());
// Idem : rect.topLeft() and rect.bottomLeft() must be VISIBLE :
// show the menu 1 pixel more LEFT (substract 1 in X) :
} else { // Overwize, try at top
if (centered)
point = QPoint( rect.left() - menuSize.width() - 1, rect.center().y() - menuSize.height() / 2 );
else if (point.y() + menuSize.height() < desktopHeight) // Then, try at top-left
point = rect.topLeft() - QPoint(menuSize.width() + 1, 0);
else // Overwise, at bottom-left
point = rect.bottomLeft() - QPoint(menuSize.width() + 1, menuSize.height());
}
// No need to clip : it will be done by menu.exec(...)
// And show the menu :
menu.exec( point + QPoint(0, MENU_Y_OFFSET) ); // Stupid offset (Qt bug ?) : we should show the menus 2 pixels more bottom !
}
// # i n c l u d e " p o p u p m e n u . m o c " // Comment this if you don't compile PopupMenuTest class

@ -0,0 +1,123 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef POPUPMENU_H
#define POPUPMENU_H
class QPopupMenu;
class QRect;
/** QPopupMenu/KPopupMenu doesn't provide metod to exec a menu
* at a given rectangle !
* eg, popup at bottom of a rectangle, and at top if not possible...
* @author Sébastien Laoût
*/
namespace PopupMenu
{
/** Show the popup menu centered into rect.
*/
void execAtRectCenter(QPopupMenu &menu, const QRect &rect);
/** Show the popup menu at left-bottom of rect, or at right-bottom
* if not possible (not enought place).
* If it isn't possible to show it at bottom, it will be shown on
* top of rect (top-left if possible, if not it will be top-right).
* If center is true, it will try to horizontaly center the popup with
* rect, so it will try two positions : bottom center and then top center.
*/
void execAtRectBottom(QPopupMenu &menu, const QRect &rect, bool centered = false);
/** Idem execAtRectBottom but on the right or left sides,
* prior aligned with the top of the rect, and at the bottom
* if not possible.
* If center is true, it will try to vertically center the popup with
* rect, so it will try two positions : right center and then left center.
*/
void execAtRectRight(QPopupMenu &menu, const QRect &rect, bool centered = false);
}
/** Test window of PopupMenu methods.
* Just include popupmenu.h in a main Qt application and call
* new PopupMenuTest();
* Click the window for more explications.
* Resize it to test particular cases.
* (Comment the class, if it isn't done yet to do not compile it :-) ).
* @author Sébastien Laoût
*/
/*****
#include <qwidget.h>
#include <qpopupmenu.h>
#include <qpainter.h>
#include <qpen.h>
c l a s s P o p u p M e n u T e s t : p u b l i c Q W i d g e t
{
Q _ O B J E C T
p u b l i c:
PopupMenuTest()
: QWidget(0)
{
setCaption("Click to test!");
show();
}
void mousePressEvent(QMouseEvent *event)
{
QPopupMenu menu;
QRect rect( mapToGlobal(QPoint(0,0)), size() );
menu.insertItem("A test of popup menu!");
menu.insertItem("This menu contain some items");
menu.insertItem("Resize the window as you want and:");
menu.insertItem("- click : execAtRectCenter");
menu.insertItem("- right click : execAtRectBottom");
menu.insertItem("- middle click : execAtRectRight");
menu.insertItem("- Shift + right click : execAtRectBottom centered");
menu.insertItem("- Shift + middle click : execAtRectRight centered");
if (event->button() & Qt::LeftButton)
PopupMenu::execAtRectCenter(menu, rect);
else if ((event->button() & Qt::RightButton) && (event->state() & Qt::ShiftButton))
PopupMenu::execAtRectBottom(menu, rect, true);
else if (event->button() & Qt::RightButton)
PopupMenu::execAtRectBottom(menu, rect);
else if ((event->button() & Qt::MidButton) && (event->state() & Qt::ShiftButton))
PopupMenu::execAtRectRight(menu, rect, true);
else if (event->button() & Qt::MidButton)
PopupMenu::execAtRectRight(menu, rect);
}
void paintEvent(QPaintEvent*)
{
QPainter paint(this);
paint.setPen(paletteBackgroundColor());
paint.drawRect(rect());
paint.drawWinFocusRect(rect());
paint.setPen( QPen(Qt::black, 1) );
paint.drawLine( rect().topLeft(), rect().bottomRight() );
paint.drawLine( rect().topRight(), rect().bottomLeft() );
}
};
*****/
#endif // POPUPMENU_H

@ -0,0 +1,602 @@
#if 0
// Note: this file has been copied from the Qt source.
// Those classes are normally used internally in Qt
// but we need them for immitate the roll-over effect of QComboBox.
//
// A portion of code has been added. It's underlined by "THIS CODE WAS ADDED:".
//
// And some class definitions have been moved from this file to qeffects.h
// Theire old position is indicated by "REMOVED CLASS DEFINITION HERE (MOVED TO qeffects.h)"
/****************************************************************************
** $Id: qt/qeffects.cpp 3.3.4 edited Dec 10 10:13 $
**
** Implementation of QEffects functions
**
** Created : 000621
**
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of the widgets module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qapplication.h"
#ifndef QT_NO_EFFECTS
#include "qwidget.h"
#include "qeffects.h"
#include "qpixmap.h"
#include "qimage.h"
#include "qtimer.h"
#include "qdatetime.h"
#include "qguardedptr.h"
#include "qscrollview.h"
/* REMOVED CLASS DEFINITION HERE (MOVED TO qeffects.h) */
static QAlphaWidget* q_blend = 0;
/*
Constructs a QAlphaWidget.
*/
QAlphaWidget::QAlphaWidget( QWidget* w, WFlags f )
: QWidget( QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)),
"qt internal alpha effect widget", f )
{
#if 1 //ndef Q_WS_WIN
setEnabled( FALSE );
#endif
pm.setOptimization( QPixmap::BestOptim );
setBackgroundMode( NoBackground );
widget = (QAccessWidget*)w;
alpha = 0;
}
/*
\reimp
*/
void QAlphaWidget::paintEvent( QPaintEvent* )
{
bitBlt( this, QPoint(0,0), &pm );
}
/*
Starts the alphablending animation.
The animation will take about \a time ms
*/
void QAlphaWidget::run( int time )
{
duration = time;
if ( duration < 0 )
duration = 150;
if ( !widget )
return;
elapsed = 0;
checkTime.start();
showWidget = TRUE;
qApp->installEventFilter( this );
widget->setWState( WState_Visible );
move( widget->geometry().x(),widget->geometry().y() );
resize( widget->size().width(), widget->size().height() );
front = QImage( widget->size(), 32 );
front = QPixmap::grabWidget( widget );
back = QImage( widget->size(), 32 );
back = QPixmap::grabWindow( QApplication::desktop()->winId(),
widget->geometry().x(), widget->geometry().y(),
widget->geometry().width(), widget->geometry().height() );
if ( !back.isNull() && checkTime.elapsed() < duration / 2 ) {
mixed = back.copy();
pm = mixed;
show();
setEnabled(FALSE);
connect( &anim, SIGNAL(timeout()), this, SLOT(render()));
anim.start( 1 );
} else {
duration = 0;
render();
}
}
/*
\reimp
*/
bool QAlphaWidget::eventFilter( QObject* o, QEvent* e )
{
switch ( e->type() ) {
case QEvent::Move:
if ( o != widget )
break;
move( widget->geometry().x(),widget->geometry().y() );
update();
break;
case QEvent::Hide:
case QEvent::Close:
if ( o != widget )
break;
case QEvent::MouseButtonPress:
#ifndef QT_NO_SCROLLVIEW
if ( ::qt_cast<QScrollView*>(o) )
break;
#endif
case QEvent::MouseButtonDblClick:
setEnabled(TRUE);
showWidget = FALSE;
render();
break;
case QEvent::KeyPress:
{
QKeyEvent *ke = (QKeyEvent*)e;
if ( ke->key() == Key_Escape )
showWidget = FALSE;
else
duration = 0;
render();
break;
}
default:
break;
}
return QWidget::eventFilter( o, e );
}
/*
\reimp
*/
void QAlphaWidget::closeEvent( QCloseEvent *e )
{
e->accept();
if ( !q_blend )
return;
showWidget = FALSE;
render();
QWidget::closeEvent( e );
}
/*
Render alphablending for the time elapsed.
Show the blended widget and free all allocated source
if the blending is finished.
*/
void QAlphaWidget::render()
{
int tempel = checkTime.elapsed();
if ( elapsed >= tempel )
elapsed++;
else
elapsed = tempel;
if ( duration != 0 )
alpha = tempel / double(duration);
else
alpha = 1;
if ( alpha >= 1 || !showWidget) {
anim.stop();
qApp->removeEventFilter( this );
if ( widget ) {
if ( !showWidget ) {
#ifdef Q_WS_WIN
setEnabled(TRUE);
setFocus();
#endif
widget->hide();
widget->setWState( WState_ForceHide );
widget->clearWState( WState_Visible );
} else if ( duration ) {
BackgroundMode bgm = widget->backgroundMode();
QColor erc = widget->eraseColor();
const QPixmap *erp = widget->erasePixmap();
widget->clearWState( WState_Visible );
widget->setBackgroundMode( NoBackground );
widget->show();
if ( bgm != FixedColor && bgm != FixedPixmap ) {
widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
widget->setBackgroundMode( bgm );
widget->setWState( WState_Visible );
}
if ( erc.isValid() ) {
widget->setEraseColor( erc );
} else if ( erp ) {
widget->setErasePixmap( *erp );
}
} else {
widget->clearWState( WState_Visible );
widget->show();
}
}
q_blend = 0;
deleteLater();
} else {
if (widget)
widget->clearWState( WState_ForceHide );
alphaBlend();
pm = mixed;
repaint( FALSE );
}
}
/*
Calculate an alphablended image.
*/
void QAlphaWidget::alphaBlend()
{
const double ia = 1-alpha;
const int sw = front.width();
const int sh = front.height();
switch( front.depth() ) {
case 32:
{
Q_UINT32** md = (Q_UINT32**)mixed.jumpTable();
Q_UINT32** bd = (Q_UINT32**)back.jumpTable();
Q_UINT32** fd = (Q_UINT32**)front.jumpTable();
for (int sy = 0; sy < sh; sy++ ) {
Q_UINT32* bl = ((Q_UINT32*)bd[sy]);
Q_UINT32* fl = ((Q_UINT32*)fd[sy]);
for (int sx = 0; sx < sw; sx++ ) {
Q_UINT32 bp = bl[sx];
Q_UINT32 fp = fl[sx];
((Q_UINT32*)(md[sy]))[sx] = qRgb(int (qRed(bp)*ia + qRed(fp)*alpha),
int (qGreen(bp)*ia + qGreen(fp)*alpha),
int (qBlue(bp)*ia + qBlue(fp)*alpha) );
}
}
}
default:
break;
}
}
/* REMOVED CLASS DEFINITION HERE (MOVED TO qeffects.h) */
static QRollEffect* q_roll = 0;
/*
Construct a QRollEffect widget.
*/
QRollEffect::QRollEffect( QWidget* w, WFlags f, DirFlags orient )
: QWidget( QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)),
"qt internal roll effect widget", f ), orientation(orient)
{
#if 1 //ndef Q_WS_WIN
setEnabled( FALSE );
#endif
widget = (QAccessWidget*) w;
Q_ASSERT( widget );
setBackgroundMode( NoBackground );
if ( widget->testWState( WState_Resized ) ) {
totalWidth = widget->width();
totalHeight = widget->height();
} else {
totalWidth = widget->sizeHint().width();
totalHeight = widget->sizeHint().height();
}
currentHeight = totalHeight;
currentWidth = totalWidth;
if ( orientation & (RightScroll|LeftScroll) )
currentWidth = 0;
if ( orientation & (DownScroll|UpScroll) )
currentHeight = 0;
pm.setOptimization( QPixmap::BestOptim );
pm = QPixmap::grabWidget( widget );
}
/*
\reimp
*/
void QRollEffect::paintEvent( QPaintEvent* )
{
int x = orientation & RightScroll ? QMIN(0, currentWidth - totalWidth) : 0;
int y = orientation & DownScroll ? QMIN(0, currentHeight - totalHeight) : 0;
bitBlt( this, x, y, &pm,
0, 0, pm.width(), pm.height(), CopyROP, TRUE );
}
/*
\reimp
*/
bool QRollEffect::eventFilter( QObject* o, QEvent* e )
{
switch ( e->type() ) {
case QEvent::Move:
if ( o != widget )
break;
move( widget->geometry().x(),widget->geometry().y() );
update();
break;
case QEvent::Hide:
case QEvent::Close:
if ( o != widget || done )
break;
setEnabled(TRUE);
showWidget = FALSE;
done = TRUE;
scroll();
break;
case QEvent::MouseButtonPress:
#ifndef QT_NO_SCROLLVIEW
if ( ::qt_cast<QScrollView*>(o) )
break;
#endif
case QEvent::MouseButtonDblClick:
if ( done )
break;
setEnabled(TRUE);
showWidget = FALSE;
done = TRUE;
scroll();
break;
case QEvent::KeyPress:
{
QKeyEvent *ke = (QKeyEvent*)e;
/* THIS CODE WAS ADDED: ************** */
if (ke->key() == Qt::Key_Enter) /*** Because we are simulating an Enter key press. */
break; /*** So we should not car about it and continue the animation. */
/************************************* */
if ( ke->key() == Key_Escape )
showWidget = FALSE;
done = TRUE;
scroll();
break;
}
default:
break;
}
return QWidget::eventFilter( o, e );
}
/*
\reimp
*/
void QRollEffect::closeEvent( QCloseEvent *e )
{
e->accept();
if ( done )
return;
showWidget = FALSE;
done = TRUE;
scroll();
QWidget::closeEvent( e );
}
/*
Start the animation.
The animation will take about \a time ms, or is
calculated if \a time is negative
*/
void QRollEffect::run( int time )
{
if ( !widget )
return;
duration = time;
elapsed = 0;
if ( duration < 0 ) {
int dist = 0;
if ( orientation & (RightScroll|LeftScroll) )
dist += totalWidth - currentWidth;
if ( orientation & (DownScroll|UpScroll) )
dist += totalHeight - currentHeight;
duration = QMIN( QMAX( dist/3, 50 ), 120 );
}
connect( &anim, SIGNAL(timeout()), this, SLOT(scroll()));
widget->setWState( WState_Visible );
move( widget->geometry().x(),widget->geometry().y() );
resize( QMIN( currentWidth, totalWidth ), QMIN( currentHeight, totalHeight ) );
show();
setEnabled(FALSE);
qApp->installEventFilter( this );
showWidget = TRUE;
done = FALSE;
anim.start( 1 );
checkTime.start();
}
/*
Roll according to the time elapsed.
*/
void QRollEffect::scroll()
{
if ( !done && widget) {
widget->clearWState( WState_ForceHide );
int tempel = checkTime.elapsed();
if ( elapsed >= tempel )
elapsed++;
else
elapsed = tempel;
if ( currentWidth != totalWidth ) {
currentWidth = totalWidth * (elapsed/duration)
+ ( 2 * totalWidth * (elapsed%duration) + duration )
/ ( 2 * duration );
// equiv. to int( (totalWidth*elapsed) / duration + 0.5 )
done = (currentWidth >= totalWidth);
}
if ( currentHeight != totalHeight ) {
currentHeight = totalHeight * (elapsed/duration)
+ ( 2 * totalHeight * (elapsed%duration) + duration )
/ ( 2 * duration );
// equiv. to int( (totalHeight*elapsed) / duration + 0.5 )
done = (currentHeight >= totalHeight);
}
done = ( currentHeight >= totalHeight ) &&
( currentWidth >= totalWidth );
int w = totalWidth;
int h = totalHeight;
int x = widget->geometry().x();
int y = widget->geometry().y();
if ( orientation & RightScroll || orientation & LeftScroll )
w = QMIN( currentWidth, totalWidth );
if ( orientation & DownScroll || orientation & UpScroll )
h = QMIN( currentHeight, totalHeight );
setUpdatesEnabled( FALSE );
if ( orientation & UpScroll )
y = widget->geometry().y() + QMAX( 0, totalHeight - currentHeight );
if ( orientation & LeftScroll )
x = widget->geometry().x() + QMAX( 0, totalWidth - currentWidth );
if ( orientation & UpScroll || orientation & LeftScroll )
move( x, y );
resize( w, h );
setUpdatesEnabled( TRUE );
repaint( FALSE );
}
if ( done ) {
anim.stop();
qApp->removeEventFilter( this );
if ( widget ) {
if ( !showWidget ) {
#ifdef Q_WS_WIN
setEnabled(TRUE);
setFocus();
#endif
widget->hide();
widget->setWState( WState_ForceHide );
widget->clearWState( WState_Visible );
} else {
BackgroundMode bgm = widget->backgroundMode();
QColor erc = widget->eraseColor();
const QPixmap *erp = widget->erasePixmap();
widget->clearWState( WState_Visible );
widget->setBackgroundMode( NoBackground );
widget->show();
if ( bgm != FixedColor && bgm != FixedPixmap ) {
widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
widget->setBackgroundMode( bgm );
widget->setWState( WState_Visible );
}
if ( erc.isValid() ) {
widget->setEraseColor( erc );
} else if ( erp ) {
widget->setErasePixmap( *erp );
}
}
}
q_roll = 0;
deleteLater();
}
}
/*
Delete this after timeout
*/
#include "qeffects.moc"
/*!
Scroll widget \a w in \a time ms. \a orient may be 1 (vertical), 2
(horizontal) or 3 (diagonal).
*/
void qScrollEffect( QWidget* w, QEffects::DirFlags orient, int time )
{
if ( q_roll ) {
delete q_roll;
q_roll = 0;
}
qApp->sendPostedEvents( w, QEvent::Move );
qApp->sendPostedEvents( w, QEvent::Resize );
#ifdef Q_WS_X11
uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
| (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
#else
uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
#endif
// those can popups - they would steal the focus, but are disabled
q_roll = new QRollEffect( w, flags, orient );
q_roll->run( time );
}
/*!
Fade in widget \a w in \a time ms.
*/
void qFadeEffect( QWidget* w, int time )
{
if ( q_blend ) {
delete q_blend;
q_blend = 0;
}
qApp->sendPostedEvents( w, QEvent::Move );
qApp->sendPostedEvents( w, QEvent::Resize );
#ifdef Q_WS_X11
uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
| (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
#else
uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
#endif
// those can popups - they would steal the focus, but are disabled
q_blend = new QAlphaWidget( w, flags );
q_blend->run( time );
}
#endif //QT_NO_EFFECTS
#endif // #if 0

@ -0,0 +1,195 @@
#if 0
// Note: this file has been copied from the Qt source.
// Those classes are normally used internally in Qt
// but we need them for immitate the roll-over effect of QComboBox.
//
// Some class definitions have been moved from qeffects.cpp to this file.
// They are framed with the comment "MOVED FROM qeffect.cpp"
/****************************************************************************
** $Id: qt/qeffects_p.h 3.3.4 edited May 27 2003 $
**
** Definition of QEffects functions
**
** Created : 000621
**
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of the widgets module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#ifndef QEFFECTS_P_H
#define QEFFECTS_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of qeffects.cpp, qcombobox.cpp, qpopupmenu.cpp and qtooltip.cpp.
// This header file may change from version to version without notice,
// or even be removed.
//
// We mean it.
//
//
#ifndef QT_H
#include "qnamespace.h"
#endif // QT_H
#ifndef QT_NO_EFFECTS
class QWidget;
struct QEffects
{
enum Direction {
LeftScroll = 0x0001,
RightScroll = 0x0002,
UpScroll = 0x0004,
DownScroll = 0x0008
};
typedef uint DirFlags;
};
extern void Q_EXPORT qScrollEffect( QWidget*, QEffects::DirFlags dir = QEffects::DownScroll, int time = -1 );
extern void Q_EXPORT qFadeEffect( QWidget*, int time = -1 );
/******************* MOVED FROM qeffect.cpp: */
#include "qguardedptr.h"
#include "qdatetime.h"
#include "qtimer.h"
#include "qpixmap.h"
#include "qimage.h"
/*
Internal class to get access to protected QWidget-members
*/
class QAccessWidget : public QWidget
{
friend class QAlphaWidget;
friend class QRollEffect;
public:
QAccessWidget( QWidget* parent=0, const char* name=0, WFlags f = 0 )
: QWidget( parent, name, f ) {}
};
/*
Internal class QAlphaWidget.
The QAlphaWidget is shown while the animation lasts
and displays the pixmap resulting from the alpha blending.
*/
class QAlphaWidget: public QWidget, private QEffects
{
Q_OBJECT
public:
QAlphaWidget( QWidget* w, WFlags f = 0 );
void run( int time );
protected:
void paintEvent( QPaintEvent* e );
void closeEvent( QCloseEvent* );
bool eventFilter( QObject* o, QEvent* e );
void alphaBlend();
protected slots:
void render();
private:
QPixmap pm;
double alpha;
QImage back;
QImage front;
QImage mixed;
QGuardedPtr<QAccessWidget> widget;
int duration;
int elapsed;
bool showWidget;
QTimer anim;
QTime checkTime;
};
/*
Internal class QRollEffect
The QRollEffect widget is shown while the animation lasts
and displays a scrolling pixmap.
*/
class QRollEffect : public QWidget, private QEffects
{
Q_OBJECT
public:
QRollEffect( QWidget* w, WFlags f, DirFlags orient );
void run( int time );
protected:
void paintEvent( QPaintEvent* );
bool eventFilter( QObject*, QEvent* );
void closeEvent( QCloseEvent* );
private slots:
void scroll();
private:
QGuardedPtr<QAccessWidget> widget;
int currentHeight;
int currentWidth;
int totalHeight;
int totalWidth;
int duration;
int elapsed;
bool done;
bool showWidget;
int orientation;
QTimer anim;
QTime checkTime;
QPixmap pm;
};
/******************************/
#endif // QT_NO_EFFECTS
#endif // QEFFECTS_P_H
#endif // #if 0

@ -0,0 +1,180 @@
// Code from KSnapshot!
/*
Copyright (C) 2003 Nadeem Hasan <nhasan@kde.org>
This library 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
Library General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "regiongrabber.h"
#include <qapplication.h>
#include <qpainter.h>
#include <qpalette.h>
#include <qstyle.h>
#include <qtimer.h>
#include <qtooltip.h>
#include <kglobalsettings.h>
SizeTip::SizeTip( QWidget *parent, const char *name )
: QLabel( parent, name, WStyle_Customize | WX11BypassWM |
WStyle_StaysOnTop | WStyle_NoBorder | WStyle_Tool )
{
setMargin( 2 );
setIndent( 0 );
setFrameStyle( QFrame::Plain | QFrame::Box );
setPalette( QToolTip::palette() );
}
void SizeTip::setTip( const QRect &rect )
{
QString tip = QString( "%1x%2" ).arg( rect.width() )
.arg( rect.height() );
setText( tip );
adjustSize();
positionTip( rect );
}
void SizeTip::positionTip( const QRect &rect )
{
QRect tipRect = geometry();
tipRect.moveTopLeft( QPoint( 0, 0 ) );
if ( rect.intersects( tipRect ) )
{
QRect deskR = KGlobalSettings::desktopGeometry( QPoint( 0, 0 ) );
tipRect.moveCenter( QPoint( deskR.width()/2, deskR.height()/2 ) );
if ( !rect.contains( tipRect, true ) && rect.intersects( tipRect ) )
tipRect.moveBottomRight( geometry().bottomRight() );
}
move( tipRect.topLeft() );
}
RegionGrabber::RegionGrabber(int delay)
: QWidget( 0, 0 ),
mouseDown( false ), sizeTip( 0L )
{
sizeTip = new SizeTip( ( QWidget * )0L );
tipTimer = new QTimer( this );
connect( tipTimer, SIGNAL( timeout() ), SLOT( updateSizeTip() ) );
QTimer::singleShot( delay, this, SLOT( initGrabber() ) );
}
RegionGrabber::~RegionGrabber()
{
delete sizeTip;
}
void RegionGrabber::initGrabber()
{
pixmap = QPixmap::grabWindow( qt_xrootwin() );
setPaletteBackgroundPixmap( pixmap );
QDesktopWidget desktopWidget;
QRect desktopSize;
if ( desktopWidget.isVirtualDesktop() )
desktopSize = desktopWidget.geometry();
else
desktopSize = desktopWidget.screenGeometry( qt_xrootwin() );
setGeometry( desktopSize );
showFullScreen();
QApplication::setOverrideCursor( crossCursor );
}
void RegionGrabber::mousePressEvent( QMouseEvent *e )
{
if ( e->button() == LeftButton )
{
mouseDown = true;
grabRect = QRect( e->pos(), e->pos() );
drawRubber();
}
}
void RegionGrabber::mouseMoveEvent( QMouseEvent *e )
{
if ( mouseDown )
{
sizeTip->hide();
tipTimer->start( 250, true );
drawRubber();
grabRect.setBottomRight( e->pos() );
drawRubber();
}
}
void RegionGrabber::mouseReleaseEvent( QMouseEvent *e )
{
mouseDown = false;
drawRubber();
sizeTip->hide();
grabRect.setBottomRight( e->pos() );
grabRect = grabRect.normalize();
QPixmap region = QPixmap::grabWindow( winId(), grabRect.x(), grabRect.y(),
grabRect.width(), grabRect.height() );
QApplication::restoreOverrideCursor();
emit regionGrabbed( region );
}
void RegionGrabber::keyPressEvent( QKeyEvent *e )
{
if ( e->key() == Key_Escape )
{
QApplication::restoreOverrideCursor();
emit regionGrabbed( QPixmap() );
}
else
e->ignore();
}
void RegionGrabber::updateSizeTip()
{
QRect rect = grabRect.normalize();
sizeTip->setTip( rect );
sizeTip->show();
}
void RegionGrabber::drawRubber()
{
QPainter p;
p.begin( this );
p.setRasterOp( NotROP );
p.setPen( QPen( color0, 1 ) );
p.setBrush( NoBrush );
style().drawPrimitive( QStyle::PE_FocusRect, &p, grabRect, colorGroup(),
QStyle::Style_Default, QStyleOption( colorGroup().base() ) );
p.end();
}
#include "regiongrabber.moc"

@ -0,0 +1,72 @@
// Code from KSnapshot!
/*
Copyright (C) 2003 Nadeem Hasan <nhasan@kde.org>
This library 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
Library General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef REGIONGRABBER_H
#define REGIONGRABBER_H
#include <qlabel.h>
#include <qpixmap.h>
class QTimer;
class SizeTip : public QLabel
{
public:
SizeTip( QWidget *parent, const char *name=0 );
~SizeTip() {}
void setTip( const QRect &rect );
void positionTip( const QRect &rect );
};
class RegionGrabber : public QWidget
{
Q_OBJECT
public:
RegionGrabber(int delay);
~RegionGrabber();
protected slots:
void initGrabber();
void updateSizeTip();
signals:
void regionGrabbed( const QPixmap & );
protected:
void mousePressEvent( QMouseEvent *e );
void mouseReleaseEvent( QMouseEvent *e );
void mouseMoveEvent( QMouseEvent *e );
void keyPressEvent( QKeyEvent *e );
void drawRubber();
bool mouseDown;
QRect grabRect;
QPixmap pixmap;
SizeTip *sizeTip;
QTimer *tipTimer;
};
#endif // REGIONGRABBER_H

@ -0,0 +1,991 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <config.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qhbox.h>
#include <qvbox.h>
#include <qtabwidget.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <knuminput.h>
#include <kcolorcombo.h>
#include <kiconloader.h>
#include <kconfig.h>
#include <kglobal.h>
#include <klocale.h>
#include <qwhatsthis.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qvbuttongroup.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <kgpgme.h>
#include <kdebug.h>
#include <qdatetime.h>
#include "basket.h"
#include "linklabel.h"
#include "settings.h"
#include "variouswidgets.h"
#include "note.h"
/** Settings */
// General: // TODO: Use this grouping everywhere!
bool Settings::s_useSystray = true;
bool Settings::s_usePassivePopup = true;
bool Settings::s_playAnimations = true;
bool Settings::s_showNotesToolTip = true; // TODO: RENAME: useBasketTooltips
bool Settings::s_confirmNoteDeletion = true;
bool Settings::s_bigNotes = false;
bool Settings::s_autoBullet = true;
bool Settings::s_exportTextTags = true;
bool Settings::s_useGnuPGAgent = false;
bool Settings::s_treeOnLeft = true;
bool Settings::s_filterOnTop = true;
int Settings::s_defImageX = 300;
int Settings::s_defImageY = 200;
bool Settings::s_enableReLockTimeout = true;
int Settings::s_reLockTimeoutMinutes = 0;
int Settings::s_newNotesPlace = 1;
int Settings::s_viewTextFileContent = false;
int Settings::s_viewHtmlFileContent = false;
int Settings::s_viewImageFileContent = false;
int Settings::s_viewSoundFileContent = false;
// Applications:
bool Settings::s_htmlUseProg = false; // TODO: RENAME: s_*App (with KService!)
bool Settings::s_imageUseProg = true;
bool Settings::s_animationUseProg = true;
bool Settings::s_soundUseProg = false;
QString Settings::s_htmlProg = "quanta";
QString Settings::s_imageProg = "kolourpaint";
QString Settings::s_animationProg = "gimp";
QString Settings::s_soundProg = "";
// Addictive Features:
bool Settings::s_groupOnInsertionLine = false;
int Settings::s_middleAction = 0;
bool Settings::s_showIconInSystray = false; // TODO: RENAME: basketIconInSystray
bool Settings::s_hideOnMouseOut = false;
int Settings::s_timeToHideOnMouseOut = 0;
bool Settings::s_showOnMouseIn = false;
int Settings::s_timeToShowOnMouseIn = 1;
// Rememberings:
int Settings::s_defIconSize = 32; // TODO: RENAME: importIconSize
bool Settings::s_blinkedFilter = false;
bool Settings::s_startDocked = false;
int Settings::s_basketTreeWidth = -1;
bool Settings::s_welcomeBasketsAdded = false;
QString Settings::s_dataFolder = "";
QDate Settings::s_lastBackup = QDate();
QPoint Settings::s_mainWindowPosition = QPoint();
QSize Settings::s_mainWindowSize = QSize();
bool Settings::s_showEmptyBasketInfo = true;
bool Settings::s_spellCheckTextNotes = true;
void Settings::loadConfig()
{
LinkLook defaultSoundLook;
LinkLook defaultFileLook;
LinkLook defaultLocalLinkLook;
LinkLook defaultNetworkLinkLook;
LinkLook defaultLauncherLook; /* italic bold underlining color hoverColor iconSize preview */
defaultSoundLook.setLook( false, false, LinkLook::Never, QColor(), QColor(), 32, LinkLook::None );
defaultFileLook.setLook( false, false, LinkLook::Never, QColor(), QColor(), 32, LinkLook::TwiceIconSize );
defaultLocalLinkLook.setLook( true, false, LinkLook::OnMouseHover, QColor(), QColor(), 22, LinkLook::TwiceIconSize );
defaultNetworkLinkLook.setLook( false, false, LinkLook::OnMouseOutside, QColor(), QColor(), 16, LinkLook::None );
defaultLauncherLook.setLook( false, true, LinkLook::Never, QColor(), QColor(), 48, LinkLook::None );
loadLinkLook(LinkLook::soundLook, "Sound Look", defaultSoundLook );
loadLinkLook(LinkLook::fileLook, "File Look", defaultFileLook );
loadLinkLook(LinkLook::localLinkLook, "Local Link Look", defaultLocalLinkLook );
loadLinkLook(LinkLook::networkLinkLook, "Network Link Look", defaultNetworkLinkLook);
loadLinkLook(LinkLook::launcherLook, "Launcher Look", defaultLauncherLook );
KConfig* config = Global::config();
config->setGroup("Main window"); // TODO: Split with a "System tray icon" group !
setTreeOnLeft( config->readBoolEntry("treeOnLeft", true) );
setFilterOnTop( config->readBoolEntry("filterOnTop", true) );
setPlayAnimations( config->readBoolEntry("playAnimations", true) );
setShowNotesToolTip( config->readBoolEntry("showNotesToolTip", true) );
setBigNotes( config->readBoolEntry("bigNotes", false) );
setConfirmNoteDeletion( config->readBoolEntry("confirmNoteDeletion", true) );
setAutoBullet( config->readBoolEntry("autoBullet", true) );
setExportTextTags( config->readBoolEntry("exportTextTags", true) );
setUseGnuPGAgent( config->readBoolEntry("useGnuPGAgent", false) );
setBlinkedFilter( config->readBoolEntry("blinkedFilter", false) );
setEnableReLockTimeout( config->readNumEntry( "enableReLockTimeout", true) );
setReLockTimeoutMinutes( config->readNumEntry( "reLockTimeoutMinutes", 0) );
setUseSystray( config->readBoolEntry("useSystray", true) );
setShowIconInSystray( config->readBoolEntry("showIconInSystray", false) );
setStartDocked( config->readBoolEntry("startDocked", false) );
setMiddleAction( config->readNumEntry( "middleAction", 0) );
setGroupOnInsertionLine( config->readBoolEntry("groupOnInsertionLine", false) );
setSpellCheckTextNotes( config->readBoolEntry("spellCheckTextNotes", true) );
setHideOnMouseOut( config->readBoolEntry("hideOnMouseOut", false) );
setTimeToHideOnMouseOut( config->readNumEntry( "timeToHideOnMouseOut", 0) );
setShowOnMouseIn( config->readBoolEntry("showOnMouseIn", false) );
setTimeToShowOnMouseIn( config->readNumEntry( "timeToShowOnMouseIn", 1) );
setBasketTreeWidth( config->readNumEntry( "basketTreeWidth", -1) );
setUsePassivePopup( config->readBoolEntry("usePassivePopup", true) );
setWelcomeBasketsAdded( config->readBoolEntry("welcomeBasketsAdded", false) );
setDataFolder( config->readPathEntry("dataFolder", "") );
setLastBackup( config->readDateTimeEntry("lastBackup", new QDateTime()).date());
setMainWindowPosition( config->readPointEntry("position" ) );
setMainWindowSize( config->readSizeEntry( "size" ) );
config->setGroup("Notification Messages");
setShowEmptyBasketInfo( config->readBoolEntry("emptyBasketInfo", true) );
config->setGroup("Programs");
setIsHtmlUseProg( config->readBoolEntry("htmlUseProg", false) );
setIsImageUseProg( config->readBoolEntry("imageUseProg", true) );
setIsAnimationUseProg( config->readBoolEntry("animationUseProg", true) );
setIsSoundUseProg( config->readBoolEntry("soundUseProg", false) );
setHtmlProg( config->readEntry( "htmlProg", "quanta") );
setImageProg( config->readEntry( "imageProg", "kolourpaint") );
setAnimationProg( config->readEntry( "animationProg", "gimp") );
setSoundProg( config->readEntry( "soundProg", "") );
config->setGroup("Note Addition");
setNewNotesPlace( config->readNumEntry( "newNotesPlace", 1) );
setViewTextFileContent( config->readBoolEntry("viewTextFileContent", false) );
setViewHtmlFileContent( config->readBoolEntry("viewHtmlFileContent", false) );
setViewImageFileContent( config->readBoolEntry("viewImageFileContent", true) );
setViewSoundFileContent( config->readBoolEntry("viewSoundFileContent", true) );
config->setGroup("Insert Note Default Values");
setDefImageX( config->readNumEntry( "defImageX", 300) );
setDefImageY( config->readNumEntry( "defImageY", 200) );
setDefIconSize( config->readNumEntry( "defIconSize", 32) );
config->setGroup("MainWindow Toolbar mainToolBar");
// The first time we start, we define "Text Alongside Icons" for the main toolbar.
// After that, the user is free to hide the text from the icons or customize as he/she want.
// But it is a good default (Fitt's Laws, better looking, less "empty"-feeling), especially for this application.
// if (!config->readBoolEntry("alreadySetIconTextRight", false)) {
// config->writeEntry( "IconText", "IconTextRight" );
// config->writeEntry( "alreadySetIconTextRight", true );
// }
if (!config->readBoolEntry("alreadySetToolbarSettings", false)) {
config->writeEntry("IconText", "IconOnly"); // In 0.6.0 Alpha versions, it was made "IconTextRight". We're back to IconOnly
config->writeEntry("Index", "0"); // Make sure the main toolbar is the first...
config->setGroup("MainWindow Toolbar richTextEditToolBar");
config->writeEntry("Position", "Top"); // In 0.6.0 Alpha versions, it was made "Bottom"
config->writeEntry("Index", "1"); // ... and the rich text toolbar is on the right of the main toolbar
config->setGroup("MainWindow Toolbar mainToolBar");
config->writeEntry("alreadySetToolbarSettings", true);
}
}
void Settings::saveConfig()
{
saveLinkLook(LinkLook::soundLook, "Sound Look" );
saveLinkLook(LinkLook::fileLook, "File Look" );
saveLinkLook(LinkLook::localLinkLook, "Local Link Look" );
saveLinkLook(LinkLook::networkLinkLook, "Network Link Look");
saveLinkLook(LinkLook::launcherLook, "Launcher Look" );
KConfig* config = Global::config();
config->setGroup("Main window");
config->writeEntry( "treeOnLeft", treeOnLeft() );
config->writeEntry( "filterOnTop", filterOnTop() );
config->writeEntry( "playAnimations", playAnimations() );
config->writeEntry( "showNotesToolTip", showNotesToolTip() );
config->writeEntry( "confirmNoteDeletion", confirmNoteDeletion() );
config->writeEntry( "bigNotes", bigNotes() );
config->writeEntry( "autoBullet", autoBullet() );
config->writeEntry( "exportTextTags", exportTextTags() );
#ifdef HAVE_LIBGPGME
if (KGpgMe::isGnuPGAgentAvailable())
config->writeEntry( "useGnuPGAgent", useGnuPGAgent() );
#endif
config->writeEntry( "blinkedFilter", blinkedFilter() );
config->writeEntry( "enableReLockTimeout", enableReLockTimeout() );
config->writeEntry( "reLockTimeoutMinutes", reLockTimeoutMinutes() );
config->writeEntry( "useSystray", useSystray() );
config->writeEntry( "showIconInSystray", showIconInSystray() );
config->writeEntry( "startDocked", startDocked() );
config->writeEntry( "middleAction", middleAction() );
config->writeEntry( "groupOnInsertionLine", groupOnInsertionLine() );
config->writeEntry( "spellCheckTextNotes", spellCheckTextNotes() );
config->writeEntry( "hideOnMouseOut", hideOnMouseOut() );
config->writeEntry( "timeToHideOnMouseOut", timeToHideOnMouseOut() );
config->writeEntry( "showOnMouseIn", showOnMouseIn() );
config->writeEntry( "timeToShowOnMouseIn", timeToShowOnMouseIn() );
config->writeEntry( "basketTreeWidth", basketTreeWidth() );
config->writeEntry( "usePassivePopup", usePassivePopup() );
config->writeEntry( "welcomeBasketsAdded", welcomeBasketsAdded() );
config->writePathEntry("dataFolder", dataFolder() );
config->writeEntry( "lastBackup", QDateTime(lastBackup()));
config->writeEntry( "position", mainWindowPosition() );
config->writeEntry( "size", mainWindowSize() );
config->setGroup("Notification Messages");
config->writeEntry( "emptyBasketInfo", showEmptyBasketInfo() );
config->setGroup("Programs");
config->writeEntry( "htmlUseProg", isHtmlUseProg() );
config->writeEntry( "imageUseProg", isImageUseProg() );
config->writeEntry( "animationUseProg", isAnimationUseProg() );
config->writeEntry( "soundUseProg", isSoundUseProg() );
config->writeEntry( "htmlProg", htmlProg() );
config->writeEntry( "imageProg", imageProg() );
config->writeEntry( "animationProg", animationProg() );
config->writeEntry( "soundProg", soundProg() );
config->setGroup("Note Addition");
config->writeEntry( "newNotesPlace", newNotesPlace() );
config->writeEntry( "viewTextFileContent", viewTextFileContent() );
config->writeEntry( "viewHtmlFileContent", viewHtmlFileContent() );
config->writeEntry( "viewImageFileContent", viewImageFileContent() );
config->writeEntry( "viewSoundFileContent", viewSoundFileContent() );
config->setGroup("Insert Note Default Values");
config->writeEntry( "defImageX", defImageX() );
config->writeEntry( "defImageY", defImageY() );
config->writeEntry( "defIconSize", defIconSize() );
config->sync();
}
void Settings::loadLinkLook(LinkLook *look, const QString &name, const LinkLook &defaultLook)
{
KConfig* config = Global::config();
config->setGroup(name);
QString underliningStrings[] = { "Always", "Never", "OnMouseHover", "OnMouseOutside" };
QString defaultUnderliningString = underliningStrings[defaultLook.underlining()];
QString previewStrings[] = { "None", "IconSize", "TwiceIconSize", "ThreeIconSize" };
QString defaultPreviewString = previewStrings[defaultLook.preview()];
bool italic = config->readBoolEntry( "italic", defaultLook.italic() );
bool bold = config->readBoolEntry( "bold", defaultLook.bold() );
QString underliningString = config->readEntry( "underlining", defaultUnderliningString );
QColor color = config->readPropertyEntry( "color", defaultLook.color() ).asColor();
QColor hoverColor = config->readPropertyEntry( "hoverColor", defaultLook.hoverColor() ).asColor();
int iconSize = config->readNumEntry( "iconSize", defaultLook.iconSize() );
QString previewString = config->readEntry( "preview", defaultPreviewString );
int underlining = 0;
if (underliningString == underliningStrings[1]) underlining = 1;
else if (underliningString == underliningStrings[2]) underlining = 2;
else if (underliningString == underliningStrings[3]) underlining = 3;
int preview = 0;
if (previewString == previewStrings[1]) preview = 1;
else if (previewString == previewStrings[2]) preview = 2;
else if (previewString == previewStrings[3]) preview = 3;
look->setLook(italic, bold, underlining, color, hoverColor, iconSize, preview);
}
void Settings::saveLinkLook(LinkLook *look, const QString &name)
{
KConfig* config = Global::config();
config->setGroup(name);
QString underliningStrings[] = { "Always", "Never", "OnMouseHover", "OnMouseOutside" };
QString underliningString = underliningStrings[look->underlining()];
QString previewStrings[] = { "None", "IconSize", "TwiceIconSize", "ThreeIconSize" };
QString previewString = previewStrings[look->preview()];
config->writeEntry( "italic", look->italic() );
config->writeEntry( "bold", look->bold() );
config->writeEntry( "underlining", underliningString );
config->writeEntry( "color", look->color() );
config->writeEntry( "hoverColor", look->hoverColor() );
config->writeEntry( "iconSize", look->iconSize() );
config->writeEntry( "preview", previewString );
}
void Settings::setBigNotes(bool big)
{
if (big == s_bigNotes)
return;
s_bigNotes = big;
// Big notes for accessibility reasons OR Standard small notes:
Note::NOTE_MARGIN = (big ? 4 : 2);
Note::INSERTION_HEIGHT = (big ? 5 : 3);
Note::EXPANDER_WIDTH = 9;
Note::EXPANDER_HEIGHT = 9;
Note::GROUP_WIDTH = 2*Note::NOTE_MARGIN + Note::EXPANDER_WIDTH;
Note::HANDLE_WIDTH = Note::GROUP_WIDTH;
Note::RESIZER_WIDTH = Note::GROUP_WIDTH;
Note::TAG_ARROW_WIDTH = 5 + (big ? 4 : 0);
Note::EMBLEM_SIZE = 16;
Note::MIN_HEIGHT = 2*Note::NOTE_MARGIN + Note::EMBLEM_SIZE;
if (Global::bnpView)
Global::bnpView->relayoutAllBaskets();
}
void Settings::setAutoBullet(bool yes)
{
s_autoBullet = yes;
if (Global::bnpView && Global::bnpView->currentBasket()) {
Global::bnpView->currentBasket()->editorPropertiesChanged();
}
}
/** GeneralPage */
GeneralPage::GeneralPage(QWidget * parent, const char * name)
: KCModule(parent, name)
{
QVBoxLayout *layout = new QVBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
QHBoxLayout *hLay;
QLabel *label;
HelpLabel *hLabel;
QGridLayout *gl = new QGridLayout(layout, /*nRows=*/3, /*nCols=*/3);
gl->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 2);
// Basket Tree Position:
m_treeOnLeft = new QComboBox(this);
m_treeOnLeft->insertItem(i18n("On left"));
m_treeOnLeft->insertItem(i18n("On right"));
label = new QLabel(m_treeOnLeft, i18n("&Basket tree position:"), this);
gl->addWidget(label, 0, 0);
gl->addWidget(m_treeOnLeft, 0, 1);
connect( m_treeOnLeft, SIGNAL(activated(int)), this, SLOT(changed()) );
// Filter Bar Position:
m_filterOnTop = new QComboBox(this);
m_filterOnTop->insertItem(i18n("On top"));
m_filterOnTop->insertItem(i18n("On bottom"));
label = new QLabel(m_filterOnTop, i18n("&Filter bar position:"), this);
gl->addWidget(label, 1, 0);
gl->addWidget(m_filterOnTop, 1, 1);
connect( m_filterOnTop, SIGNAL(activated(int)), this, SLOT(changed()) );
// Use Baloons to Report Results of Global Actions:
hLay = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
m_usePassivePopup = new QCheckBox(i18n("&Use balloons to report results of global actions"), this);
connect( m_usePassivePopup, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
hLabel = new HelpLabel(
i18n("What are global actions?"),
("<p>" + i18n("You can configure global shortcuts to do some actions without having to show the main window. For instance, you can paste the clipboard content, take a color from "
"a point of the screen, etc. You can also use the mouse scroll wheel over the system tray icon to change the current basket. Or use the middle mouse button "
"on that icon to paste the current selection.") + "</p>" +
"<p>" + i18n("When doing so, %1 pops up a little balloon message to inform you the action has been successfully done. You can disable that balloon.") + "</p>" +
"<p>" + i18n("Note that those messages are smart enough to not appear if the main window is visible. This is because you already see the result of your actions in the main window.") + "</p>")
.arg(kapp->aboutData()->programName()),
this);
hLay->addWidget(m_usePassivePopup);
hLay->addWidget(hLabel);
hLay->addStretch();
layout->addLayout(hLay);
// System Tray Icon:
QGroupBox *gbSys = new QGroupBox(3, Qt::Vertical, i18n("System Tray Icon"), this);
layout->addWidget(gbSys);
QVBoxLayout *sysLay = new QVBoxLayout(gbSys, /*margin=*/0, KDialogBase::spacingHint());
// Dock in System Tray:
m_useSystray = new QCheckBox(i18n("&Dock in system tray"), gbSys);
sysLay->addWidget(m_useSystray);
connect( m_useSystray, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
m_systray = new QWidget(gbSys);
QVBoxLayout *subSysLay = new QVBoxLayout(m_systray, /*margin=*/0, KDialogBase::spacingHint());
sysLay->addWidget(m_systray);
// Show Current Basket Icon in System Tray Icon:
m_showIconInSystray = new QCheckBox(i18n("&Show current basket icon in system tray icon"), m_systray);
subSysLay->addWidget(m_showIconInSystray);
connect(m_showIconInSystray, SIGNAL(stateChanged(int)), this, SLOT(changed()));
QGridLayout *gs = new QGridLayout(0, /*nRows=*/2, /*nCols=*/3);
subSysLay->addLayout(gs);
gs->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 2);
// Hide Main Window when Mouse Goes out of it for Some Time:
m_timeToHideOnMouseOut = new KIntNumInput(0, m_systray);
m_hideOnMouseOut = new QCheckBox(i18n("&Hide main window when mouse leaves it for"), m_systray);
m_timeToHideOnMouseOut->setRange(0, 600, 1, false);
m_timeToHideOnMouseOut->setSuffix(i18n(" tenths of seconds"));
gs->addWidget(m_hideOnMouseOut, 0, 0);
gs->addWidget(m_timeToHideOnMouseOut, 0, 1);
connect(m_hideOnMouseOut, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_timeToHideOnMouseOut, SIGNAL(valueChanged (int)), this, SLOT(changed()));
// subSysLay->addWidget(
// Show Main Window when Mouse Hovers over the System Tray Icon for Some Time:
m_timeToShowOnMouseIn = new KIntNumInput(0, m_systray);
m_showOnMouseIn = new QCheckBox(i18n("Show &main window when mouse hovers over the system tray icon for"), m_systray);
m_timeToShowOnMouseIn->setRange(0, 600, 1, false);
m_timeToShowOnMouseIn->setSuffix(i18n(" tenths of seconds"));
gs->addWidget(m_showOnMouseIn, 1, 0);
gs->addWidget(m_timeToShowOnMouseIn, 1, 1);
connect(m_showOnMouseIn, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_timeToShowOnMouseIn, SIGNAL(valueChanged (int)), this, SLOT(changed()));
connect( m_hideOnMouseOut, SIGNAL(toggled(bool)), m_timeToHideOnMouseOut, SLOT(setEnabled(bool)) );
connect( m_showOnMouseIn, SIGNAL(toggled(bool)), m_timeToShowOnMouseIn, SLOT(setEnabled(bool)) );
connect( m_useSystray, SIGNAL(toggled(bool)), m_systray, SLOT(setEnabled(bool)) );
layout->insertStretch(-1);
load();
}
void GeneralPage::load()
{
m_treeOnLeft->setCurrentItem( (int)!Settings::treeOnLeft() );
m_filterOnTop->setCurrentItem( (int)!Settings::filterOnTop() );
m_usePassivePopup->setChecked(Settings::usePassivePopup());
m_useSystray->setChecked( Settings::useSystray() );
m_systray->setEnabled( Settings::useSystray() );
m_showIconInSystray->setChecked( Settings::showIconInSystray() );
m_hideOnMouseOut->setChecked( Settings::hideOnMouseOut() );
m_timeToHideOnMouseOut->setValue( Settings::timeToHideOnMouseOut() );
m_timeToHideOnMouseOut->setEnabled( Settings::hideOnMouseOut() );
m_showOnMouseIn->setChecked( Settings::showOnMouseIn() );
m_timeToShowOnMouseIn->setValue( Settings::timeToShowOnMouseIn() );
m_timeToShowOnMouseIn->setEnabled( Settings::showOnMouseIn() );
}
void GeneralPage::save()
{
Settings::setTreeOnLeft( ! m_treeOnLeft->currentItem() );
Settings::setFilterOnTop( ! m_filterOnTop->currentItem() );
Settings::setUsePassivePopup( m_usePassivePopup->isChecked() );
Settings::setUseSystray( m_useSystray->isChecked() );
Settings::setShowIconInSystray( m_showIconInSystray->isChecked() );
Settings::setShowOnMouseIn( m_showOnMouseIn->isChecked() );
Settings::setTimeToShowOnMouseIn( m_timeToShowOnMouseIn->value() );
Settings::setHideOnMouseOut( m_hideOnMouseOut->isChecked() );
Settings::setTimeToHideOnMouseOut( m_timeToHideOnMouseOut->value() );
}
void GeneralPage::defaults()
{
// TODO
}
/** BasketsPage */
BasketsPage::BasketsPage(QWidget * parent, const char * name)
: KCModule(parent, name)
{
QVBoxLayout *layout = new QVBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
QHBoxLayout *hLay;
HelpLabel *hLabel;
// Appearance:
QGroupBox *appearanceBox = new QGroupBox(3, Qt::Vertical, i18n("Appearance"), this);
layout->addWidget(appearanceBox);
m_playAnimations = new QCheckBox(i18n("Ani&mate changes in baskets"), appearanceBox);
connect( m_playAnimations, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
m_showNotesToolTip = new QCheckBox(i18n("&Show tooltips in baskets"), appearanceBox);
connect( m_showNotesToolTip, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
m_bigNotes = new QCheckBox(i18n("&Big notes"), appearanceBox);
connect( m_bigNotes, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
// Behavior:
QGroupBox *behaviorBox = new QGroupBox(5, Qt::Vertical, i18n("Behavior"), this);
layout->addWidget(behaviorBox);
m_autoBullet = new QCheckBox(i18n("&Transform lines starting with * or - to lists in text editors"), behaviorBox);
connect( m_autoBullet, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
m_confirmNoteDeletion = new QCheckBox(i18n("Ask confirmation before &deleting notes"), behaviorBox);
connect( m_confirmNoteDeletion, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
QWidget *widget = new QWidget(behaviorBox);
hLay = new QHBoxLayout(widget, /*margin=*/0, KDialogBase::spacingHint());
m_exportTextTags = new QCheckBox(i18n("&Export tags in texts"), widget);
connect( m_exportTextTags, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
QPixmap pixmapHelp(KGlobal::dirs()->findResource("data", "basket/images/tag_export_help.png"));
QMimeSourceFactory::defaultFactory()->setPixmap("__resource_help_tag_export.png", pixmapHelp);
hLabel = new HelpLabel(
i18n("When does this apply?"),
"<p>" + i18n("It does apply when you copy and paste, or drag and drop notes to a text editor.") + "</p>" +
"<p>" + i18n("If enabled, this property lets you paste the tags as textual equivalents.") + "<br>" +
i18n("For instance, a list of notes with the <b>To Do</b> and <b>Done</b> tags are exported as lines preceded by <b>[ ]</b> or <b>[x]</b>, "
"representing an empty checkbox and a checked box.") + "</p>" +
"<p align='center'><img src=\"__resource_help_tag_export.png\"></p>",
widget);
hLay->addWidget(m_exportTextTags);
hLay->addWidget(hLabel);
hLay->addStretch();
m_groupOnInsertionLineWidget = new QWidget(behaviorBox);
QHBoxLayout *hLayV = new QHBoxLayout(m_groupOnInsertionLineWidget, /*margin=*/0, KDialogBase::spacingHint());
m_groupOnInsertionLine = new QCheckBox(i18n("&Group a new note when clicking on the right of the insertion line"), m_groupOnInsertionLineWidget);
QPixmap pixmap(KGlobal::dirs()->findResource("data", "basket/images/insertion_help.png"));
QMimeSourceFactory::defaultFactory()->setPixmap("__resource_help_insertion_line.png", pixmap);
HelpLabel *helpV = new HelpLabel(
i18n("How to group a new note?"),
i18n("<p>When this option is enabled, the insertion-line not only allows you to insert notes at the cursor position, but also allows you to group a new note with the one under the cursor:</p>") +
"<p align='center'><img src=\"__resource_help_insertion_line.png\"></p>" +
i18n("<p>Place your mouse between notes, where you want to add a new one.<br>"
"Click on the <b>left</b> of the insertion-line middle-mark to <b>insert</b> a note.<br>"
"Click on the <b>right</b> to <b>group</b> a note, with the one <b>below or above</b>, depending on where your mouse is.</p>"),
m_groupOnInsertionLineWidget);
hLayV->addWidget(m_groupOnInsertionLine);
hLayV->addWidget(helpV);
hLayV->insertStretch(-1);
layout->addWidget(m_groupOnInsertionLineWidget);
connect(m_groupOnInsertionLine, SIGNAL(stateChanged(int)), this, SLOT(changed()));
widget = new QWidget(behaviorBox);
QGridLayout *ga = new QGridLayout(widget, /*nRows=*/3, /*nCols=*/4, /*margin=*/0, KDialogBase::spacingHint());
ga->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 3);
m_middleAction = new QComboBox(widget);
m_middleAction->insertItem( i18n("Do nothing") );
m_middleAction->insertItem( i18n("Paste clipboard") );
m_middleAction->insertItem( i18n("Insert image note") );
m_middleAction->insertItem( i18n("Insert link note") );
m_middleAction->insertItem( i18n("Insert launcher note") );
m_middleAction->insertItem( i18n("Insert color note") );
m_middleAction->insertItem( i18n("Grab screen zone") );
m_middleAction->insertItem( i18n("Insert color from screen") );
m_middleAction->insertItem( i18n("Load note from file") );
m_middleAction->insertItem( i18n("Import Launcher from KDE Menu") );
m_middleAction->insertItem( i18n("Import icon") );
QLabel *labelM = new QLabel(m_middleAction, i18n("&Shift+middle-click anywhere:"), widget);
ga->addWidget(labelM, 0, 0);
ga->addWidget(m_middleAction, 0, 1);
ga->addWidget(new QLabel(i18n("at cursor position"), widget), 0, 2);
connect( m_middleAction, SIGNAL(activated(int)), this, SLOT(changed()) );
// Protection:
QGroupBox *protectionBox = new QGroupBox(3, Qt::Vertical, i18n("Password Protection"), this);
layout->addWidget(protectionBox);
widget = new QWidget(protectionBox);
// Re-Lock timeout configuration
hLay = new QHBoxLayout(widget, /*margin=*/0, KDialogBase::spacingHint());
m_enableReLockTimeoutMinutes = new QCheckBox(i18n("A&utomatically lock protected baskets when closed for"), widget);
hLay->addWidget(m_enableReLockTimeoutMinutes);
m_reLockTimeoutMinutes = new KIntNumInput(widget);
m_reLockTimeoutMinutes->setMinValue(0);
m_reLockTimeoutMinutes->setSuffix(i18n(" minutes"));
hLay->addWidget(m_reLockTimeoutMinutes);
//label = new QLabel(i18n("minutes"), this);
//hLay->addWidget(label);
hLay->addStretch();
// layout->addLayout(hLay);
connect( m_enableReLockTimeoutMinutes, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
connect( m_reLockTimeoutMinutes, SIGNAL(valueChanged(int)), this, SLOT(changed()) );
connect( m_enableReLockTimeoutMinutes, SIGNAL(toggled(bool)), m_reLockTimeoutMinutes, SLOT(setEnabled(bool)) );
#ifdef HAVE_LIBGPGME
m_useGnuPGAgent = new QCheckBox(i18n("Use GnuPG agent for &private/public key protected baskets"), protectionBox);
// hLay->addWidget(m_useGnuPGAgent);
connect( m_useGnuPGAgent, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
#endif
layout->insertStretch(-1);
load();
}
void BasketsPage::load()
{
m_playAnimations->setChecked(Settings::playAnimations());
m_showNotesToolTip->setChecked(Settings::showNotesToolTip());
m_bigNotes->setChecked(Settings::bigNotes());
m_autoBullet->setChecked(Settings::autoBullet());
m_confirmNoteDeletion->setChecked(Settings::confirmNoteDeletion());
m_exportTextTags->setChecked(Settings::exportTextTags());
m_groupOnInsertionLine->setChecked(Settings::groupOnInsertionLine());
m_middleAction->setCurrentItem(Settings::middleAction());
// The correctness of this code depends on the default of enableReLockTimeout
// being true - otherwise, the reLockTimeoutMinutes widget is not disabled properly.
m_enableReLockTimeoutMinutes->setChecked(Settings::enableReLockTimeout());
m_reLockTimeoutMinutes->setValue(Settings::reLockTimeoutMinutes());
#ifdef HAVE_LIBGPGME
m_useGnuPGAgent->setChecked(Settings::useGnuPGAgent());
if (KGpgMe::isGnuPGAgentAvailable()) {
m_useGnuPGAgent->setChecked(Settings::useGnuPGAgent());
} else {
m_useGnuPGAgent->setChecked(false);
m_useGnuPGAgent->setEnabled(false);
}
#endif
}
void BasketsPage::save()
{
Settings::setPlayAnimations( m_playAnimations->isChecked() );
Settings::setShowNotesToolTip( m_showNotesToolTip->isChecked() );
Settings::setBigNotes( m_bigNotes->isChecked() );
Settings::setAutoBullet( m_autoBullet->isChecked() );
Settings::setConfirmNoteDeletion( m_confirmNoteDeletion->isChecked() );
Settings::setExportTextTags( m_exportTextTags->isChecked() );
Settings::setGroupOnInsertionLine( m_groupOnInsertionLine->isChecked() );
Settings::setMiddleAction( m_middleAction->currentItem() );
Settings::setEnableReLockTimeout( m_enableReLockTimeoutMinutes->isChecked());
Settings::setReLockTimeoutMinutes(m_reLockTimeoutMinutes->value());
#ifdef HAVE_LIBGPGME
Settings::setUseGnuPGAgent( m_useGnuPGAgent->isChecked() );
#endif
}
void BasketsPage::defaults()
{
// TODO
}
/** class NewNotesPage: */
NewNotesPage::NewNotesPage(QWidget * parent, const char * name)
: KCModule(parent, name)
{
QVBoxLayout *layout = new QVBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
QHBoxLayout *hLay;
QLabel *label;
// Place of New Notes:
hLay = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
m_newNotesPlace = new QComboBox(this);
label = new QLabel(m_newNotesPlace, i18n("&Place of new notes:"), this);
m_newNotesPlace->insertItem(i18n("On top"));
m_newNotesPlace->insertItem(i18n("On bottom"));
m_newNotesPlace->insertItem(i18n("At current note"));
hLay->addWidget(label);
hLay->addWidget(m_newNotesPlace);
hLay->addStretch();
//layout->addLayout(hLay);
label->hide();
m_newNotesPlace->hide();
connect( m_newNotesPlace, SIGNAL(textChanged(const QString &)), this, SLOT(changed()) );
// New Images Size:
hLay = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
m_imgSizeX = new KIntNumInput(this);
m_imgSizeX->setMinValue(1);
m_imgSizeX->setMaxValue(4096);
m_imgSizeX->setReferencePoint(100);
connect( m_imgSizeX, SIGNAL(valueChanged(int)), this, SLOT(changed()) );
label = new QLabel(m_imgSizeX, i18n("&New images size:"), this);
hLay->addWidget(label);
hLay->addWidget(m_imgSizeX);
m_imgSizeY = new KIntNumInput(this);
m_imgSizeY->setMinValue(1);
m_imgSizeY->setMaxValue(4096);
m_imgSizeY->setReferencePoint(100);
connect( m_imgSizeY, SIGNAL(valueChanged(int)), this, SLOT(changed()) );
label = new QLabel(m_imgSizeY, i18n("&by"), this);
hLay->addWidget(label);
hLay->addWidget(m_imgSizeY);
label = new QLabel(i18n("pixels"), this);
hLay->addWidget(label);
m_pushVisualize = new QPushButton(i18n("&Visualize..."), this);
hLay->addWidget(m_pushVisualize);
hLay->addStretch();
layout->addLayout(hLay);
connect( m_pushVisualize, SIGNAL(clicked()), this, SLOT(visualize()) );
// View File Content:
QVButtonGroup *buttonGroup = new QVButtonGroup(i18n("View Content of Added Files for the Following Types"), this);
m_viewTextFileContent = new QCheckBox( i18n("&Plain text"), buttonGroup );
m_viewHtmlFileContent = new QCheckBox( i18n("&HTML page"), buttonGroup );
m_viewImageFileContent = new QCheckBox( i18n("&Image or animation"), buttonGroup );
m_viewSoundFileContent = new QCheckBox( i18n("&Sound"), buttonGroup );
layout->addWidget(buttonGroup);
connect( m_viewTextFileContent, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
connect( m_viewHtmlFileContent, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
connect( m_viewImageFileContent, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
connect( m_viewSoundFileContent, SIGNAL(stateChanged(int)), this, SLOT(changed()) );
layout->insertStretch(-1);
load();
}
void NewNotesPage::load()
{
m_newNotesPlace->setCurrentItem(Settings::newNotesPlace());
m_imgSizeX->setValue(Settings::defImageX());
m_imgSizeY->setValue(Settings::defImageY());
m_viewTextFileContent->setChecked( Settings::viewTextFileContent() );
m_viewHtmlFileContent->setChecked( Settings::viewHtmlFileContent() );
m_viewImageFileContent->setChecked( Settings::viewImageFileContent() );
m_viewSoundFileContent->setChecked( Settings::viewSoundFileContent() );
}
void NewNotesPage::save()
{
Settings::setNewNotesPlace(m_newNotesPlace->currentItem());
Settings::setDefImageX(m_imgSizeX->value());
Settings::setDefImageY(m_imgSizeY->value());
Settings::setViewTextFileContent( m_viewTextFileContent->isChecked() );
Settings::setViewHtmlFileContent( m_viewHtmlFileContent->isChecked() );
Settings::setViewImageFileContent( m_viewImageFileContent->isChecked() );
Settings::setViewSoundFileContent( m_viewSoundFileContent->isChecked() );
}
void NewNotesPage::defaults()
{
// TODO
}
void NewNotesPage::visualize()
{
ViewSizeDialog size(this, m_imgSizeX->value(), m_imgSizeY->value());
size.exec();
m_imgSizeX->setValue(size.width());
m_imgSizeY->setValue(size.height());
}
/** class NotesAppearancePage: */
NotesAppearancePage::NotesAppearancePage(QWidget * parent, const char * name)
: KCModule(parent, name)
{
QVBoxLayout *layout = new QVBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
QTabWidget *tabs = new QTabWidget(this);
layout->addWidget(tabs);
m_soundLook = new LinkLookEditWidget(this, i18n("Conference audio record"), "sound", tabs);
m_fileLook = new LinkLookEditWidget(this, i18n("Annual report"), "document", tabs);
m_localLinkLook = new LinkLookEditWidget(this, i18n("Home folder"), "folder_home", tabs);
m_networkLinkLook = new LinkLookEditWidget(this, "www.kde.org", KMimeType::iconForURL("http://www.kde.org"), tabs);
m_launcherLook = new LinkLookEditWidget(this, i18n("Launch %1").arg(kapp->aboutData()->programName()), "basket", tabs);
tabs->addTab(m_soundLook, i18n("&Sounds") );
tabs->addTab(m_fileLook, i18n("&Files") );
tabs->addTab(m_localLinkLook, i18n("&Local Links") );
tabs->addTab(m_networkLinkLook, i18n("&Network Links"));
tabs->addTab(m_launcherLook, i18n("Launc&hers") );
load();
}
void NotesAppearancePage::load()
{
m_soundLook->set(LinkLook::soundLook);
m_fileLook->set(LinkLook::fileLook);
m_localLinkLook->set(LinkLook::localLinkLook);
m_networkLinkLook->set(LinkLook::networkLinkLook);
m_launcherLook->set(LinkLook::launcherLook);
}
void NotesAppearancePage::save()
{
m_soundLook->saveChanges();
m_fileLook->saveChanges();
m_localLinkLook->saveChanges();
m_networkLinkLook->saveChanges();
m_launcherLook->saveChanges();
Global::bnpView->linkLookChanged();
}
void NotesAppearancePage::defaults()
{
// TODO
}
/** class ApplicationsPage: */
ApplicationsPage::ApplicationsPage(QWidget * parent, const char * name)
: KCModule(parent, name)
{
/* Applications page */
QVBoxLayout *layout = new QVBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
m_htmlUseProg = new QCheckBox(i18n("Open &text notes with a custom application:"), this);
m_htmlProg = new RunCommandRequester("", i18n("Open text notes with:"), this);
QHBoxLayout *hLayH = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
hLayH->insertSpacing(-1, 20);
hLayH->addWidget(m_htmlProg);
connect(m_htmlUseProg, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_htmlProg->lineEdit(), SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
m_imageUseProg = new QCheckBox(i18n("Open &image notes with a custom application:"), this);
m_imageProg = new RunCommandRequester("", i18n("Open image notes with:"), this);
QHBoxLayout *hLayI = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
hLayI->insertSpacing(-1, 20);
hLayI->addWidget(m_imageProg);
connect(m_imageUseProg, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_imageProg->lineEdit(), SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
m_animationUseProg = new QCheckBox(i18n("Open a&nimation notes with a custom application:"), this);
m_animationProg = new RunCommandRequester("", i18n("Open animation notes with:"), this);
QHBoxLayout *hLayA = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
hLayA->insertSpacing(-1, 20);
hLayA->addWidget(m_animationProg);
connect(m_animationUseProg, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_animationProg->lineEdit(), SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
m_soundUseProg = new QCheckBox(i18n("Open so&und notes with a custom application:"), this);
m_soundProg = new RunCommandRequester("", i18n("Open sound notes with:"), this);
QHBoxLayout *hLayS = new QHBoxLayout(0L, /*margin=*/0, KDialogBase::spacingHint());
hLayS->insertSpacing(-1, 20);
hLayS->addWidget(m_soundProg);
connect(m_soundUseProg, SIGNAL(stateChanged(int)), this, SLOT(changed()));
connect(m_soundProg->lineEdit(), SIGNAL(textChanged(const QString &)), this, SLOT(changed()));
QString whatsthis = i18n(
"<p>If checked, the application defined below will be used when opening that type of note.</p>"
"<p>Otherwise, the application you've configured in Konqueror will be used.</p>");
QWhatsThis::add(m_htmlUseProg, whatsthis);
QWhatsThis::add(m_imageUseProg, whatsthis);
QWhatsThis::add(m_animationUseProg, whatsthis);
QWhatsThis::add(m_soundUseProg, whatsthis);
whatsthis = i18n(
"<p>Define the application to use for opening that type of note instead of the "
"application configured in Konqueror.</p>");
QWhatsThis::add(m_htmlProg, whatsthis);
QWhatsThis::add(m_imageProg, whatsthis);
QWhatsThis::add(m_animationProg, whatsthis);
QWhatsThis::add(m_soundProg, whatsthis);
layout->addWidget(m_htmlUseProg);
layout->addItem(hLayH);
layout->addWidget(m_imageUseProg);
layout->addItem(hLayI);
layout->addWidget(m_animationUseProg);
layout->addItem(hLayA);
layout->addWidget(m_soundUseProg);
layout->addItem(hLayS);
layout->addSpacing(KDialogBase::spacingHint());
QHBoxLayout *hLay = new QHBoxLayout(0L, /*margin=*/0, /*spacing=*/0);
HelpLabel *hl1 = new HelpLabel(
i18n("How to change the application used to open Web links?"),
i18n("<p>When opening Web links, they are opened in different applications, depending on the content of the link "
"(a Web page, an image, a PDF document...), such as if they were files on your computer.</p>"
"<p>Here is how to do if you want every Web addresses to be opened in your Web browser. "
"It is useful if you are not using KDE (if you are using eg. GNOME, XFCE...).</p>"
"<ul>"
"<li>Open the KDE Control Center (if it is not available, try to type \"kcontrol\" in a command line terminal);</li>"
"<li>Go to the \"KDE Components\" and then \"Components Selector\" section;</li>"
"<li>Choose \"Web Browser\", check \"In the following browser:\" and enter the name of your Web browser (like \"firefox\" or \"epiphany\").</li>"
"</ul>"
"<p>Now, when you click <i>any</i> link that start with \"http://...\", it will be opened in your Web browser (eg. Mozilla Firefox or Epiphany or...).</p>"
"<p>For more fine-grained configuration (like opening only Web pages in your Web browser), read the second help link.</p>"),
this);
hLay->addWidget(hl1);
hLay->addStretch();
layout->addLayout(hLay);
hLay = new QHBoxLayout(0L, /*margin=*/0, /*spacing=*/0);
HelpLabel *hl2 = new HelpLabel(
i18n("How to change the applications used to open files and links?"),
i18n("<p>Here is how to set the application to be used for each type of file. "
"This also applies to Web links if you choose not to open them systematically in a Web browser (see the first help link). "
"The default settings should be good enough for you, but this tip is useful if you are using GNOME, XFCE, or another environment than KDE.</p>"
"<p>This is an example of how to open HTML pages in your Web browser (and keep using the other applications for other addresses or files). "
"Repeat these steps for each type of file you want to open in a specific application.</p>"
"<ul>"
"<li>Open the KDE Control Center (if it is not available, try to type \"kcontrol\" in a command line terminal);</li>"
"<li>Go to the \"KDE Components\" and then \"File Associations\" section;</li>"
"<li>In the tree, expand \"text\" and click \"html\";</li>"
"<li>In the applications list, add your Web browser as the first entry;</li>"
"<li>Do the same for the type \"application -> xhtml+xml\".</li>"
"</ul>"),
this);
hLay->addWidget(hl2);
hLay->addStretch();
layout->addLayout(hLay);
connect( m_htmlUseProg, SIGNAL(toggled(bool)), m_htmlProg, SLOT(setEnabled(bool)) );
connect( m_imageUseProg, SIGNAL(toggled(bool)), m_imageProg, SLOT(setEnabled(bool)) );
connect( m_animationUseProg, SIGNAL(toggled(bool)), m_animationProg, SLOT(setEnabled(bool)) );
connect( m_soundUseProg, SIGNAL(toggled(bool)), m_soundProg, SLOT(setEnabled(bool)) );
layout->insertStretch(-1);
load();
}
void ApplicationsPage::load()
{
m_htmlProg->setRunCommand(Settings::htmlProg());
m_htmlUseProg->setChecked(Settings::isHtmlUseProg());
m_htmlProg->setEnabled(Settings::isHtmlUseProg());
m_imageProg->setRunCommand(Settings::imageProg());
m_imageUseProg->setChecked(Settings::isImageUseProg());
m_imageProg->setEnabled(Settings::isImageUseProg());
m_animationProg->setRunCommand(Settings::animationProg());
m_animationUseProg->setChecked(Settings::isAnimationUseProg());
m_animationProg->setEnabled(Settings::isAnimationUseProg());
m_soundProg->setRunCommand(Settings::soundProg());
m_soundUseProg->setChecked(Settings::isSoundUseProg());
m_soundProg->setEnabled(Settings::isSoundUseProg());
}
void ApplicationsPage::save()
{
Settings::setIsHtmlUseProg( m_htmlUseProg->isChecked() );
Settings::setHtmlProg( m_htmlProg->runCommand() );
Settings::setIsImageUseProg( m_imageUseProg->isChecked() );
Settings::setImageProg( m_imageProg->runCommand() );
Settings::setIsAnimationUseProg( m_animationUseProg->isChecked() );
Settings::setAnimationProg( m_animationProg->runCommand() );
Settings::setIsSoundUseProg( m_soundUseProg->isChecked() );
Settings::setSoundProg( m_soundProg->runCommand() );
}
void ApplicationsPage::defaults()
{
// TODO
}
#include "settings.moc"

@ -0,0 +1,392 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef SETTINGS_H
#define SETTINGS_H
#include <qstring.h>
#include <kdialogbase.h>
#include <qcheckbox.h>
#include <qcombobox.h>
#include <qtooltip.h>
#include <qcolor.h>
#include <qpoint.h>
#include <qsize.h>
#include <kcmodule.h>
#include <kaction.h>
#include <kmainwindow.h>
#include <qdatetime.h>
#include "global.h"
#include "bnpview.h"
#include "systemtray.h"
class QGroupBox;
class QButtonGroup;
class KColorCombo;
class KIntNumInput;
class KGlobalAccel;
class QLabel;
class Container;
class SystemTray;
class DebugWindow;
class LinkLook;
class LinkLookEditWidget;
class RunCommandRequester;
class IconSizeCombo;
class GeneralPage : public KCModule
{
Q_OBJECT
public:
GeneralPage(QWidget * parent=0, const char * name=0);
GeneralPage() {};
virtual ~GeneralPage() {}
virtual void load();
virtual void save();
virtual void defaults();
private:
// General
QComboBox *m_treeOnLeft;
QComboBox *m_filterOnTop;
QCheckBox *m_usePassivePopup;
// System Tray Icon
QCheckBox *m_useSystray;
QWidget *m_systray;
QCheckBox *m_showIconInSystray;
QCheckBox *m_hideOnMouseOut;
KIntNumInput *m_timeToHideOnMouseOut;
QCheckBox *m_showOnMouseIn;
KIntNumInput *m_timeToShowOnMouseIn;
};
class BasketsPage : public KCModule
{
Q_OBJECT
public:
BasketsPage(QWidget * parent=0, const char * name=0);
BasketsPage() {};
virtual void load();
virtual void save();
virtual void defaults();
private:
// Appearance
QCheckBox *m_playAnimations;
QCheckBox *m_showNotesToolTip;
QCheckBox *m_bigNotes;
// Behavior
QCheckBox *m_autoBullet;
QCheckBox *m_confirmNoteDeletion;
QCheckBox *m_exportTextTags;
QWidget *m_groupOnInsertionLineWidget;
QCheckBox *m_groupOnInsertionLine;
QComboBox *m_middleAction;
// Protection
QCheckBox *m_useGnuPGAgent;
QCheckBox *m_enableReLockTimeoutMinutes;
KIntNumInput *m_reLockTimeoutMinutes;
};
class NewNotesPage : public KCModule
{
Q_OBJECT
public:
NewNotesPage(QWidget * parent=0, const char * name=0);
NewNotesPage() {};
virtual void load();
virtual void save();
virtual void defaults();
private slots:
void visualize();
private:
// Notes Image Size
KIntNumInput *m_imgSizeX;
KIntNumInput *m_imgSizeY;
QPushButton *m_pushVisualize;
// Note Addition
QComboBox *m_newNotesPlace;
QCheckBox *m_viewTextFileContent;
QCheckBox *m_viewHtmlFileContent;
QCheckBox *m_viewImageFileContent;
QCheckBox *m_viewSoundFileContent;
};
class NotesAppearancePage : public KCModule
{
Q_OBJECT
public:
NotesAppearancePage(QWidget * parent=0, const char * name=0);
NotesAppearancePage() {};
virtual void load();
virtual void save();
virtual void defaults();
private:
// Link Looks
LinkLookEditWidget *m_soundLook;
LinkLookEditWidget *m_fileLook;
LinkLookEditWidget *m_localLinkLook;
LinkLookEditWidget *m_networkLinkLook;
LinkLookEditWidget *m_launcherLook;
};
class ApplicationsPage : public KCModule
{
Q_OBJECT
public:
ApplicationsPage(QWidget * parent=0, const char * name=0);
ApplicationsPage() {};
virtual void load();
virtual void save();
virtual void defaults();
private:
// Applications
QCheckBox *m_htmlUseProg;
QCheckBox *m_imageUseProg;
QCheckBox *m_animationUseProg;
QCheckBox *m_soundUseProg;
RunCommandRequester *m_htmlProg;
RunCommandRequester *m_imageProg;
RunCommandRequester *m_animationProg;
RunCommandRequester *m_soundProg;
};
/** Handle all global variables (to avoid lot of extern declarations)
* @author S<EFBFBD>astien Laot
*/
class Settings // FIXME: Distaptch new config events ?
{
protected:
/** Main window */
static bool s_treeOnLeft;
static bool s_filterOnTop;
static bool s_playAnimations;
static bool s_showNotesToolTip;
static bool s_confirmNoteDeletion;
static bool s_bigNotes;
static bool s_autoBullet;
static bool s_exportTextTags;
static bool s_useGnuPGAgent;
static bool s_usePassivePopup;
static int s_middleAction; // O:Nothing ; 1:Paste ; 2:Text ; 3:Html ; 4:Image ; 5:Link ; 6:Launcher ; 7:Color
static bool s_groupOnInsertionLine;
static bool s_spellCheckTextNotes;
static int s_basketTreeWidth;
static bool s_welcomeBasketsAdded;
static QString s_dataFolder;
static QDate s_lastBackup;
static QPoint s_mainWindowPosition;
static QSize s_mainWindowSize;
static bool s_showEmptyBasketInfo;
static bool s_blinkedFilter;
static bool s_enableReLockTimeout;
static int s_reLockTimeoutMinutes;
/** Note Addition */
static int s_newNotesPlace; // 0:OnTop ; 1:OnBottom ; 2:AtCurrentNote
static int s_viewTextFileContent;
static int s_viewHtmlFileContent;
static int s_viewImageFileContent;
static int s_viewSoundFileContent;
/** System tray Icon */
static bool s_useSystray;
static bool s_showIconInSystray;
static bool s_startDocked;
static bool s_hideOnMouseOut;
static int s_timeToHideOnMouseOut;
static bool s_showOnMouseIn;
static int s_timeToShowOnMouseIn;
/** Programs */
static bool s_htmlUseProg;
static bool s_imageUseProg;
static bool s_animationUseProg;
static bool s_soundUseProg;
static QString s_htmlProg;
static QString s_imageProg;
static QString s_animationProg;
static QString s_soundProg;
/** Insert Note Default Values */
static int s_defImageX;
static int s_defImageY;
static int s_defIconSize;
public: /* And the following methods are just getter / setters */
/** App settings GET */
static inline bool treeOnLeft() { return s_treeOnLeft; }
static inline bool filterOnTop() { return s_filterOnTop; }
static inline bool playAnimations() { return s_playAnimations; }
static inline bool showNotesToolTip() { return s_showNotesToolTip; }
static inline bool confirmNoteDeletion() { return s_confirmNoteDeletion; }
static inline bool bigNotes() { return s_bigNotes; }
static inline bool autoBullet() { return s_autoBullet; }
static inline bool exportTextTags() { return s_exportTextTags; }
static inline bool useGnuPGAgent() { return s_useGnuPGAgent; }
static inline bool blinkedFilter() { return s_blinkedFilter; }
static inline bool enableReLockTimeout() { return s_enableReLockTimeout; }
static inline int reLockTimeoutMinutes() { return s_reLockTimeoutMinutes; }
static inline bool useSystray() { return s_useSystray; }
static inline bool showIconInSystray() { return s_showIconInSystray; }
static inline bool startDocked() { return s_startDocked; }
static inline int middleAction() { return s_middleAction; }
static inline bool groupOnInsertionLine() { return s_groupOnInsertionLine; }
static inline bool spellCheckTextNotes() { return s_spellCheckTextNotes; }
static inline bool hideOnMouseOut() { return s_hideOnMouseOut; }
static inline int timeToHideOnMouseOut() { return s_timeToHideOnMouseOut; }
static inline bool showOnMouseIn() { return s_showOnMouseIn; }
static inline int timeToShowOnMouseIn() { return s_timeToShowOnMouseIn; }
static inline int basketTreeWidth() { return s_basketTreeWidth; }
static inline int dropTimeToShow() { return 7; } // TODO: 700 ; TODO: There is certainly a KGlobalConfig ???
static inline bool usePassivePopup() { return s_usePassivePopup; }
static inline bool welcomeBasketsAdded() { return s_welcomeBasketsAdded; }
static inline QString dataFolder() { return s_dataFolder; }
static inline QDate lastBackup() { return s_lastBackup; }
static inline QPoint mainWindowPosition() { return s_mainWindowPosition; }
static inline QSize mainWindowSize() { return s_mainWindowSize; }
static inline bool showEmptyBasketInfo() { return s_showEmptyBasketInfo; }
/** Programs */
static inline bool isHtmlUseProg() { return s_htmlUseProg; }
static inline bool isImageUseProg() { return s_imageUseProg; }
static inline bool isAnimationUseProg() { return s_animationUseProg; }
static inline bool isSoundUseProg() { return s_soundUseProg; }
static inline QString htmlProg() { return s_htmlProg; }
static inline QString imageProg() { return s_imageProg; }
static inline QString animationProg() { return s_animationProg; }
static inline QString soundProg() { return s_soundProg; }
/** Insert Note Default Values */
static inline int defImageX() { return s_defImageX; }
static inline int defImageY() { return s_defImageY; }
static inline int defIconSize() { return s_defIconSize; }
/** Note Addition */
static inline int newNotesPlace() { return s_newNotesPlace; }
static inline int viewTextFileContent() { return s_viewTextFileContent; }
static inline int viewHtmlFileContent() { return s_viewHtmlFileContent; }
static inline int viewImageFileContent() { return s_viewImageFileContent; }
static inline int viewSoundFileContent() { return s_viewSoundFileContent; }
/** App settings SET */
static void setTreeOnLeft(bool onLeft)
{
s_treeOnLeft = onLeft;
if (Global::bnpView)
Global::bnpView->setTreePlacement(onLeft);
}
static void setFilterOnTop(bool onTop)
{
if (s_filterOnTop != onTop) {
s_filterOnTop = onTop;
if (Global::bnpView)
Global::bnpView->filterPlacementChanged(onTop);
}
}
static void setShowNotesToolTip(bool show)
{
s_showNotesToolTip = show;
}
static void setUseSystray(bool useSystray)
{
if (s_useSystray != useSystray) {
s_useSystray = useSystray;
if (Global::systemTray != 0L) {
if (Settings::useSystray())
Global::systemTray->show();
else {
Global::systemTray->hide();
if(Global::mainWindow()) Global::mainWindow()->show();
}
}
if (Global::bnpView)
Global::bnpView->m_actHideWindow->setEnabled(useSystray);
}
}
static void setShowIconInSystray(bool show)
{
if (s_showIconInSystray != show) {
s_showIconInSystray = show;
if (Global::systemTray != 0L && Settings::useSystray())
Global::systemTray->updateToolTip();
}
}
static inline void setConfirmNoteDeletion(bool confirm) { s_confirmNoteDeletion = confirm; }
static void setBigNotes(bool big);
static void setAutoBullet(bool yes);
static inline void setExportTextTags(bool yes) { s_exportTextTags = yes; }
static inline void setUseGnuPGAgent(bool yes) { s_useGnuPGAgent = yes; }
static inline void setPlayAnimations(bool play) { s_playAnimations = play; }
static inline void setBlinkedFilter(bool blinked) { s_blinkedFilter = blinked; }
static inline void setEnableReLockTimeout(bool yes) { s_enableReLockTimeout = yes; }
static inline void setReLockTimeoutMinutes(int minutes) { s_reLockTimeoutMinutes = minutes; }
static inline void setStartDocked(bool docked) { s_startDocked = docked; }
static inline void setMiddleAction(int action) { s_middleAction = action; }
static inline void setGroupOnInsertionLine(bool yes) { s_groupOnInsertionLine = yes; }
static inline void setSpellCheckTextNotes(bool yes) { s_spellCheckTextNotes = yes; }
static inline void setHideOnMouseOut(bool hide) { s_hideOnMouseOut = hide; }
static inline void setTimeToHideOnMouseOut(int time) { s_timeToHideOnMouseOut = time; }
static inline void setShowOnMouseIn(bool show) { s_showOnMouseIn = show; }
static inline void setTimeToShowOnMouseIn(int time) { s_timeToShowOnMouseIn = time; }
static inline void setBasketTreeWidth(int width) { s_basketTreeWidth = width; }
static inline void setUsePassivePopup(bool enable) { s_usePassivePopup = enable; }
static inline void setWelcomeBasketsAdded(bool added) { s_welcomeBasketsAdded = added; }
static inline void setDataFolder(const QString &folder) { s_dataFolder = folder; }
static inline void setLastBackup(const QDate &date) { s_lastBackup = date; }
static inline void setMainWindowPosition(const QPoint &pos) { s_mainWindowPosition = pos; }
static inline void setMainWindowSize(const QSize &size) { s_mainWindowSize = size; }
static inline void setShowEmptyBasketInfo(bool show) { s_showEmptyBasketInfo = show; }
// Programs :
static inline void setIsHtmlUseProg(bool useProg) { s_htmlUseProg = useProg; }
static inline void setIsImageUseProg(bool useProg) { s_imageUseProg = useProg; }
static inline void setIsAnimationUseProg(bool useProg) { s_animationUseProg = useProg; }
static inline void setIsSoundUseProg(bool useProg) { s_soundUseProg = useProg; }
static inline void setHtmlProg(const QString &prog) { s_htmlProg = prog; }
static inline void setImageProg(const QString &prog) { s_imageProg = prog; }
static inline void setAnimationProg(const QString &prog) { s_animationProg = prog; }
static inline void setSoundProg(const QString &prog) { s_soundProg = prog; }
// Insert Note Default Values :
static inline void setDefImageX(int val) { s_defImageX = val; }
static inline void setDefImageY(int val) { s_defImageY = val; }
static inline void setDefIconSize(int val) { s_defIconSize = val; }
// Note Addition
static inline void setNewNotesPlace(int val) { s_newNotesPlace = val; }
static inline void setViewTextFileContent(bool view) { s_viewTextFileContent = view; }
static inline void setViewHtmlFileContent(bool view) { s_viewHtmlFileContent = view; }
static inline void setViewImageFileContent(bool view) { s_viewImageFileContent = view; }
static inline void setViewSoundFileContent(bool view) { s_viewSoundFileContent = view; }
public:
/* Save and load config */
static void loadConfig();
static void saveConfig();
protected:
static void loadLinkLook(LinkLook *look, const QString &name, const LinkLook &defaultLook);
static void saveLinkLook(LinkLook *look, const QString &name);
};
#endif // SETTINGS_H

@ -0,0 +1,696 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstring.h>
#include <qdir.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <qptrstack.h>
#include <qlayout.h>
#include <qvbuttongroup.h>
#include <qradiobutton.h>
#include <kmessagebox.h>
#include <qtextedit.h>
#include "softwareimporters.h"
#include "basket.h"
#include "basketfactory.h"
#include "notefactory.h"
#include "global.h"
#include "bnpview.h"
#include "xmlwork.h"
#include "tools.h"
/** class TreeImportDialog: */
TreeImportDialog::TreeImportDialog(QWidget *parent)
: KDialogBase(KDialogBase::Swallow, i18n("Import Hierarchy"), KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"ImportHierarchy", /*modal=*/true, /*separator=*/false)
{
QWidget *page = new QWidget(this);
QVBoxLayout *topLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
m_choices = new QVButtonGroup(i18n("How to Import the Notes?"), page);
new QRadioButton(i18n("&Keep original hierarchy (all notes in separate baskets)"), m_choices);
new QRadioButton(i18n("&First level notes in separate baskets"), m_choices);
new QRadioButton(i18n("&All notes in one basket"), m_choices);
m_choices->setButton(0);
topLayout->addWidget(m_choices);
topLayout->addStretch(10);
setMainWidget(page);
}
TreeImportDialog::~TreeImportDialog()
{
}
int TreeImportDialog::choice()
{
return m_choices->selectedId();
}
/** class TextFileImportDialog: */
TextFileImportDialog::TextFileImportDialog(QWidget *parent)
: KDialogBase(KDialogBase::Swallow, i18n("Import Text File"), KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/"ImportTextFile", /*modal=*/true, /*separator=*/false)
{
QWidget *page = new QWidget(this);
QVBoxLayout *topLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
m_choices = new QVButtonGroup(i18n("Format of the Text File"), page);
new QRadioButton(i18n("Notes separated by an &empty line"), m_choices);
new QRadioButton(i18n("One &note per line"), m_choices);
new QRadioButton(i18n("Notes begin with a &dash (-)"), m_choices);
new QRadioButton(i18n("Notes begin with a &star (*)"), m_choices);
m_anotherSeparator = new QRadioButton(i18n("&Use another separator:"), m_choices);
QWidget *indentedTextEdit = new QWidget(m_choices);
QHBoxLayout *hLayout = new QHBoxLayout(indentedTextEdit, /*margin=*/0, spacingHint());
hLayout->addSpacing(20);
m_customSeparator = new QTextEdit(indentedTextEdit);
m_customSeparator->setTextFormat(Qt::PlainText);
hLayout->addWidget(m_customSeparator);
m_choices->insertChild(indentedTextEdit);
new QRadioButton(i18n("&All in one note"), m_choices);
m_choices->setButton(0);
topLayout->addWidget(m_choices);
connect( m_customSeparator, SIGNAL(textChanged()), this, SLOT(customSeparatorChanged()) );
setMainWidget(page);
}
TextFileImportDialog::~TextFileImportDialog()
{
}
QString TextFileImportDialog::separator()
{
switch (m_choices->selectedId()) {
default:
case 0: return "\n\n";
case 1: return "\n";
case 2: return "\n-";
case 3: return "\n*";
case 4: return m_customSeparator->text();
case 5: return "";
}
}
void TextFileImportDialog::customSeparatorChanged()
{
if (!m_anotherSeparator->isOn())
m_anotherSeparator->toggle();
}
/** namespace SoftwareImporters: */
QString SoftwareImporters::fromICS(const QString &ics)
{
QString result = ics;
// Remove escaped '\' characters and append the text to the body
int pos = 0;
while ( (pos = result.find('\\', pos)) != -1 ) {
if ((uint)pos == result.length() - 1) // End of string
break;
if (result[pos+1] == 'n') {
result.replace(pos, 2, '\n');
} else if (result[pos+1] == 'r') {
result.replace(pos, 2, '\r');
} else if (result[pos+1] == 't') {
result.replace(pos, 2, '\t');
} else if (result[pos] == '\\') {
result.remove(pos, 1); // Take care of "\\", "\,", "\;" and other escaped characters I haven't noticed
++pos;
}
}
return result;
}
QString SoftwareImporters::fromTomboy(QString tomboy)
{
// The first line is the note title, and we already have it, so we remove it (yes, that's pretty stupid to duplicate it in the content...):
tomboy = tomboy.mid(tomboy.find("\n")).stripWhiteSpace();
// Font styles and decorations:
tomboy.replace("<bold>", "<b>");
tomboy.replace("</bold>", "</b>");
tomboy.replace("<italic>", "<i>");
tomboy.replace("</italic>", "</i>");
tomboy.replace("<strikethrough>", "<span style='text-decoration: line-through'>");
tomboy.replace("</strikethrough>", "</span>");
// Highlight not supported by QTextEdit:
tomboy.replace("<highlight>", "<span style='color:#ff0080'>");
tomboy.replace("</highlight>", "</span>");
// Font sizes:
tomboy.replace("<size:small>", "<span style='font-size: 7pt'>");
tomboy.replace("</size:small>", "</span>");
tomboy.replace("<size:large>", "<span style='font-size: 16pt'>");
tomboy.replace("</size:large>", "</span>");
tomboy.replace("<size:huge>", "<span style='font-size: 20pt'>");
tomboy.replace("</size:huge>", "</span>");
// Internal links to other notes aren't supported yet by BasKet Note Pads:
tomboy.replace("<link:internal>", "");
tomboy.replace("</link:internal>", "");
// In the Tomboy file, new lines are "\n" and not "<br>":
tomboy.replace("\n", "<br>\n");
// Preserve consecutive spaces:
return "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>" + tomboy + "</body></html>";
}
Note* SoftwareImporters::insertTitledNote(Basket *parent, const QString &title, const QString &content, Qt::TextFormat format/* = Qt::PlainText*/, Note *parentNote/* = 0*/)
{
Note *nGroup = new Note(parent);
Note *nTitle = NoteFactory::createNoteText(title, parent);
nTitle->addState(Tag::stateForId("title"));
Note *nContent;
if (format == Qt::PlainText)
nContent = NoteFactory::createNoteText(content, parent);
else
nContent = NoteFactory::createNoteHtml(content, parent);
if (parentNote == 0)
parentNote = parent->firstNote(); // In the first column!
parent->insertNote(nGroup, parentNote, Note::BottomColumn, QPoint(), /*animate=*/false);
parent->insertNote(nTitle, nGroup, Note::BottomColumn, QPoint(), /*animate=*/false);
parent->insertNote(nContent, nTitle, Note::BottomInsert, QPoint(), /*animate=*/false);
return nGroup;
}
void SoftwareImporters::finishImport(Basket *basket)
{
// Unselect the last inserted group:
basket->unselectAll();
// Focus the FIRST note (the last inserted note is currently focused!):
basket->setFocusedNote(basket->firstNoteShownInStack());
// Relayout every notes at theire new place and simulate a load animation (because already loaded just after the creation).
// Without a relayouting, notes on the bottom would comes from the top (because they were inserted on top) and clutter the animation load:
basket->relayoutNotes(/*animate=*/false);
basket->animateLoad();
basket->save();
}
void SoftwareImporters::importKJots()
{
QString dirPath = locateLocal("appdata","") + "/../kjots/"; // I think the assumption is good
QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
QStringList list = dir.entryList();
if (list.isEmpty())
return;
BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/i18n("From KJots"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
Basket *kjotsBasket = Global::bnpView->currentBasket();
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file
QFile file(dirPath + *it);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::Locale);
QString buf = stream.readLine();
// IT IS A NOTEBOOK FILE, AT THE VERION 0.6.x and older:
if ( !buf.isNull() && buf.left(9) == "\\NewEntry") {
// First create a basket for it:
BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/KURL(file.name()).fileName(), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
QString title, body;
bool haveAnEntry = false;
while (1) {
if (buf.left(9) == "\\NewEntry") {
if (haveAnEntry) // Do not add note the first time
insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body));
title = buf.mid(10, buf.length()); // Problem : basket will be saved
body = ""; // New note will then be created // EACH time a note is imported
haveAnEntry = true;
} else if (buf.left(3) != "\\ID") { // Don't care of the ID
// Remove escaped '\' characters and append the text to the body
int pos = 0;
while ( (pos = buf.find('\\', pos)) != -1 )
if (buf[++pos] == '\\')
buf.remove(pos, 1);
body.append(buf + "\n");
}
buf = stream.readLine();
if (buf.isNull()) // OEF
break;
}
// Add the ending note (there isn't any other "\\NewEntry" to do it):
if (haveAnEntry)
insertTitledNote(basket, title, Tools::stripEndWhiteSpaces(body));
finishImport(basket);
// IT IS A NOTEBOOK XML FILE, AT THE VERION 0.7.0 and later:
} else if ( (*it).endsWith(".book") /*&& !buf.isNull() && (buf.left(2) == "<!" / *<!DOCTYPE...* / || buf.left(2) == "<?" / *<?xml...* /)*/) {
QDomDocument *doc = XMLWork::openFile("KJots", dirPath + *it);
if (doc == 0)
continue;
QString bookTitle = XMLWork::getElementText(doc->documentElement(), "KJotsBook/Title");
// First create a basket for it:
BasketFactory::newBasket(/*icon=*/"kjots", /*name=*/bookTitle, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/kjotsBasket);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
QDomElement docElem = XMLWork::getElement(doc->documentElement(), "KJotsBook");
for ( QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling() ) {
QDomElement e = n.toElement();
if ( (!e.isNull()) && e.tagName() == "KJotsPage" )
insertTitledNote(basket, XMLWork::getElementText(e, "Title"), XMLWork::getElementText(e, "Text"));
}
finishImport(basket);
}
file.close();
}
}
}
void SoftwareImporters::importKNotes()
{
QString dirPath = locateLocal("appdata","") + "/../knotes/"; // I thing the assumption is good
QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
QStringList list = dir.entryList();
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file
if ( ! (*it).endsWith(".ics") ) // Don't process *.ics~ and otehr files
continue;
QFile file(dirPath + *it);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
// First create a basket for it:
BasketFactory::newBasket(/*icon=*/"knotes", /*name=*/i18n("From KNotes"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
bool inVJournal = false;
bool inDescription = false;
bool isRichText = false;
QString title, body;
QString buf;
while (1) {
buf = stream.readLine();
if (buf.isNull()) // OEF
break;
if ( !buf.isNull() && buf == "BEGIN:VJOURNAL") {
inVJournal = true;
} else if (inVJournal && buf.startsWith("SUMMARY:")) {
title = buf.mid(8, buf.length());
} else if (inVJournal && buf.startsWith("DESCRIPTION:")) {
body = buf.mid(12, buf.length());
inDescription = true;
} else if (inDescription && buf.startsWith(" ")) {
body += buf.mid(1, buf.length());
} else if (buf.startsWith("X-KDE-KNotes-RichText:")) {
isRichText = XMLWork::trueOrFalse(buf.mid(22, buf.length() - 22).stripWhiteSpace(), "false");
} else if (buf == "END:VJOURNAL") {
insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? Qt::RichText : Qt::PlainText));
inVJournal = false;
inDescription = false;
isRichText = false;
title = "";
body = "";
} else
inDescription = false;
}
// Bouh : duplicate code
// In case of unvalide ICAL file!
if ( ! body.isEmpty() ) // Add the ending note
insertTitledNote(basket, fromICS(title), fromICS(body), (isRichText ? Qt::RichText : Qt::PlainText));
file.close();
finishImport(basket);
}
}
}
void SoftwareImporters::importStickyNotes()
{
// Sticky Notes file is usually located in ~/.gnome2/stickynotes_applet
// We will search all directories in "~/" that contain "gnome" in the name,
// and will search for "stickynotes_applet" file (that should be XML file with <stickynotes> root.
QDir dir(QDir::home().absPath(), QString::null, QDir::Name | QDir::IgnoreCase,
QDir::Dirs | QDir::NoSymLinks | QDir::Hidden);
QStringList founds;
QStringList list = dir.entryList();
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each folder
if ( (*it).contains("gnome", false) ) {
QString fullPath = QDir::home().absPath() + "/" + (*it) + "/stickynotes_applet";
if (dir.exists(fullPath))
founds += fullPath;
}
}
for ( QStringList::Iterator it = founds.begin(); it != founds.end(); ++it ) { // For each file
QFile file(*it);
QDomDocument *doc = XMLWork::openFile("stickynotes", *it);
if (doc == 0)
continue;
// First create a basket for it:
BasketFactory::newBasket(/*icon=*/"gnome", /*name=*/i18n("From Sticky Notes"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
QDomElement docElem = doc->documentElement();
for ( QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling() ) {
QDomElement e = n.toElement();
if ( (!e.isNull()) && e.tagName() == "note" )
insertTitledNote(basket, e.attribute("title"), e.text());
}
finishImport(basket);
}
}
// TODO: FIXME: Code duplicated from notecontent.cpp but with UTF-8 encoding.
// TODO: FIXME: Later, merge!
QString loadUtf8FileToString(const QString &fileName)
{
QFile file(fileName);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
QString text;
text = stream.read();
file.close();
return text;
} else
return "";
}
void SoftwareImporters::importTomboy()
{
QString dirPath = QDir::home().absPath() + "/.tomboy/"; // I thing the assumption is good
QDir dir(dirPath, QString::null, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
Basket *basket = 0; // Create the basket ONLY if we found at least one note to add!
QStringList list = dir.entryList();
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { // For each file
if ( ! (*it).endsWith(".note") )
continue;
QDomDocument *doc = XMLWork::openFile("note", dirPath + *it);
if (doc == 0)
continue;
if (basket == 0) {
// First create a basket for it:
BasketFactory::newBasket(/*icon=*/"tomboy", /*name=*/i18n("From Tomboy"), /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
basket = Global::bnpView->currentBasket();
basket->load();
}
QDomElement docElem = doc->documentElement();
QString title = XMLWork::getElementText(docElem, "title");
// DOES NOT REALLY WORKS:
//QDomElement contentElement = XMLWork::getElement(docElem, "text/note-content");
//QString content = XMLWork::innerXml(contentElement);
// Isolate "<note-content version="0.1">CONTENT</note-content>"!
QString xml = loadUtf8FileToString(dirPath + *it);
xml = xml.mid(xml.find("<note-content "));
xml = xml.mid(xml.find(">") + 1);
xml = xml.mid(0, xml.find("</note-content>"));
if (!title.isEmpty() && !/*content*/xml.isEmpty())
insertTitledNote(basket, title, fromTomboy(xml/*content*/), Qt::RichText);
}
if (basket)
finishImport(basket);
}
void SoftwareImporters::importTextFile()
{
QString fileName = KFileDialog::getOpenFileName(":ImportTextFile", "*|All files");
if (fileName.isEmpty())
return;
TextFileImportDialog dialog;
if (dialog.exec() == QDialog::Rejected)
return;
QString separator = dialog.separator();
QFile file(fileName);
if (file.open(IO_ReadOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::Locale);
QString content = stream.read();
QStringList list = (separator.isEmpty()
? QStringList(content)
: QStringList::split(separator, content, /*allowEmptyEntries=*/false)
);
// First create a basket for it:
QString title = i18n("From TextFile.txt", "From %1").arg(KURL(fileName).fileName());
BasketFactory::newBasket(/*icon=*/"txt", title, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", /*createIn=*/0);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
// Import every notes:
for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
Note *note = NoteFactory::createNoteFromText((*it).stripWhiteSpace(), basket);
basket->insertNote(note, basket->firstNote(), Note::BottomColumn, QPoint(), /*animate=*/false);
}
// Finish the export:
finishImport(basket);
}
}
/** @author Petri Damsten <petri.damsten@iki.fi>
*/
void SoftwareImporters::importKnowIt()
{
KURL url = KFileDialog::getOpenURL(":ImportKnowIt",
"*.kno|KnowIt files\n*|All files");
if (!url.isEmpty())
{
QFile file(url.path());
QFileInfo info(url.path());
Basket* basket = 0;
QPtrStack<Basket> baskets;
QString text;
int hierarchy = 0;
TreeImportDialog dialog;
if (dialog.exec() == QDialog::Rejected)
return;
hierarchy = dialog.choice();
BasketFactory::newBasket(/*icon=*/"knowit",
/*name=*/info.baseName(),
/*backgroundImage=*/"",
/*backgroundColor=*/QColor(),
/*textColor=*/QColor(),
/*templateName=*/"1column",
/*createIn=*/0);
basket = Global::bnpView->currentBasket();
basket->load();
baskets.push(basket);
if(file.open(IO_ReadOnly))
{
QTextStream stream(&file);
uint level = 0;
QString name;
QString line;
QStringList links;
QStringList descriptions;
stream.setEncoding(QTextStream::UnicodeUTF8);
while(1)
{
line = stream.readLine();
if(line.startsWith("\\NewEntry") ||
line.startsWith("\\CurrentEntry") || stream.atEnd())
{
while(level + 1 < baskets.count())
baskets.pop();
if(level + 1 > baskets.count())
baskets.push(basket);
if(!name.isEmpty())
{
if((level == 0 && hierarchy == 1) ||
(hierarchy == 0))
{
BasketFactory::newBasket(/*icon=*/"knowit",
/*name=*/name,
/*backgroundImage=*/"",
/*backgroundColor=*/QColor(),
/*textColor=*/QColor(),
/*templateName=*/"1column",
/*createIn=*/baskets.top());
basket = Global::bnpView->currentBasket();
basket->load();
}
if(!text.stripWhiteSpace().isEmpty() ||
hierarchy == 2 ||
(hierarchy == 1 && level > 0))
{
insertTitledNote(basket, name, text, Qt::RichText);
}
for(uint j = 0; j < links.count(); ++j)
{
Note* link;
if(descriptions.count() < j+1 || descriptions[j].isEmpty())
link = NoteFactory::createNoteLink(links[j], basket);
else
link = NoteFactory::createNoteLink(links[j],
descriptions[j], basket);
basket->insertCreatedNote(link);
}
finishImport(basket);
}
if(stream.atEnd())
break;
int i = line.find("Entry") + 6;
int n = line.find(' ', i);
level = line.mid(i, n - i).toInt();
name = line.mid(n+1);
text = "";
links.clear();
descriptions.clear();
}
else if(line.startsWith("\\Link"))
{
links.append(line.mid(6));
}
else if(line.startsWith("\\Descr"))
{
while(descriptions.count() < links.count() - 1)
descriptions.append("");
descriptions.append(line.mid(7));
}
else
{
text += line + "\n";
}
}
file.close();
}
}
}
void SoftwareImporters::importTuxCards()
{
QString fileName = KFileDialog::getOpenFileName(":ImportTuxCards", "*|All files");
if (fileName.isEmpty())
return;
TreeImportDialog dialog;
if (dialog.exec() == QDialog::Rejected)
return;
int hierarchy = dialog.choice();
QDomDocument *document = XMLWork::openFile("tuxcards_data_file"/*"InformationCollection"*/, fileName);
if (document == 0) {
KMessageBox::error(0, i18n("Can not import that file. It is either corrupted or not a TuxCards file."), i18n("Bad File Format"));
return;
}
QDomElement collection = document->documentElement();
int remainingHierarchy = (hierarchy == 0 ? 65000 : 3 - hierarchy);
importTuxCardsNode(collection, /*parentBasket=*/0, /*parentNote=*/0, remainingHierarchy);
}
// TODO: <InformationElement isOpen="true" isEncripted="false"
void SoftwareImporters::importTuxCardsNode(const QDomElement &element, Basket *parentBasket, Note *parentNote, int remainingHierarchy)
{
for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
QDomElement e = n.toElement();
if (e.isNull() || e.tagName() != "InformationElement") // Cannot handle that!
continue;
QString icon = e.attribute("iconFileName");
QString name = XMLWork::getElementText(e, "Description");
QString content = XMLWork::getElementText(e, "Information");
bool isRichText = (e.attribute("informationFormat") == "RTF");
bool isEncrypted = (e.attribute("isEncripted") == "true");
if (icon.isEmpty() || icon == "none")
icon = "tuxcards";
Note *nContent;
if (isEncrypted) {
KMessageBox::information(0, i18n("A note is encrypted. The importer does not yet support encrypted notes. Please remove the encryption with TuxCards and re-import the file."), i18n("Encrypted Notes not Supported Yet"));
isRichText = true;
content = i18n("<font color='red'><b>Encrypted note.</b><br>The importer do not support encrypted notes yet. Please remove the encryption with TuxCards and re-import the file.</font>");
}
if (remainingHierarchy > 0) {
BasketFactory::newBasket(icon, name, /*backgroundImage=*/"", /*backgroundColor=*/QColor(), /*textColor=*/QColor(), /*templateName=*/"1column", parentBasket);
Basket *basket = Global::bnpView->currentBasket();
basket->load();
if (isRichText)
nContent = NoteFactory::createNoteHtml(content, basket);
else
nContent = NoteFactory::createNoteText(content, basket);
basket->insertNote(nContent, basket->firstNote(), Note::BottomColumn, QPoint(), /*animate=*/false);
importTuxCardsNode(e, basket, 0, remainingHierarchy - 1);
finishImport(basket);
} else {
Note *nGroup = insertTitledNote(parentBasket, name, content, (isRichText ? Qt::RichText : Qt::PlainText), parentNote);
importTuxCardsNode(e, parentBasket, nGroup, remainingHierarchy - 1);
}
}
}
#include "softwareimporters.moc"

@ -0,0 +1,91 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef SOFTWAREIMPORTERS_H
#define SOFTWAREIMPORTERS_H
#include <qnamespace.h>
#include <kdialogbase.h>
class QString;
class QVButtonGroup;
class QDomElement;
class KTextEdit;
class Basket;
class Note;
/** The dialog to ask how to import hierarchical data.
* @author Sébastien Laoût
*/
class TreeImportDialog : public KDialogBase
{
Q_OBJECT
public:
TreeImportDialog(QWidget *parent = 0);
~TreeImportDialog();
int choice();
private:
QVButtonGroup *m_choices;
};
/** The dialog to ask how to import text files.
* @author Sébastien Laoût
*/
class TextFileImportDialog : public KDialogBase
{
Q_OBJECT
public:
TextFileImportDialog(QWidget *parent = 0);
~TextFileImportDialog();
QString separator();
protected slots:
void customSeparatorChanged();
private:
QVButtonGroup *m_choices;
QRadioButton *m_anotherSeparator;
QTextEdit *m_customSeparator;
};
/** Functions that import data from other softwares.
* @author Sébastien Laoût
*/
namespace SoftwareImporters
{
// Useful methods to design importers:
QString fromICS(const QString &ics);
QString fromTomboy(QString tomboy);
Note* insertTitledNote(Basket *parent, const QString &title, const QString &content, Qt::TextFormat format = Qt::PlainText, Note *parentNote = 0);
void finishImport(Basket *basket);
// The importers in themselves:
void importKNotes();
void importKJots();
void importKnowIt();
void importTuxCards();
void importStickyNotes();
void importTomboy();
void importTextFile();
//
void importTuxCardsNode(const QDomElement &element, Basket *parentBasket, Note *parentNote, int remainingHierarchy);
}
#endif // SOFTWAREIMPORTERS_H

@ -0,0 +1,463 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
/** KSystemTray2 */
// To draw the systray screenshot image:
#include <qdockwindow.h>
#include <qmovie.h>
#include <qvariant.h>
#include "linklabel.h"
#include "note.h"
#include <qdesktopwidget.h>
#include <qmime.h>
#include <qpainter.h>
#include <qpoint.h>
#include <qpixmap.h>
// To know the program name:
#include <kglobal.h>
#include <kinstance.h>
#include <kaboutdata.h>
#include <kiconeffect.h>
// Others:
#include <kmessagebox.h>
#include <kmanagerselection.h>
#include <kdeversion.h>
#include <kapplication.h>
#include <kpopupmenu.h>
#include <kiconloader.h>
#include <kdebug.h>
#include "systemtray.h"
#include "basket.h"
#include "settings.h"
#include "global.h"
#include "tools.h"
KSystemTray2::KSystemTray2(QWidget *parent, const char *name)
: KSystemTray(parent, name)
{
}
KSystemTray2::~KSystemTray2()
{
}
void KSystemTray2::displayCloseMessage(QString fileMenu)
{
/* IDEAS OF IMPROVEMENTS:
* - Use queuedMessageBox() but it need a dontAskAgainName parameter
* and image in QMimeSourceFactory shouldn't be removed.
* - Sometimes the systray icon is covered (a passive popup...)
* Use XComposite extension, if available, to get the kicker pixmap.
* - Perhapse desaturate the area around the proper SysTray icon,
* helping bring it into sharper focus. Or draw the cicle with XOR
* brush.
* - Perhapse add the icon in the text (eg. "... in the
* system tray ([icon])."). Add some clutter to the dialog.
*/
#if KDE_IS_VERSION( 3, 1, 90 )
// Don't do all the computations if they are unneeded:
if ( ! KMessageBox::shouldBeShownContinue("hideOnCloseInfo") )
return;
#endif
// "Default parameter". Here, to avoid a i18n() call and dependancy in the .h
if (fileMenu.isEmpty())
fileMenu = i18n("File");
// Some values we need:
QPoint g = mapToGlobal(pos());
int desktopWidth = kapp->desktop()->width();
int desktopHeight = kapp->desktop()->height();
int tw = width();
int th = height();
// We are triying to make a live screenshot of the systray icon to circle it
// and show it to the user. If no systray is used or if the icon is not visible,
// we should not show that screenshot but only a text!
// 1. Determine if the user use a system tray area or not:
QCString screenstr;
screenstr.setNum(qt_xscreen());
QCString trayatom = "_NET_SYSTEM_TRAY_S" + screenstr;
bool useSystray = (KSelectionWatcher(trayatom).owner() != 0L);
// 2. And then if the icon is visible too (eg. this->show() has been called):
useSystray = useSystray && isVisible();
// 3. Kicker (or another systray manager) can be visible but masked out of
// the screen (ie. on right or on left of it). We check if the icon isn't
// out of screen.
if (useSystray) {
QRect deskRect(0, 0, desktopWidth, desktopHeight);
if ( !deskRect.contains(g.x(), g.y()) ||
!deskRect.contains(g.x() + tw, g.y() + th) )
useSystray = false;
}
// 4. We raise the window containing the systray icon (typically the kicker) to
// have the most chances it is visible during the capture:
/* if (useSystray) {
// We are testing if one of the corners is hidden, and if yes, we would enter
// a time consuming process (raise kicker and wait some time):
// if (kapp->widgetAt(g) != this ||
// kapp->widgetAt(g + QPoint(tw-1, 0)) != this ||
// kapp->widgetAt(g + QPoint(0, th-1)) != this ||
// kapp->widgetAt(g + QPoint(tw-1, th-1)) != this) {
int systrayManagerWinId = topLevelWidget()->winId();
KWin::forceActiveWindow(systrayManagerWinId);
kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
// KWin::activateWindow(systrayManagerWinId);
// kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
// KWin::raiseWindow(systrayManagerWinId);
// kapp->processEvents(); // Because without it the systrayManager is raised only after the messageBox is displayed
sleep(1);
// TODO: Re-verify that at least one corner is now visible
// }
}*/
// KMessageBox::information(this, QString::number(g.x()) + ":" + QString::number(g.y()) + ":" +
// QString::number((int)(kapp->widgetAt(g+QPoint(1,1)))));
QString message = i18n(
"<p>Closing the main window will keep %1 running in the system tray. "
"Use <b>Quit</b> from the <b>Basket</b> menu to quit the application.</p>"
).arg(KGlobal::instance()->aboutData()->programName());
// We are sure the systray icon is visible: ouf!
if (useSystray) {
// Compute size and position of the pixmap to be grabbed:
int w = desktopWidth / 4;
int h = desktopHeight / 9;
int x = g.x() + tw/2 - w/2; // Center the rectange in the systray icon
int y = g.y() + th/2 - h/2;
if (x < 0) x = 0; // Move the rectangle to stay in the desktop limits
if (y < 0) y = 0;
if (x + w > desktopWidth) x = desktopWidth - w;
if (y + h > desktopHeight) y = desktopHeight - h;
// Grab the desktop and draw a circle arround the icon:
QPixmap shot = QPixmap::grabWindow(qt_xrootwin(), x, y, w, h);
QPainter painter(&shot);
const int CIRCLE_MARGINS = 6;
const int CIRCLE_WIDTH = 3;
const int SHADOW_OFFSET = 1;
const int IMAGE_BORDER = 1;
int ax = g.x() - x - CIRCLE_MARGINS - 1;
int ay = g.y() - y - CIRCLE_MARGINS - 1;
painter.setPen( QPen(KApplication::palette().active().dark(), CIRCLE_WIDTH) );
painter.drawArc(ax + SHADOW_OFFSET, ay + SHADOW_OFFSET,
tw + 2*CIRCLE_MARGINS, th + 2*CIRCLE_MARGINS, 0, 16*360);
painter.setPen( QPen(Qt::red/*KApplication::palette().active().highlight()*/, CIRCLE_WIDTH) );
painter.drawArc(ax, ay, tw + 2*CIRCLE_MARGINS, th + 2*CIRCLE_MARGINS, 0, 16*360);
#if 1
// Draw the pixmap over the screenshot in case a window hide the icon:
painter.drawPixmap(g.x() - x, g.y() - y + 1, *pixmap());
#endif
painter.end();
// Then, we add a border arround the image to make it more visible:
QPixmap finalShot(w + 2*IMAGE_BORDER, h + 2*IMAGE_BORDER);
finalShot.fill(KApplication::palette().active().foreground());
painter.begin(&finalShot);
painter.drawPixmap(IMAGE_BORDER, IMAGE_BORDER, shot);
painter.end();
// Associate source to image and show the dialog:
QMimeSourceFactory::defaultFactory()->setPixmap("systray_shot", finalShot);
KMessageBox::information(kapp->activeWindow(),
message + "<p><center><img source=\"systray_shot\"></center></p>",
i18n("Docking in System Tray"), "hideOnCloseInfo");
QMimeSourceFactory::defaultFactory()->setData("systray_shot", 0L);
} else {
KMessageBox::information(kapp->activeWindow(),
message,
i18n("Docking in System Tray"), "hideOnCloseInfo");
}
}
/** SystemTray */
SystemTray::SystemTray(QWidget *parent, const char *name)
: KSystemTray2(parent, name != 0 ? name : "SystemTray"), m_showTimer(0), m_autoShowTimer(0)
{
setAcceptDrops(true);
m_showTimer = new QTimer(this);
connect( m_showTimer, SIGNAL(timeout()), Global::bnpView, SLOT(setActive()) );
m_autoShowTimer = new QTimer(this);
connect( m_autoShowTimer, SIGNAL(timeout()), Global::bnpView, SLOT(setActive()) );
// Create pixmaps for the icon:
m_iconPixmap = loadIcon("basket");
// FIXME: When main window is shown at start, the icon is loaded 1 pixel too high
// and then reloaded instantly after at the right position.
// setPixmap(m_iconPixmap); // Load it the sooner as possible to avoid flicker
QImage lockedIconImage = m_iconPixmap.convertToImage();
QPixmap lockOverlayPixmap = loadIcon("lockoverlay");
QImage lockOverlayImage = lockOverlayPixmap.convertToImage();
KIconEffect::overlay(lockedIconImage, lockOverlayImage);
m_lockedIconPixmap.convertFromImage(lockedIconImage);
updateToolTip(); // Set toolTip AND icon
}
SystemTray::~SystemTray()
{
}
void SystemTray::mousePressEvent(QMouseEvent *event)
{
if (event->button() & Qt::LeftButton) { // Prepare drag
m_pressPos = event->globalPos();
m_canDrag = true;
event->accept();
} else if (event->button() & Qt::MidButton) { // Paste
Global::bnpView->currentBasket()->setInsertPopupMenu();
Global::bnpView->currentBasket()->pasteNote(QClipboard::Selection);
Global::bnpView->currentBasket()->cancelInsertPopupMenu();
if (Settings::usePassivePopup())
Global::bnpView->showPassiveDropped(i18n("Pasted selection to basket <i>%1</i>"));
event->accept();
} else if (event->button() & Qt::RightButton) { // Popup menu
KPopupMenu menu(this);
menu.insertTitle( SmallIcon("basket"), kapp->aboutData()->programName() );
Global::bnpView->actNewBasket->plug(&menu);
Global::bnpView->actNewSubBasket->plug(&menu);
Global::bnpView->actNewSiblingBasket->plug(&menu);
menu.insertSeparator();
Global::bnpView->m_actPaste->plug(&menu);
Global::bnpView->m_actGrabScreenshot->plug(&menu);
Global::bnpView->m_actColorPicker->plug(&menu);
if(!Global::bnpView->isPart())
{
KAction* action;
menu.insertSeparator();
action = Global::bnpView->actionCollection()->action("options_configure_global_keybinding");
if(action)
action->plug(&menu);
action = Global::bnpView->actionCollection()->action("options_configure");
if(action)
action->plug(&menu);
menu.insertSeparator();
// Minimize / restore : since we manage the popup menu by ourself, we should do that work :
action = Global::bnpView->actionCollection()->action("minimizeRestore");
if(action)
{
if (Global::mainWindow()->isVisible())
action->setText(i18n("&Minimize"));
else
action->setText(i18n("&Restore"));
action->plug(&menu);
}
action = Global::bnpView->actionCollection()->action("file_quit");
if(action)
action->plug(&menu);
}
Global::bnpView->currentBasket()->setInsertPopupMenu();
connect( &menu, SIGNAL(aboutToHide()), Global::bnpView->currentBasket(), SLOT(delayedCancelInsertPopupMenu()) );
menu.exec(event->globalPos());
event->accept();
} else
event->ignore();
}
void SystemTray::mouseMoveEvent(QMouseEvent *event)
{
event->ignore();
}
void SystemTray::mouseReleaseEvent(QMouseEvent *event)
{
m_canDrag = false;
if (event->button() == Qt::LeftButton) // Show / hide main window
if ( rect().contains(event->pos()) ) { // Accept only if released in systemTray
toggleActive();
emit showPart();
event->accept();
} else
event->ignore();
}
void SystemTray::dragEnterEvent(QDragEnterEvent *event)
{
m_showTimer->start( Settings::dropTimeToShow() * 100, true );
Global::bnpView->currentBasket()->showFrameInsertTo();
/// m_parentContainer->setStatusBarDrag(); // FIXME: move this line in Basket::showFrameInsertTo() ?
Basket::acceptDropEvent(event);
}
void SystemTray::dragMoveEvent(QDragMoveEvent *event)
{
Basket::acceptDropEvent(event);
}
void SystemTray::dragLeaveEvent(QDragLeaveEvent*)
{
m_showTimer->stop();
m_canDrag = false;
Global::bnpView->currentBasket()->resetInsertTo();
Global::bnpView->updateStatusBarHint();
}
#include <iostream>
void SystemTray::dropEvent(QDropEvent *event)
{
m_showTimer->stop();
Global::bnpView->currentBasket()->blindDrop(event);
/* Basket *basket = Global::bnpView->currentBasket();
if (!basket->isLoaded()) {
Global::bnpView->showPassiveLoading(basket);
basket->load();
}
basket->contentsDropEvent(event);
std::cout << (long) basket->selectedNotes() << std::endl;
if (Settings::usePassivePopup())
Global::bnpView->showPassiveDropped(i18n("Dropped to basket <i>%1</i>"));*/
}
/* This function comes directly from JuK: */
/*
* This function copies the entirety of src into dest, starting in
* dest at x and y. This function exists because I was unable to find
* a function like it in either QImage or kdefx
*/
static bool copyImage(QImage &dest, QImage &src, int x, int y)
{
if(dest.depth() != src.depth())
return false;
if((x + src.width()) >= dest.width())
return false;
if((y + src.height()) >= dest.height())
return false;
// We want to use KIconEffect::overlay to do this, since it handles
// alpha, but the images need to be the same size. We can handle that.
QImage large_src(dest);
// It would perhaps be better to create large_src based on a size, but
// this is the easiest way to make a new image with the same depth, size,
// etc.
large_src.detach();
// However, we do have to specifically ensure that setAlphaBuffer is set
// to false
large_src.setAlphaBuffer(false);
large_src.fill(0); // All transparent pixels
large_src.setAlphaBuffer(true);
int w = src.width();
int h = src.height();
for(int dx = 0; dx < w; dx++)
for(int dy = 0; dy < h; dy++)
large_src.setPixel(dx + x, dy + y, src.pixel(dx, dy));
// Apply effect to image
KIconEffect::overlay(dest, large_src);
return true;
}
void SystemTray::updateToolTip()
{
// return; /////////////////////////////////////////////////////
Basket *basket = Global::bnpView->currentBasket();
if (!basket)
return;
if (basket->icon().isEmpty() || basket->icon() == "basket" || ! Settings::showIconInSystray())
setPixmap(basket->isLocked() ? m_lockedIconPixmap : m_iconPixmap);
else {
// Code that comes from JuK:
QPixmap bgPix = loadIcon("basket");
QPixmap fgPix = SmallIcon(basket->icon());
QImage bgImage = bgPix.convertToImage(); // Probably 22x22
QImage fgImage = fgPix.convertToImage(); // Should be 16x16
QImage lockOverlayImage = loadIcon("lockoverlay").convertToImage();
KIconEffect::semiTransparent(bgImage);
copyImage(bgImage, fgImage, (bgImage.width() - fgImage.width()) / 2,
(bgImage.height() - fgImage.height()) / 2);
if (basket->isLocked())
KIconEffect::overlay(bgImage, lockOverlayImage);
bgPix.convertFromImage(bgImage);
setPixmap(bgPix);
}
//QTimer::singleShot( Container::c_delayTooltipTime, this, SLOT(updateToolTipDelayed()) );
// No need to delay: it's be called when notes are changed:
updateToolTipDelayed();
}
void SystemTray::updateToolTipDelayed()
{
Basket *basket = Global::bnpView->currentBasket();
QString tip = "<p><nobr>" + ( basket->isLocked() ? kapp->makeStdCaption(i18n("%1 (Locked)"))
: kapp->makeStdCaption( "%1") )
.arg(Tools::textToHTMLWithoutP(basket->basketName()));
QToolTip::add(this, tip);
}
void SystemTray::wheelEvent(QWheelEvent *event)
{
if (event->delta() > 0)
Global::bnpView->goToPreviousBasket();
else
Global::bnpView->goToNextBasket();
if (Settings::usePassivePopup())
Global::bnpView->showPassiveContent();
}
void SystemTray::enterEvent(QEvent*)
{
if (Settings::showOnMouseIn())
m_autoShowTimer->start(Settings::timeToShowOnMouseIn() * 100, true );
}
void SystemTray::leaveEvent(QEvent*)
{
m_autoShowTimer->stop();
}
#include "systemtray.moc"

@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef SYSTEMTRAY_H
#define SYSTEMTRAY_H
#include <ksystemtray.h>
class MainWindow;
/** Convenient class to develop the displayCloseMessage() dialog
* hopefuly integrated in KDE 3.4
* @author S<EFBFBD>astien Laot
*/
class KSystemTray2 : public KSystemTray
{
Q_OBJECT
public:
KSystemTray2(QWidget *parent = 0, const char *name = 0);
~KSystemTray2();
/**
* Call this method when the user clicked the close button of the window
* (the [x]) to inform him that the application sit in the system tray
* and willn't be closed (as he is used to).
*
* You usualy call it from reimplemented KMainWindow::queryClose()
*
* @since 3.4
*/
void displayCloseMessage(QString fileMenu = "");
};
/** This class provide a personalized system tray icon.
* @author S<EFBFBD>astien Laot
*/
class SystemTray : public KSystemTray2
{
Q_OBJECT
public:
SystemTray(QWidget *parent = 0, const char *name = 0);
~SystemTray();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dragMoveEvent(QDragMoveEvent* event);
virtual void dragLeaveEvent(QDragLeaveEvent*);
virtual void dropEvent(QDropEvent *event);
void wheelEvent(QWheelEvent *event);
void enterEvent(QEvent*);
void leaveEvent(QEvent*);
public slots:
void updateToolTip();
protected slots:
void updateToolTipDelayed();
signals:
void showPart();
private:
QTimer *m_showTimer;
QTimer *m_autoShowTimer;
bool m_canDrag;
QPoint m_pressPos;
QPixmap m_iconPixmap;
QPixmap m_lockedIconPixmap;
};
#endif // SYSTEMTRAY_H

@ -0,0 +1,934 @@
/***************************************************************************
* Copyright (C) 2005 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kapplication.h>
#include <kstyle.h>
#include <kiconloader.h>
#include <qpainter.h>
#include <qfont.h>
#include <qdom.h>
#include <qdir.h>
#include <kglobalsettings.h>
#include <klocale.h>
#include "tag.h"
#include "xmlwork.h"
#include "global.h"
#include "debugwindow.h"
#include "bnpview.h"
#include "tools.h"
#include "basket.h"
#include <iostream>
/** class State: */
State::State(const QString &id, Tag *tag)
: m_id(id), m_name(), m_emblem(), m_bold(false), m_italic(false), m_underline(false), m_strikeOut(false),
m_textColor(), m_fontName(), m_fontSize(-1), m_backgroundColor(), m_textEquivalent(), m_onAllTextLines(false), m_parentTag(tag)
{
}
State::~State()
{
}
State* State::nextState(bool cycle /*= true*/)
{
if (!parentTag())
return 0;
List states = parentTag()->states();
// The tag contains only one state:
if (states.count() == 1)
return 0;
// Find the next state:
for (List::iterator it = states.begin(); it != states.end(); ++it)
// Found the current state in the list:
if (*it == this) {
// Find the next state:
State *next = *(++it);
if (it == states.end())
return (cycle ? states.first() : 0);
return next;
}
// Should not happens:
return 0;
}
QString State::fullName()
{
if (!parentTag() || parentTag()->states().count() == 1)
return (name().isEmpty() && parentTag() ? parentTag()->name() : name());
return QString(i18n("%1: %2")).arg(parentTag()->name(), name());
}
QFont State::font(QFont base)
{
if (bold())
base.setBold(true);
if (italic())
base.setItalic(true);
if (underline())
base.setUnderline(true);
if (strikeOut())
base.setStrikeOut(true);
if (!fontName().isEmpty())
base.setFamily(fontName());
if (fontSize() > 0)
base.setPointSize(fontSize());
return base;
}
QString State::toCSS(const QString &gradientFolderPath, const QString &gradientFolderName, const QFont &baseFont)
{
QString css;
if (bold())
css += " font-weight: bold;";
if (italic())
css += " font-style: italic;";
if (underline() && strikeOut())
css += " text-decoration: underline line-through;";
else if (underline())
css += " text-decoration: underline;";
else if (strikeOut())
css += " text-decoration: line-through;";
if (textColor().isValid())
css += " color: " + textColor().name() + ";";
if (!fontName().isEmpty()) {
QString fontFamily = Tools::cssFontDefinition(fontName(), /*onlyFontFamily=*/true);
css += " font-family: " + fontFamily + ";";
}
if (fontSize() > 0)
css += " font-size: " + QString::number(fontSize()) + "px;";
if (backgroundColor().isValid()) {
// Get the colors of the gradient and the border:
QColor topBgColor;
QColor bottomBgColor;
Note::getGradientColors(backgroundColor(), &topBgColor, &bottomBgColor);
// Produce the CSS code:
QString gradientFileName = Basket::saveGradientBackground(backgroundColor(), font(baseFont), gradientFolderPath);
css += " background: " + bottomBgColor.name() + " url('" + gradientFolderName + gradientFileName + "') repeat-x;";
css += " border-top: solid " + topBgColor.name() + " 1px;";
css += " border-bottom: solid " + Tools::mixColor(topBgColor, bottomBgColor).name() + " 1px;";
}
if (css.isEmpty())
return "";
else
return " .tag_" + id() + " {" + css + " }\n";
}
void State::merge(const List &states, State *result, int *emblemsCount, bool *haveInvisibleTags, const QColor &backgroundColor)
{
*result = State(); // Reset to default values.
*emblemsCount = 0;
*haveInvisibleTags = false;
for (List::const_iterator it = states.begin(); it != states.end(); ++it) {
State *state = *it;
bool isVisible = false;
// For each propertie, if that properties have a value (is not default) is the current state of the list,
// and if it haven't been set to the result state by a previous state, then it's visible and we assign the propertie to the result state.
if (!state->emblem().isEmpty()) {
++*emblemsCount;
isVisible = true;
}
if (state->bold() && !result->bold()) {
result->setBold(true);
isVisible = true;
}
if (state->italic() && !result->italic()) {
result->setItalic(true);
isVisible = true;
}
if (state->underline() && !result->underline()) {
result->setUnderline(true);
isVisible = true;
}
if (state->strikeOut() && !result->strikeOut()) {
result->setStrikeOut(true);
isVisible = true;
}
if (state->textColor().isValid() && !result->textColor().isValid()) {
result->setTextColor(state->textColor());
isVisible = true;
}
if (!state->fontName().isEmpty() && result->fontName().isEmpty()) {
result->setFontName(state->fontName());
isVisible = true;
}
if (state->fontSize() > 0 && result->fontSize() <= 0) {
result->setFontSize(state->fontSize());
isVisible = true;
}
if (state->backgroundColor().isValid() && !result->backgroundColor().isValid() && state->backgroundColor() != backgroundColor) { // vv
result->setBackgroundColor(state->backgroundColor()); // This is particular: if the note background color is the same as the basket one, don't use that.
isVisible = true;
}
// If it's not visible, well, at least one tag is not visible: the note will display "..." at the tags arrow place to show that:
if (!isVisible)
*haveInvisibleTags = true;
}
}
void State::copyTo(State *other)
{
other->m_id = m_id;
other->m_name = m_name;
other->m_emblem = m_emblem;
other->m_bold = m_bold;
other->m_italic = m_italic;
other->m_underline = m_underline;
other->m_strikeOut = m_strikeOut;
other->m_textColor = m_textColor;
other->m_fontName = m_fontName;
other->m_fontSize = m_fontSize;
other->m_backgroundColor = m_backgroundColor;
other->m_textEquivalent = m_textEquivalent;
other->m_onAllTextLines = m_onAllTextLines; // TODO
//TODO: other->m_parentTag;
}
/** class Tag: */
Tag::List Tag::all = Tag::List();
long Tag::nextStateUid = 1;
long Tag::getNextStateUid()
{
return nextStateUid++; // Return the next Uid and THEN increment the Uid
}
Tag::Tag()
{
static int tagNumber = 0;
++tagNumber;
QString sAction = "tag_shortcut_number_" + QString::number(tagNumber);
m_action = new KAction("FAKE TEXT", "FAKE ICON", KShortcut(), Global::bnpView, SLOT(activatedTagShortcut()), Global::bnpView->actionCollection(), sAction);
m_action->setShortcutConfigurable(false); // We do it in the tag properties dialog
m_inheritedBySiblings = false;
}
Tag::~Tag()
{
delete m_action;
}
void Tag::setName(const QString &name)
{
m_name = name;
m_action->setText("TAG SHORTCUT: " + name); // TODO: i18n (for debug purpose only by now).
}
State* Tag::stateForId(const QString &id)
{
for (List::iterator it = all.begin(); it != all.end(); ++it)
for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2)
if ((*it2)->id() == id)
return *it2;
return 0;
}
Tag* Tag::tagForKAction(KAction *action)
{
for (List::iterator it = all.begin(); it != all.end(); ++it)
if ((*it)->m_action == action)
return *it;
return 0;
}
QMap<QString, QString> Tag::loadTags(const QString &path/* = QString()*//*, bool merge = false*/)
{
QMap<QString, QString> mergedStates;
bool merge = !path.isEmpty();
QString fullPath = (merge ? path : Global::savesFolder() + "tags.xml");
QString doctype = "basketTags";
QDir dir;
if (!dir.exists(fullPath)) {
if (merge)
return mergedStates;
DEBUG_WIN << "Tags file does not exist: Creating it...";
createDefaultTagsSet(fullPath);
}
QDomDocument *document = XMLWork::openFile(doctype, fullPath);
if (!document) {
DEBUG_WIN << "<font color=red>FAILED to read the tags file</font>";
return mergedStates;
}
QDomElement docElem = document->documentElement();
if (!merge)
nextStateUid = docElem.attribute("nextStateUid", QString::number(nextStateUid)).toLong();
QDomNode node = docElem.firstChild();
while (!node.isNull()) {
QDomElement element = node.toElement();
if ( (!element.isNull()) && element.tagName() == "tag" ) {
Tag *tag = new Tag();
// Load properties:
QString name = XMLWork::getElementText(element, "name");
QString shortcut = XMLWork::getElementText(element, "shortcut");
QString inherited = XMLWork::getElementText(element, "inherited", "false");
tag->setName(name);
tag->setShortcut(KShortcut(shortcut));
tag->setInheritedBySiblings(XMLWork::trueOrFalse(inherited));
// Load states:
QDomNode subNode = element.firstChild();
while (!subNode.isNull()) {
QDomElement subElement = subNode.toElement();
if ( (!subElement.isNull()) && subElement.tagName() == "state" ) {
State *state = new State(subElement.attribute("id"), tag);
state->setName( XMLWork::getElementText(subElement, "name") );
state->setEmblem( XMLWork::getElementText(subElement, "emblem") );
QDomElement textElement = XMLWork::getElement(subElement, "text");
state->setBold( XMLWork::trueOrFalse(textElement.attribute("bold", "false")) );
state->setItalic( XMLWork::trueOrFalse(textElement.attribute("italic", "false")) );
state->setUnderline( XMLWork::trueOrFalse(textElement.attribute("underline", "false")) );
state->setStrikeOut( XMLWork::trueOrFalse(textElement.attribute("strikeOut", "false")) );
QString textColor = textElement.attribute("color", "");
state->setTextColor(textColor.isEmpty() ? QColor() : QColor(textColor));
QDomElement fontElement = XMLWork::getElement(subElement, "font");
state->setFontName(fontElement.attribute("name", ""));
QString fontSize = fontElement.attribute("size", "");
state->setFontSize(fontSize.isEmpty() ? -1 : fontSize.toInt());
QString backgroundColor = XMLWork::getElementText(subElement, "backgroundColor", "");
state->setBackgroundColor(backgroundColor.isEmpty() ? QColor() : QColor(backgroundColor));
QDomElement textEquivalentElement = XMLWork::getElement(subElement, "textEquivalent");
state->setTextEquivalent( textEquivalentElement.attribute("string", "") );
state->setOnAllTextLines( XMLWork::trueOrFalse(textEquivalentElement.attribute("onAllTextLines", "false")) );
tag->appendState(state);
}
subNode = subNode.nextSibling();
}
// If the Tag is Valid:
if (tag->countStates() > 0) {
// Rename Things if Needed:
State *firstState = tag->states().first();
if (tag->countStates() == 1 && firstState->name().isEmpty())
firstState->setName(tag->name());
if (tag->name().isEmpty())
tag->setName(firstState->name());
// Add or Merge the Tag:
if (!merge) {
all.append(tag);
} else {
Tag *similarTag = tagSimilarTo(tag);
// Tag does not exists, add it:
if (similarTag == 0) {
// We are merging the new states, so we should choose new and unique (on that computer) ids for those states:
for (State::List::iterator it = tag->states().begin(); it != tag->states().end(); ++it) {
State *state = *it;
QString uid = state->id();
QString newUid = "tag_state_" + QString::number(getNextStateUid());
state->setId(newUid);
mergedStates[uid] = newUid;
}
// TODO: if shortcut is already assigned to a previous note, do not import it, keep the user settings!
all.append(tag);
// Tag already exists, rename to theire ids:
} else {
State::List::iterator it2 = similarTag->states().begin();
for (State::List::iterator it = tag->states().begin(); it != tag->states().end(); ++it, ++it2) {
State *state = *it;
State *similarState = *it2;
QString uid = state->id();
QString newUid = similarState->id();
if (uid != newUid)
mergedStates[uid] = newUid;
}
delete tag; // Already exists, not to be merged. Delete the shortcut and all.
}
}
}
}
node = node.nextSibling();
}
return mergedStates;
}
Tag* Tag::tagSimilarTo(Tag *tagToTest)
{
// Tags are considered similar if they have the same name, the same number of states, in the same order, and the same look.
// Keyboard shortcut, text equivalent and onEveryLines are user settings, and thus not considered during the comparision.
// Default tags (To Do, Important, Idea...) do not take into account the name of the tag and states during the comparision.
// Default tags are equal only if they have the same number of states, in the same order, and the same look.
// This is because default tag names are translated differently in every countries, but they are essentialy the same!
// User tags begins with "tag_state_" followed by a number. Default tags are the other ones.
// Browse all tags:
for (List::iterator it = all.begin(); it != all.end(); ++it) {
Tag *tag = *it;
bool same = true;
bool sameName;
bool defaultTag = true;
// We test only name and look. Shorcut and whenever it is inherited by sibling new notes are user settings only!
sameName = tag->name() == tagToTest->name();
if (tag->countStates() != tagToTest->countStates())
continue; // Tag is different!
// We found a tag with same name, check if every states/look are same too:
State::List::iterator itTest = tagToTest->states().begin();
for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2, ++itTest) {
State *state = *it2;
State *stateToTest = *itTest;
if (state->id().startsWith("tag_state_") || stateToTest->id().startsWith("tag_state_")) { defaultTag = false; }
if (state->name() != stateToTest->name()) { sameName = false; }
if (state->emblem() != stateToTest->emblem()) { same = false; break; }
if (state->bold() != stateToTest->bold()) { same = false; break; }
if (state->italic() != stateToTest->italic()) { same = false; break; }
if (state->underline() != stateToTest->underline()) { same = false; break; }
if (state->strikeOut() != stateToTest->strikeOut()) { same = false; break; }
if (state->textColor() != stateToTest->textColor()) { same = false; break; }
if (state->fontName() != stateToTest->fontName()) { same = false; break; }
if (state->fontSize() != stateToTest->fontSize()) { same = false; break; }
if (state->backgroundColor() != stateToTest->backgroundColor()) { same = false; break; }
// Text equivalent (as well as onAllTextLines) is also a user setting!
}
// We found an existing tag that is "exactly" the same:
if (same && (sameName || defaultTag))
return tag;
}
// Not found:
return 0;
}
void Tag::saveTags()
{
DEBUG_WIN << "Saving tags...";
saveTagsTo(all, Global::savesFolder() + "tags.xml");
}
void Tag::saveTagsTo(QValueList<Tag*> &list, const QString &fullPath)
{
// Create Document:
QDomDocument document(/*doctype=*/"basketTags");
QDomElement root = document.createElement("basketTags");
root.setAttribute("nextStateUid", nextStateUid);
document.appendChild(root);
// Save all tags:
for (List::iterator it = list.begin(); it != list.end(); ++it) {
Tag *tag = *it;
// Create tag node:
QDomElement tagNode = document.createElement("tag");
root.appendChild(tagNode);
// Save tag properties:
XMLWork::addElement( document, tagNode, "name", tag->name() );
XMLWork::addElement( document, tagNode, "shortcut", tag->shortcut().toStringInternal() );
XMLWork::addElement( document, tagNode, "inherited", XMLWork::trueOrFalse(tag->inheritedBySiblings()) );
// Save all states:
for (State::List::iterator it2 = (*it)->states().begin(); it2 != (*it)->states().end(); ++it2) {
State *state = *it2;
// Create state node:
QDomElement stateNode = document.createElement("state");
tagNode.appendChild(stateNode);
// Save state properties:
stateNode.setAttribute("id", state->id());
XMLWork::addElement( document, stateNode, "name", state->name() );
XMLWork::addElement( document, stateNode, "emblem", state->emblem() );
QDomElement textNode = document.createElement("text");
stateNode.appendChild(textNode);
QString textColor = (state->textColor().isValid() ? state->textColor().name() : "");
textNode.setAttribute( "bold", XMLWork::trueOrFalse(state->bold()) );
textNode.setAttribute( "italic", XMLWork::trueOrFalse(state->italic()) );
textNode.setAttribute( "underline", XMLWork::trueOrFalse(state->underline()) );
textNode.setAttribute( "strikeOut", XMLWork::trueOrFalse(state->strikeOut()) );
textNode.setAttribute( "color", textColor );
QDomElement fontNode = document.createElement("font");
stateNode.appendChild(fontNode);
fontNode.setAttribute( "name", state->fontName() );
fontNode.setAttribute( "size", state->fontSize() );
QString backgroundColor = (state->backgroundColor().isValid() ? state->backgroundColor().name() : "");
XMLWork::addElement( document, stateNode, "backgroundColor", backgroundColor );
QDomElement textEquivalentNode = document.createElement("textEquivalent");
stateNode.appendChild(textEquivalentNode);
textEquivalentNode.setAttribute( "string", state->textEquivalent() );
textEquivalentNode.setAttribute( "onAllTextLines", XMLWork::trueOrFalse(state->onAllTextLines()) );
}
}
// Write to Disk:
if (!Basket::safelySaveToFile(fullPath, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString()))
DEBUG_WIN << "<font color=red>FAILED to save tags</font>!";
}
void Tag::copyTo(Tag *other)
{
other->m_name = m_name;
other->m_action->setShortcut(m_action->shortcut());
other->m_inheritedBySiblings = m_inheritedBySiblings;
}
void Tag::createDefaultTagsSet(const QString &fullPath)
{
QString xml = QString(
"<!DOCTYPE basketTags>\n"
"<basketTags>\n"
" <tag>\n"
" <name>%1</name>\n" // "To Do"
" <shortcut>Ctrl+1</shortcut>\n"
" <inherited>true</inherited>\n"
" <state id=\"todo_unchecked\">\n"
" <name>%2</name>\n" // "Unchecked"
" <emblem>tag_checkbox</emblem>\n"
" <text bold=\"false\" italic=\"false\" underline=\"false\" strikeOut=\"false\" color=\"\" />\n"
" <font name=\"\" size=\"\" />\n"
" <backgroundColor></backgroundColor>\n"
" <textEquivalent string=\"[ ]\" onAllTextLines=\"false\" />\n"
" </state>\n"
" <state id=\"todo_done\">\n"
" <name>%3</name>\n" // "Done"
" <emblem>tag_checkbox_checked</emblem>\n"
" <text bold=\"false\" italic=\"false\" underline=\"false\" strikeOut=\"true\" color=\"\" />\n"
" <font name=\"\" size=\"\" />\n"
" <backgroundColor></backgroundColor>\n"
" <textEquivalent string=\"[x]\" onAllTextLines=\"false\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%4</name>\n" // "Progress"
" <shortcut>Ctrl+2</shortcut>\n"
" <inherited>true</inherited>\n"
" <state id=\"progress_000\">\n"
" <name>%5</name>\n" // "0 %"
" <emblem>tag_progress_000</emblem>\n"
" <textEquivalent string=\"[ ]\" />\n"
" </state>\n"
" <state id=\"progress_025\">\n"
" <name>%6</name>\n" // "25 %"
" <emblem>tag_progress_025</emblem>\n"
" <textEquivalent string=\"[= ]\" />\n"
" </state>\n"
" <state id=\"progress_050\">\n"
" <name>%7</name>\n" // "50 %"
" <emblem>tag_progress_050</emblem>\n"
" <textEquivalent string=\"[== ]\" />\n"
" </state>\n"
" <state id=\"progress_075\">\n"
" <name>%8</name>\n" // "75 %"
" <emblem>tag_progress_075</emblem>\n"
" <textEquivalent string=\"[=== ]\" />\n"
" </state>\n"
" <state id=\"progress_100\">\n"
" <name>%9</name>\n" // "100 %"
" <emblem>tag_progress_100</emblem>\n"
" <textEquivalent string=\"[====]\" />\n"
" </state>\n"
" </tag>\n"
"\n")
.arg( i18n("To Do"), i18n("Unchecked"), i18n("Done") ) // %1 %2 %3
.arg( i18n("Progress"), i18n("0 %"), i18n("25 %") ) // %4 %5 %6
.arg( i18n("50 %"), i18n("75 %"), i18n("100 %") ) // %7 %8 %9
+ QString(
" <tag>\n"
" <name>%1</name>\n" // "Priority"
" <shortcut>Ctrl+3</shortcut>\n"
" <inherited>true</inherited>\n"
" <state id=\"priority_low\">\n"
" <name>%2</name>\n" // "Low"
" <emblem>tag_priority_low</emblem>\n"
" <textEquivalent string=\"{1}\" />\n"
" </state>\n"
" <state id=\"priority_medium\">\n"
" <name>%3</name>\n" // "Medium
" <emblem>tag_priority_medium</emblem>\n"
" <textEquivalent string=\"{2}\" />\n"
" </state>\n"
" <state id=\"priority_high\">\n"
" <name>%4</name>\n" // "High"
" <emblem>tag_priority_high</emblem>\n"
" <textEquivalent string=\"{3}\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%5</name>\n" // "Preference"
" <shortcut>Ctrl+4</shortcut>\n"
" <inherited>true</inherited>\n"
" <state id=\"preference_bad\">\n"
" <name>%6</name>\n" // "Bad"
" <emblem>tag_preference_bad</emblem>\n"
" <textEquivalent string=\"(* )\" />\n"
" </state>\n"
" <state id=\"preference_good\">\n"
" <name>%7</name>\n" // "Good"
" <emblem>tag_preference_good</emblem>\n"
" <textEquivalent string=\"(** )\" />\n"
" </state>\n"
" <state id=\"preference_excelent\">\n"
" <name>%8</name>\n" // "Excellent"
" <emblem>tag_preference_excelent</emblem>\n" // "excelent": typo error, but we should keep compatibility with old versions.
" <textEquivalent string=\"(***)\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%9</name>\n" // "Highlight"
" <shortcut>Ctrl+5</shortcut>\n"
" <state id=\"highlight\">\n"
" <backgroundColor>#ffffcc</backgroundColor>\n"
" <textEquivalent string=\"=>\" />\n"
" </state>\n"
" </tag>\n"
"\n")
.arg( i18n("Priority"), i18n("Low"), i18n("Medium") ) // %1 %2 %3
.arg( i18n("High"), i18n("Preference"), i18n("Bad") ) // %4 %5 %6
.arg( i18n("Good"), i18n("Excellent"), i18n("Highlight") ) // %7 %8 %9
+ QString(
" <tag>\n"
" <name>%1</name>\n" // "Important"
" <shortcut>Ctrl+6</shortcut>\n"
" <state id=\"important\">\n"
" <emblem>tag_important</emblem>\n"
" <backgroundColor>#ffcccc</backgroundColor>\n"
" <textEquivalent string=\"!!\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%2</name>\n" // "Very Important"
" <shortcut>Ctrl+7</shortcut>\n"
" <state id=\"very_important\">\n"
" <emblem>tag_important</emblem>\n"
" <text color=\"#ffffff\" />\n"
" <backgroundColor>#ff0000</backgroundColor>\n"
" <textEquivalent string=\"/!\\\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%3</name>\n" // "Information"
" <shortcut>Ctrl+8</shortcut>\n"
" <state id=\"information\">\n"
" <emblem>messagebox_info</emblem>\n"
" <textEquivalent string=\"(i)\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%4</name>\n" // "Idea"
" <shortcut>Ctrl+9</shortcut>\n"
" <state id=\"idea\">\n"
" <emblem>ktip</emblem>\n"
" <textEquivalent string=\"%5\" />\n" // I.
" </state>\n"
" </tag>""\n"
"\n"
" <tag>\n"
" <name>%6</name>\n" // "Title"
" <shortcut>Ctrl+0</shortcut>\n"
" <state id=\"title\">\n"
" <text bold=\"true\" />\n"
" <textEquivalent string=\"##\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <name>%7</name>\n" // "Code"
" <state id=\"code\">\n"
" <font name=\"monospace\" />\n"
" <textEquivalent string=\"|\" onAllTextLines=\"true\" />\n"
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <state id=\"work\">\n"
" <name>%8</name>\n" // "Work"
" <text color=\"#ff8000\" />\n"
" <textEquivalent string=\"%9\" />\n" // W.
" </state>\n"
" </tag>""\n"
"\n")
.arg( i18n("Important"), i18n("Very Important"), i18n("Information") ) // %1 %2 %3
.arg( i18n("Idea"), i18n("The initial of 'Idea'", "I."), i18n("Title") ) // %4 %5 %6
.arg( i18n("Code"), i18n("Work"), i18n("The initial of 'Work'", "W.") ) // %7 %8 %9
+ QString(
" <tag>\n"
" <state id=\"personal\">\n"
" <name>%1</name>\n" // "Personal"
" <text color=\"#008000\" />\n"
" <textEquivalent string=\"%2\" />\n" // P.
" </state>\n"
" </tag>\n"
"\n"
" <tag>\n"
" <state id=\"funny\">\n"
" <name>%3</name>\n" // "Funny"
" <emblem>tag_fun</emblem>\n"
" </state>\n"
" </tag>\n"
"</basketTags>\n"
"")
.arg( i18n("Personal"), i18n("The initial of 'Personal'", "P."), i18n("Funny") ); // %1 %2 %3
// Write to Disk:
QFile file(fullPath);
if (file.open(IO_WriteOnly)) {
QTextStream stream(&file);
stream.setEncoding(QTextStream::UnicodeUTF8);
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
stream << xml;
file.close();
} else
DEBUG_WIN << "<font color=red>FAILED to create the tags file</font>!";
}
#include <kapplication.h>
#include <qrect.h>
#include <qstyle.h>
#include <qcheckbox.h>
#include <qbitmap.h>
#include <kglobalsettings.h>
#include <qimage.h>
#include <qradiobutton.h>
#include <kiconeffect.h>
/** class IndentedMenuItem: */
IndentedMenuItem::IndentedMenuItem(const QString &text, const QString &icon, const QString &shortcut)
: m_text(text), m_icon(icon), m_shortcut(shortcut)
{
}
IndentedMenuItem::~IndentedMenuItem()
{
}
void IndentedMenuItem::paint(QPainter *painter, const QColorGroup &cg, bool active, bool enabled, int x, int y, int w, int h)
{
QPen pen = painter->pen();
QFont font = painter->font();
int iconSize = KIcon::SizeSmall;
int iconMargin = StateMenuItem::iconMargin();
/* When an item is disabled, it often have a 3D sunken look.
* This is done by calling this paint routine two times, with different pen color and offset.
* A disabled item is first painted in the rect (x+1, y+1, w, h) and with pen of cg.light() color,
* It is then drawn a second time in the rect (x, y, w, h).
* But we don't want to draw the icon two times! So, we try to detect if we are in the "etched-text draw" state and then don't draw the icon.
* This doesn't work for every styles but it's already better than nothing (styles when it doesn't work are seldomly used, if used).
*/
bool drawingEtchedText = !enabled && !active && painter->pen().color() != cg.mid()/*== cg.foreground()*/;
if (drawingEtchedText) {
QString styleName = kapp->style().name();
if (styleName == "plastik" || styleName == "lipstik")
painter->setPen(cg.light());
drawingEtchedText = !enabled && !active && painter->pen().color() != cg.foreground();
} else
drawingEtchedText = !enabled && !active && painter->pen().color() == cg.light();
if (!m_icon.isEmpty() && !drawingEtchedText) {
QPixmap icon = kapp->iconLoader()->loadIcon(m_icon, KIcon::Small, iconSize,
(enabled ? (active ? KIcon::ActiveState : KIcon::DefaultState) : KIcon::DisabledState),
/*path_store=*/0L, /*canReturnNull=*/true);
painter->drawPixmap(x, y + (h-iconSize)/2, icon);
}
/* Pen and font are already set to the good ones, so we can directly draw the text.
* BUT, for the half of styles provided with KDE, the pen is not set for the Active state (when hovered by mouse of selected by keyboard).
* So, I set the pen myself.
* But it's certainly a bug in those styles because some other styles eg. just draw a 3D sunken rect when an item is selected
* and keep the background to white, drawing a white text over it is... very bad. But I can't see what can be done.
*/
if (active && enabled)
painter->setPen(KGlobalSettings::highlightedTextColor());
painter->drawText(x + iconSize + iconMargin, y, w - iconSize - iconMargin, h, AlignLeft | AlignVCenter | DontClip | ShowPrefix, m_text/*painter->pen().color().name()*/);
if (!m_shortcut.isEmpty()) {
painter->setPen(pen);
if (active && enabled)
painter->setPen(KGlobalSettings::highlightedTextColor());
painter->setFont(font);
painter->setClipping(false);
painter->drawText(x + 5 + w, y, 3000, h, AlignLeft | AlignVCenter | DontClip | ShowPrefix, m_shortcut);
}
}
QSize IndentedMenuItem::sizeHint()
{
int iconSize = KIcon::SizeSmall;
int iconMargin = StateMenuItem::iconMargin();
QSize textSize = QFontMetrics(KGlobalSettings::menuFont()).size( AlignLeft | AlignVCenter | ShowPrefix | DontClip, m_text );
return QSize(iconSize + iconMargin + textSize.width(), textSize.height());
}
/** class StateMenuItem: */
StateMenuItem::StateMenuItem(State *state, const QString &shortcut, bool withTagName)
: m_state(state), m_shortcut(shortcut)
{
m_name = (withTagName && m_state->parentTag() ? m_state->parentTag()->name() : m_state->name());
}
StateMenuItem::~StateMenuItem()
{
}
void StateMenuItem::paint(QPainter *painter, const QColorGroup &cg, bool active, bool enabled, int x, int y, int w, int h)
{
QPen pen = painter->pen();
QFont font = painter->font();
int iconSize = 16; // We use 16 instead of KIcon::SizeSmall (the size of icons in menus) because tags will always be 16*16 icons
if (!active && m_state->backgroundColor().isValid())
painter->fillRect(x/*-1*/, y/*-1*/, w/*+2*/, h/*+2*/, m_state->backgroundColor());
/* When an item is disabled, it often have a 3D sunken look.
* This is done by calling this paint routine two times, with different pen color and offset.
* A disabled item is first painted in the rect (x+1, y+1, w, h) and with pen of cg.light() color,
* It is then drawn a second time in the rect (x, y, w, h).
* But we don't want to draw the icon two times! So, we try to detect if we are in the "etched-text draw" state and then don't draw the icon.
* This doesn't work for every styles but it's already better than nothing (styles when it doesn't work are seldomly used, if used).
*/
bool drawingEtchedText = !enabled && !active && painter->pen().color() != cg.mid()/*== cg.foreground()*/;
if (drawingEtchedText) {
QString styleName = kapp->style().name();
if (styleName == "plastik" || styleName == "lipstik")
painter->setPen(cg.light());
drawingEtchedText = !enabled && !active && painter->pen().color() != cg.foreground();
} else
drawingEtchedText = !enabled && !active && painter->pen().color() == cg.light();
if (!m_state->emblem().isEmpty() && !drawingEtchedText) {
QPixmap icon = kapp->iconLoader()->loadIcon(m_state->emblem(), KIcon::Small, iconSize,
(enabled ? (active ? KIcon::ActiveState : KIcon::DefaultState) : KIcon::DisabledState),
/*path_store=*/0L, /*canReturnNull=*/true);
painter->drawPixmap(x, y + (h-iconSize)/2, icon);
}
if (enabled && !active && m_state->textColor().isValid())
painter->setPen(m_state->textColor());
/* Pen and font are already set to the good ones, so we can directly draw the text.
* BUT, for the half of styles provided with KDE, the pen is not set for the Active state (when hovered by mouse of selected by keyboard).
* So, I set the pen myself.
* But it's certainly a bug in those styles because some other styles eg. just draw a 3D sunken rect when an item is selected
* and keep the background to white, drawing a white text over it is... very bad. But I can't see what can be done.
*/
if (active && enabled)
painter->setPen(KGlobalSettings::highlightedTextColor());
painter->setFont( m_state->font(painter->font()) );
painter->drawText(x + iconSize + iconMargin(), y, w - iconSize - iconMargin(), h, AlignLeft | AlignVCenter | DontClip | ShowPrefix, m_name);
if (!m_shortcut.isEmpty()) {
painter->setPen(pen);
if (active && enabled)
painter->setPen(KGlobalSettings::highlightedTextColor());
painter->setFont(font);
painter->setClipping(false);
painter->drawText(x + 5 + w, y, 3000, h, AlignLeft | AlignVCenter | DontClip | ShowPrefix, m_shortcut);
}
}
QSize StateMenuItem::sizeHint()
{
int iconSize = 16; // We use 16 instead of KIcon::SizeSmall (the size of icons in menus) because tags will always be 16*16 icons
QFont theFont = m_state->font(KGlobalSettings::menuFont());
QSize textSize = QFontMetrics(theFont).size( AlignLeft | AlignVCenter | ShowPrefix | DontClip, m_name );
return QSize(iconSize + iconMargin() + textSize.width(), textSize.height());
}
QIconSet StateMenuItem::checkBoxIconSet(bool checked, QColorGroup cg)
{
int width = kapp->style().pixelMetric(QStyle::PM_IndicatorWidth, 0);
int height = kapp->style().pixelMetric(QStyle::PM_IndicatorHeight, 0);
QRect rect(0, 0, width, height);
QColor menuBackgroundColor = (dynamic_cast<KStyle*>(&(kapp->style())) == NULL ? cg.background() : cg.background().light(103));
// Enabled, Not hovering
QPixmap pixmap(width, height);
pixmap.fill(menuBackgroundColor); // In case the pixelMetric() haven't returned a bigger rectangle than what drawPrimitive() draws
QPainter painter(&pixmap);
int style = QStyle::Style_Enabled | QStyle::Style_Active | (checked ? QStyle::Style_On : QStyle::Style_Off);
QColor background = cg.color(QColorGroup::Background);
kapp->style().drawPrimitive(QStyle::PE_Indicator, &painter, rect, cg, style);
painter.end();
// Enabled, Hovering
QPixmap pixmapHover(width, height);
pixmapHover.fill(menuBackgroundColor); // In case the pixelMetric() haven't returned a bigger rectangle than what drawPrimitive() draws
painter.begin(&pixmapHover);
style |= QStyle::Style_MouseOver;
cg.setColor(QColorGroup::Background, KGlobalSettings::highlightColor());
kapp->style().drawPrimitive(QStyle::PE_Indicator, &painter, rect, cg, style);
painter.end();
// Disabled
QPixmap pixmapDisabled(width, height);
pixmapDisabled.fill(menuBackgroundColor); // In case the pixelMetric() haven't returned a bigger rectangle than what drawPrimitive() draws
painter.begin(&pixmapDisabled);
style = /*QStyle::Style_Enabled | */QStyle::Style_Active | (checked ? QStyle::Style_On : QStyle::Style_Off);
cg.setColor(QColorGroup::Background, background);
kapp->style().drawPrimitive(QStyle::PE_Indicator, &painter, rect, cg, style);
painter.end();
QIconSet iconSet(pixmap);
iconSet.setPixmap(pixmapHover, QIconSet::Automatic, QIconSet::Active);
iconSet.setPixmap(pixmapDisabled, QIconSet::Automatic, QIconSet::Disabled);
return iconSet;
}
QIconSet StateMenuItem::radioButtonIconSet(bool checked, QColorGroup cg)
{
int width = kapp->style().pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, 0);
int height = kapp->style().pixelMetric(QStyle::PM_ExclusiveIndicatorHeight, 0);
QRect rect(0, 0, width, height);
int style = QStyle::Style_Default | QStyle::Style_Enabled | (checked ? QStyle::Style_On : QStyle::Style_Off);
QPixmap pixmap(width, height);
pixmap.fill(Qt::red);
QPainter painter(&pixmap);
/* We can't use that line of code (like for checkboxes):
* //kapp->style().drawPrimitive(QStyle::PE_ExclusiveIndicator, &painter, rect, cg, style);
* because Plastik (and derived styles) don't care of the QStyle::Style_On flag and will ALWAYS draw an unchecked radiobutton.
* So, we use another method:
*/
QRadioButton rb(0);
rb.setChecked(checked);
kapp->style().drawControl(QStyle::CE_RadioButton, &painter, &rb, rect, cg, style);
painter.end();
/* Some styles like Plastik (and derived ones) have QStyle::PE_ExclusiveIndicator drawing a radiobutton disc, as wanted,
* and leave pixels ouside it untouched, BUT QStyle::PE_ExclusiveIndicatorMask is a fully black square.
* So, we can't apply the mask to make the radiobutton circle transparent outside.
* We're using an hack by filling the pixmap in Qt::red, drawing the radiobutton and then creating an heuristic mask.
* The heuristic mask is created using the 4 edge pixels (that are red) and by making transparent every pixels that are of this color:
*/
pixmap.setMask(pixmap.createHeuristicMask());
QPixmap pixmapHover(width, height);
pixmapHover.fill(Qt::red);
painter.begin(&pixmapHover);
//kapp->style().drawPrimitive(QStyle::PE_ExclusiveIndicator, &painter, rect, cg, style);
style |= QStyle::Style_MouseOver;
cg.setColor(QColorGroup::Background, KGlobalSettings::highlightColor());
kapp->style().drawControl(QStyle::CE_RadioButton, &painter, &rb, rect, cg, style);
painter.end();
pixmapHover.setMask(pixmapHover.createHeuristicMask());
QIconSet iconSet(pixmap);
iconSet.setPixmap(pixmapHover, QIconSet::Automatic, QIconSet::Active);
return iconSet;
}

@ -0,0 +1,198 @@
/***************************************************************************
* Copyright (C) 2005 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef TAG_H
#define TAG_H
#include <qstring.h>
#include <qcolor.h>
#include <qfont.h>
#include <qvaluelist.h>
#include <kaction.h>
#include <kshortcut.h>
class QPainter;
class Tag;
/**
* @author S<EFBFBD>astien Laot
*/
class State
{
public:
/// LIST OF STATES:
typedef QValueList<State*> List;
public:
/// CONSTRUCTOR AND DESTRUCTOR:
State(const QString &id = QString(), Tag *tag = 0);
~State();
/// SET PROPERTIES:
void setId(const QString &id) { m_id = id; }
void setName(const QString &name) { m_name = name; }
void setEmblem(const QString &emblem) { m_emblem = emblem; }
void setBold(bool bold) { m_bold = bold; }
void setItalic(bool italic) { m_italic = italic; }
void setUnderline(bool underline) { m_underline = underline; }
void setStrikeOut(bool strikeOut) { m_strikeOut = strikeOut; }
void setTextColor(const QColor &color) { m_textColor = color; }
void setFontName(const QString &font) { m_fontName = font; }
void setFontSize(int size) { m_fontSize = size; }
void setBackgroundColor(const QColor &color) { m_backgroundColor = color; }
void setTextEquivalent(const QString &text) { m_textEquivalent = text; }
void setOnAllTextLines(bool yes) { m_onAllTextLines = yes; }
void setParentTag(Tag *tag) { m_parentTag = tag; }
/// GET PROPERTIES:
QString id() const { return m_id; }
QString name() const { return m_name; }
QString emblem() const { return m_emblem; }
bool bold() const { return m_bold; }
bool italic() const { return m_italic; }
bool underline() const { return m_underline; }
bool strikeOut() const { return m_strikeOut; }
QColor textColor() const { return m_textColor; }
QString fontName() const { return m_fontName; }
int fontSize() const { return m_fontSize; }
QColor backgroundColor() const { return m_backgroundColor; }
QString textEquivalent() const { return m_textEquivalent; }
bool onAllTextLines() const { return m_onAllTextLines; }
Tag* parentTag() const { return m_parentTag; }
/// HELPING FUNCTIONS:
State *nextState(bool cycle = true);
QString fullName();
QFont font(QFont base);
QString toCSS(const QString &gradientFolderPath, const QString &gradientFolderName, const QFont &baseFont);
static void merge(const List &states, State *result, int *emblemsCount, bool *haveInvisibleTags, const QColor &backgroundColor);
void copyTo(State *other);
private:
/// PROPERTIES:
QString m_id;
QString m_name;
QString m_emblem;
bool m_bold;
bool m_italic;
bool m_underline;
bool m_strikeOut;
QColor m_textColor;
QString m_fontName;
int m_fontSize;
QColor m_backgroundColor;
QString m_textEquivalent;
bool m_onAllTextLines;
Tag *m_parentTag;
};
/** A Tag is a category of Notes.
* A Note can have 0, 1 or more Tags.
* A Tag can have a unique State or several States.
* @author S<EFBFBD>astien Laot
*/
class Tag
{
public:
/// LIST OF ALL TAGS IN THE APPLICATION:
typedef QValueList<Tag*> List;
static Tag::List all;
static State* stateForId(const QString &id);
static Tag* tagForKAction(KAction *action);
static Tag* tagSimilarTo(Tag *tagToTest);
static QMap<QString, QString> loadTags(const QString &path = QString()/*, bool merge = false*/); /// << Load the tags contained in the XML file @p path or those in the application settings if @p path isEmpty(). If @p merge is true and a tag with the id of a tag that should be loaded already exist, the tag will get a new id. Otherwise, the tag will be dismissed.
static void saveTags();
static void saveTagsTo(QValueList<Tag*> &list, const QString &fullPath);
static void createDefaultTagsSet(const QString &file);
static long getNextStateUid();
private:
static long nextStateUid;
public:
/// CONSTRUCTOR AND DESTRUCTOR:
Tag(/*State *firstState, const QString &name, bool inheritedBySiblings*/);
~Tag();
/// SET PROPERTIES:
void setName(const QString &name);
void setShortcut(const KShortcut &shortcut) { m_action->setShortcut(shortcut); }
void setInheritedBySiblings(bool inherited) { m_inheritedBySiblings = inherited; }
void appendState(State *state) { m_states.append(state); state->setParentTag(this); }
void removeState(State *state) { m_states.remove(state); state->setParentTag(0); }
/// GET PROPERTIES:
QString name() const { return m_name; }
KShortcut shortcut() const { return m_action->shortcut(); }
bool inheritedBySiblings() const { return m_inheritedBySiblings; }
State::List& states() const { return (State::List&)m_states; }
int countStates() const { return m_states.count(); }
void copyTo(Tag *other);
private:
/// PROPERTIES:
QString m_name;
KAction *m_action;
bool m_inheritedBySiblings;
State::List m_states;
};
#include <qiconset.h>
#include <qmenudata.h>
#include <qstring.h>
class QPainter;
/** A menu item to indent icon and text (to keep place for a checkbox or a radiobutton on left).
* You should not set any icon when adding this entry to the menu.
* Instead, the constructor take the icon and the item take care to draw it itself.
* Better suited to be used with StateMenuItem (or TagMenuItem).
* @author S<EFBFBD>astien Laot
*/
class IndentedMenuItem : public QCustomMenuItem
{
public:
IndentedMenuItem(const QString &text, const QString &icon = "", const QString &shortcut = "");
~IndentedMenuItem();
void paint(QPainter *painter, const QColorGroup &cg, bool active, bool enabled, int x, int y, int w, int h);
QSize sizeHint();
bool fullSpan() { return true; }
private:
QString m_text;
QString m_icon;
QString m_shortcut;
};
/** A menu item representing a State or a Tag.
* @author S<EFBFBD>astien Laot
*/
class StateMenuItem : public QCustomMenuItem
{
public:
StateMenuItem(State *state, const QString &shortcut, bool withTagName = false);
~StateMenuItem();
void paint(QPainter *painter, const QColorGroup &cg, bool active, bool enabled, int x, int y, int w, int h);
QSize sizeHint();
bool fullSpan() { return true; }
private:
State *m_state;
QString m_name;
QString m_shortcut;
public:
static QIconSet checkBoxIconSet(bool checked, QColorGroup cg);
static QIconSet radioButtonIconSet(bool checked, QColorGroup cg);
static int iconMargin() { return 5; }
};
#endif // TAG_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,185 @@
/***************************************************************************
* Copyright (C) 2005 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef TAGEDIT_H
#define TAGEDIT_H
#include <kdialogbase.h>
#include <kcombobox.h>
#include <qlistview.h>
#include <qvaluelist.h>
class QGroupBox;
class QLineEdit;
class QCheckBox;
class KPushButton;
class KKeyButton;
class KIconButton;
class KFontCombo;
class QLabel;
class KShortcut;
class KColorCombo2;
class FontSizeCombo;
class Tag;
class State;
class StateCopy
{
public:
typedef QValueList<StateCopy*> List;
StateCopy(State *old = 0);
~StateCopy();
State *oldState;
State *newState;
void copyBack();
};
class TagCopy
{
public:
typedef QValueList<TagCopy*> List;
TagCopy(Tag *old = 0);
~TagCopy();
Tag *oldTag;
Tag *newTag;
StateCopy::List stateCopies;
void copyBack();
bool isMultiState();
};
class TagListViewItem : public QListViewItem
{
public:
TagListViewItem(QListView *parent, TagCopy *tagCopy);
TagListViewItem(QListViewItem *parent, TagCopy *tagCopy);
TagListViewItem(QListView *parent, QListViewItem *after, TagCopy *tagCopy);
TagListViewItem(QListViewItem *parent, QListViewItem *after, TagCopy *tagCopy);
TagListViewItem(QListView *parent, StateCopy *stateCopy);
TagListViewItem(QListViewItem *parent, StateCopy *stateCopy);
TagListViewItem(QListView *parent, QListViewItem *after, StateCopy *stateCopy);
TagListViewItem(QListViewItem *parent, QListViewItem *after, StateCopy *stateCopy);
~TagListViewItem();
TagCopy* tagCopy() { return m_tagCopy; }
StateCopy* stateCopy() { return m_stateCopy; }
bool isEmblemObligatory();
TagListViewItem* lastChild();
TagListViewItem* prevSibling();
TagListViewItem* parent() const; // Reimplemented to cast the return value
int width(const QFontMetrics &fontMetrics, const QListView *listView, int column) const;
void setup();
void paintCell(QPainter *painter, const QColorGroup &colorGroup, int column, int width, int align);
private:
TagCopy *m_tagCopy;
StateCopy *m_stateCopy;
};
class TagListView : public QListView
{
Q_OBJECT
public:
TagListView(QWidget *parent = 0, const char *name = 0, WFlags flags = 0);
~TagListView();
void keyPressEvent(QKeyEvent *event);
void contentsMouseDoubleClickEvent(QMouseEvent *event);
void contentsMousePressEvent(QMouseEvent *event);
void contentsMouseReleaseEvent(QMouseEvent *event);
TagListViewItem* currentItem() const; // Reimplemented to cast the return value
TagListViewItem* firstChild() const; // Reimplemented to cast the return value
TagListViewItem* lastItem() const; // Reimplemented to cast the return value
signals:
void deletePressed();
void doubleClickedItem();
};
/**
* @author S<EFBFBD>astien Laot
*/
class TagsEditDialog : public KDialogBase
{
Q_OBJECT
public:
TagsEditDialog(QWidget *parent = 0, State *stateToEdit = 0, bool addNewTag = false);
~TagsEditDialog();
State::List deletedStates() { return m_deletedStates; }
State::List addedStates() { return m_addedStates; }
TagListViewItem* itemForState(State *state);
private slots:
void newTag();
void newState();
void moveUp();
void moveDown();
void deleteTag();
void renameIt();
void capturedShortcut(const KShortcut &shortcut);
void removeShortcut();
void removeEmblem();
void modified();
void currentItemChanged(QListViewItem *item);
void slotCancel();
void slotOk();
void selectUp();
void selectDown();
void selectLeft();
void selectRight();
void resetTreeSizeHint();
private:
void loadBlankState();
void loadStateFrom(State *state);
void loadTagFrom(Tag *tag);
void saveStateTo(State *state);
void saveTagTo(Tag *tag);
void ensureCurrentItemVisible();
TagListView *m_tags;
KPushButton *m_moveUp;
KPushButton *m_moveDown;
KPushButton *m_deleteTag;
QLineEdit *m_tagName;
KKeyButton *m_shortcut;
QPushButton *m_removeShortcut;
QCheckBox *m_inherit;
QGroupBox *m_tagBox;
QGroupBox *m_stateBox;
QLabel *m_stateNameLabel;
QLineEdit *m_stateName;
KIconButton *m_emblem;
QPushButton *m_removeEmblem;
QPushButton *m_bold;
QPushButton *m_underline;
QPushButton *m_italic;
QPushButton *m_strike;
KColorCombo2 *m_textColor;
KFontCombo *m_font;
FontSizeCombo *m_fontSize;
KColorCombo2 *m_backgroundColor;
QLineEdit *m_textEquivalent;
QCheckBox *m_onEveryLines;
TagCopy::List m_tagCopies;
State::List m_deletedStates;
State::List m_addedStates;
bool m_loading;
};
#endif // TAGEDIT_H

@ -0,0 +1,446 @@
/***************************************************************************
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <kdebug.h>
#include <qstring.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qstylesheet.h>
#include <qregexp.h>
#include <qvaluestack.h>
#include <qfileinfo.h>
#include <qdir.h>
#include <qmime.h>
#include <qfont.h>
#include <qfontinfo.h>
#include <qobjectlist.h>
#include "tools.h"
QMemArray<QTime> StopWatch::starts;
QMemArray<double> StopWatch::totals;
QMemArray<uint> StopWatch::counts;
void StopWatch::start(uint id)
{
if (id >= starts.size()) {
totals.resize(id + 1);
counts.resize(id + 1);
for (uint i = starts.size(); i <= id; i++) {
totals[i] = 0;
counts[i] = 0;
}
starts.resize(id + 1);
}
starts[id] = QTime::currentTime();
}
void StopWatch::check(uint id)
{
if (id >= starts.size())
return;
double time = starts[id].msecsTo(QTime::currentTime()) / 1000.0;
totals[id] += time;
counts[id]++;
kdDebug() << k_funcinfo << "Timer_" << id << ": " << time << " s [" << counts[id] << " times, total: " << totals[id] << " s, average: " << totals[id] / counts[id] << " s]" << endl;
}
QString Tools::textToHTML(const QString &text)
{
if (text.isEmpty())
return "<p></p>";
if (/*text.isEmpty() ||*/ text == " " || text == "&nbsp;")
return "<p>&nbsp;</p>";
// convertFromPlainText() replace "\n\n" by "</p>\n<p>": we don't want that
QString htmlString = QStyleSheet::convertFromPlainText(text, QStyleSheetItem::WhiteSpaceNormal);
return htmlString.replace("</p>\n", "<br>\n<br>\n").replace("\n<p>", "\n"); // Don't replace first and last tags
}
QString Tools::textToHTMLWithoutP(const QString &text)
{
// textToHTML(text) return "<p>HTMLizedText</p>". We remove the strating "<p>" and ending </p>"
QString HTMLizedText = textToHTML(text);
return HTMLizedText.mid(3, HTMLizedText.length() - 3 - 4);
}
QString Tools::htmlToParagraph(const QString &html)
{
QString result = html;
bool startedBySpan = false;
// Remove the <html> start tag, all the <head> and the <body> start
// Because <body> can contain style="..." parameter, we transform it to <span>
int pos = result.find("<body");
if (pos != -1) {
result = "<span" + result.mid(pos + 5);
startedBySpan = true;
}
// Remove the ending "</p>\n</body></html>", each tag can be separated by space characters (%s)
// "</p>" can be omitted (eg. if the HTML doesn't contain paragraph but tables), as well as "</body>" (optinal)
pos = result.find(QRegExp("(?:(?:</p>[\\s\\n\\r\\t]*)*</body>[\\s\\n\\r\\t]*)*</html>", false)); // Case unsensitive
if (pos != -1)
result = result.left(pos);
if (startedBySpan)
result += "</span>";
return result.replace("</p>", "<br><br>").replace("<p>", "");
}
// The following is adapted from KStringHanlder::tagURLs
// The adaptation lies in the change to urlEx
// Thanks to Richard Heck
QString Tools::tagURLs(const QString &text)
{
QRegExp urlEx("(www\\.(?!\\.)|([a-zA-z]+)://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%\\$]+[\\d\\w/]");
QString richText(text);
int urlPos = 0;
int urlLen;
while ((urlPos = urlEx.search(richText, urlPos)) >= 0) {
urlLen = urlEx.matchedLength();
QString href = richText.mid(urlPos, urlLen);
// Qt doesn't support (?<=pattern) so we do it here
if ((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()) {
urlPos++;
continue;
}
QString anchor = "<a href=\"" + href + "\">" + href + "</a>";
richText.replace(urlPos, urlLen, anchor);
urlPos += anchor.length();
}
return richText;
}
QString Tools::htmlToText(const QString &html)
{
QString text = htmlToParagraph(html);
text.remove("\n");
text.replace("</h1>", "\n");
text.replace("</h2>", "\n");
text.replace("</h3>", "\n");
text.replace("</h4>", "\n");
text.replace("</h5>", "\n");
text.replace("</h6>", "\n");
text.replace("</li>", "\n");
text.replace("</dt>", "\n");
text.replace("</dd>", "\n");
text.replace("<dd>", " ");
text.replace("</div>","\n");
text.replace("</blockquote>","\n");
text.replace("</caption>","\n");
text.replace("</tr>", "\n");
text.replace("</th>", " ");
text.replace("</td>", " ");
text.replace("<br>", "\n");
text.replace("<br />","\n");
// FIXME: Format <table> tags better, if possible
// TODO: Replace &eacute; and co. by theire equivalent!
// To manage tags:
int pos = 0;
int pos2;
QString tag, tag3;
// To manage lists:
int deep = 0; // The deep of the current line in imbriqued lists
QValueStack<bool> ul; // true if current list is a <ul> one, false if it's an <ol> one
QValueStack<int> lines; // The line number if it is an <ol> list
// We're removing every other tags, or replace them in the case of li:
while ( (pos = text.find("<"), pos) != -1 ) {
// What is the current tag?
tag = text.mid(pos + 1, 2);
tag3 = text.mid(pos + 1, 3);
// Lists work:
if (tag == "ul") {
deep++;
ul.push(true);
lines.push(-1);
} else if (tag == "ol") {
deep++;
ul.push(false);
lines.push(0);
} else if (tag3 == "/ul" || tag3 == "/ol") {
deep--;
ul.pop();
lines.pop();
}
// Where the tag closes?
pos2 = text.find(">");
if (pos2 != -1) {
// Remove the tag:
text.remove(pos, pos2 - pos + 1);
// And replace li with "* ", "x. "... without forbidding to indent that:
if (tag == "li") {
// How many spaces before the line (indentation):
QString spaces = "";
for (int i = 1; i < deep; i++)
spaces += " ";
// The bullet or number of the line:
QString bullet = "* ";
if (ul.top() == false) {
lines.push(lines.pop() + 1);
bullet = QString::number(lines.top()) + ". ";
}
// Insertion:
text.insert(pos, spaces + bullet);
}
if ( (tag3 == "/ul" || tag3 == "/ol") && deep == 0 )
text.insert(pos, "\n"); // Empty line before and after a set of lists
}
++pos;
}
text.replace("&gt;", ">");
text.replace("&lt;", "<");
text.replace("&quot;", "\"");
text.replace("&nbsp;", " ");
text.replace("&amp;", "&"); // CONVERT IN LAST!!
return text;
}
QString Tools::cssFontDefinition(const QFont &font, bool onlyFontFamily)
{
// The font definition:
QString definition = QString(font.italic() ? "italic " : "") +
QString(font.bold() ? "bold " : "") +
QString::number(QFontInfo(font).pixelSize()) + "px ";
// Then, try to match the font name with a standard CSS font family:
QString genericFont = "";
if (definition.contains("serif", false) || definition.contains("roman", false))
genericFont = "serif";
// No "else if" because "sans serif" must be counted as "sans". So, the order between "serif" and "sans" is important
if (definition.contains("sans", false) || definition.contains("arial", false) || definition.contains("helvetica", false))
genericFont = "sans-serif";
if (definition.contains("mono", false) || definition.contains("courier", false) ||
definition.contains("typewriter", false) || definition.contains("console", false) ||
definition.contains("terminal", false) || definition.contains("news", false))
genericFont = "monospace";
// Eventually add the generic font family to the definition:
QString fontDefinition = "\"" + font.family() + "\"";
if (!genericFont.isEmpty())
fontDefinition += ", " + genericFont;
if (onlyFontFamily)
return fontDefinition;
return definition + fontDefinition;
}
QString Tools::stripEndWhiteSpaces(const QString &string)
{
uint length = string.length();
uint i;
for (i = length; i > 0; --i)
if (!string[i-1].isSpace())
break;
if (i == 0)
return "";
else
return string.left(i);
}
bool Tools::isWebColor(const QColor &color)
{
int r = color.red(); // The 216 web colors are those colors whose RGB (Red, Green, Blue)
int g = color.green(); // values are all in the set (0, 51, 102, 153, 204, 255).
int b = color.blue();
return ( ( r == 0 || r == 51 || r == 102 ||
r == 153 || r == 204 || r == 255 ) &&
( g == 0 || g == 51 || g == 102 ||
g == 153 || g == 204 || g == 255 ) &&
( b == 0 || b == 51 || b == 102 ||
b == 153 || b == 204 || b == 255 ) );
}
QColor Tools::mixColor(const QColor &color1, const QColor &color2)
{
QColor mixedColor;
mixedColor.setRgb( (color1.red() + color2.red()) / 2,
(color1.green() + color2.green()) / 2,
(color1.blue() + color2.blue()) / 2 );
return mixedColor;
}
bool Tools::tooDark(const QColor &color)
{
int dontCare, value;
color.getHsv(/*hue:*/dontCare, /*saturation:*/dontCare, value);
return value < 175;
}
// TODO: Use it for all indentPixmap()
QPixmap Tools::normalizePixmap(const QPixmap &pixmap, int width, int height)
{
if (height <= 0)
height = width;
if (pixmap.isNull() || (pixmap.width() == width && pixmap.height() == height))
return pixmap;
return pixmap;
}
QPixmap Tools::indentPixmap(const QPixmap &source, int depth, int deltaX)
{
// Verify if it is possible:
if (depth <= 0 || source.isNull())
return source;
// Compute the number of pixels to indent:
if (deltaX <= 0)
deltaX = 2 * source.width() / 3;
int indent = depth * deltaX;
// Create the images:
QImage resultImage(indent + source.width(), source.height(), 32);
QImage sourceImage = source.convertToImage();
resultImage.setAlphaBuffer(true);
// Clear the indent part (the left part) by making it fully transparent:
uint *p;
for (int row = 0; row < resultImage.height(); ++row) {
for (int column = 0; column < resultImage.width(); ++column) {
p = (uint *)resultImage.scanLine(row) + column;
*p = 0; // qRgba(0, 0, 0, 0)
}
}
// Copy the source image byte per byte to the right part:
uint *q;
for (int row = 0; row < sourceImage.height(); ++row) {
for (int column = 0; column < sourceImage.width(); ++column) {
p = (uint *)resultImage.scanLine(row) + indent + column;
q = (uint *)sourceImage.scanLine(row) + column;
*p = *q;
}
}
// And return the result:
QPixmap result;
result.convertFromImage(resultImage);
return result;
}
#include <iostream>
void Tools::deleteRecursively(const QString &folderOrFile)
{
if (folderOrFile.isEmpty())
return;
QFileInfo fileInfo(folderOrFile);
if (fileInfo.isDir()) {
// Delete the child files:
QDir dir(folderOrFile, QString::null, QDir::Name | QDir::IgnoreCase, QDir::All | QDir::Hidden);
QStringList list = dir.entryList();
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
if ( *it != "." && *it != ".." )
deleteRecursively(folderOrFile + "/" + *it);
// And then delete the folder:
dir.rmdir(folderOrFile);
} else
// Delete the file:
QFile::remove(folderOrFile);
}
QString Tools::fileNameForNewFile(const QString &wantedName, const QString &destFolder)
{
QString fileName = wantedName;
QString fullName = destFolder + fileName;
QString extension = "";
int number = 2;
QDir dir;
// First check if the file do not exists yet (simplier and more often case)
dir = QDir(fullName);
if ( ! dir.exists(fullName) )
return fileName;
// Find the file extension, if it exists : Split fileName in fileName and extension
// Example : fileName == "note5-3.txt" => fileName = "note5-3" and extension = ".txt"
int extIndex = fileName.findRev('.');
if (extIndex != -1 && extIndex != int(fileName.length()-1)) { // Extension found and fileName do not ends with '.' !
extension = fileName.mid(extIndex);
fileName.truncate(extIndex);
} // else fileName = fileName and extension = ""
// Find the file number, if it exists : Split fileName in fileName and number
// Example : fileName == "note5-3" => fileName = "note5" and number = 3
int extNumber = fileName.findRev('-');
if (extNumber != -1 && extNumber != int(fileName.length()-1)) { // Number found and fileName do not ends with '-' !
bool isANumber;
int theNumber = fileName.mid(extNumber + 1).toInt(&isANumber);
if (isANumber) {
number = theNumber;
fileName.truncate(extNumber);
} // else :
} // else fileName = fileName and number = 2 (because if the file already exists, the genereated name is at last the 2nd)
QString finalName;
for (/*int number = 2*/; ; ++number) { // TODO: FIXME: If overflow ???
finalName = fileName + "-" + QString::number(number) + extension;
fullName = destFolder + finalName;
dir = QDir(fullName);
if ( ! dir.exists(fullName) )
break;
}
return finalName;
}
// TODO: Move it from NoteFactory
/*QString NoteFactory::iconForURL(const KURL &url)
{
QString icon = KMimeType::iconForURL(url.url());
if ( url.protocol() == "mailto" )
icon = "message";
return icon;
}*/
bool Tools::isAFileCut(QMimeSource *source)
{
if (source->provides("application/x-kde-cutselection")) {
QByteArray array = source->encodedData("application/x-kde-cutselection");
return !array.isEmpty() && QCString(array.data(), array.size() + 1).at(0) == '1';
} else
return false;
}
void Tools::printChildren(QObject* parent)
{
const QObjectList* objs = parent->children();
QObjectListIt it(*objs);
QObject *obj;
while((obj = it.current())!= 0){
++it;
kdDebug() << k_funcinfo << obj->className() << ": " << obj->name() << endl;
}
}

@ -0,0 +1,95 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef TOOLS_H
#define TOOLS_H
class QString;
class QColor;
class QMimeSource;
class StopWatch
{
public:
static void start(uint id);
static void check(uint id);
private:
static QMemArray<QTime> starts;
static QMemArray<double> totals;
static QMemArray<uint> counts;
};
/** Some useful functions for that application.
* @author Sébastien Laoût
*/
namespace Tools
{
// Text <-> HTML Conversions and Tools:
QString textToHTML(const QString &text);
QString textToHTMLWithoutP(const QString &text);
QString htmlToParagraph(const QString &html);
QString htmlToText(const QString &html);
QString tagURLs(const QString &test);
QString cssFontDefinition(const QFont &font, bool onlyFontFamily = false);
// String Manipulations:
QString stripEndWhiteSpaces(const QString &string);
// Pixmap Manipulations:
/** @Return true if it is a Web color
*/
bool isWebColor(const QColor &color);
/** @Return a color that is 50% of @p color1 and 50% of @p color2.
*/
QColor mixColor(const QColor &color1, const QColor &color2);
/** @Return true if the color is too dark to be darkened one more time.
*/
bool tooDark(const QColor &color);
/** Make sure the @p pixmap is of the size (@p width, @p height) and @return a pixmap of this size.
* If @p height <= 0, then width will be used to make the picture square.
*/
QPixmap normalizePixmap(const QPixmap &pixmap, int width, int height = 0);
/** @Return the pixmap @p source with depth*deltaX transparent pixels added to the left.\n
* If @p deltaX is <= 0, then an indent delta is computed depending on the @p source width.
*/
QPixmap indentPixmap(const QPixmap &source, int depth, int deltaX = 0);
// File and Folder Manipulations:
/** Delete the folder @p folderOrFile recursively (to remove sub-folders and child files too).
*/
void deleteRecursively(const QString &folderOrFile);
/** @Return a new filename that doesn't already exist in @p destFolder.
* If @p wantedName alread exist in @p destFolder, a dash and a number will be added before the extenssion.
* Id there were already such a number in @p wantedName, it is incremented until a free filename is found.
*/
QString fileNameForNewFile(const QString &wantedName, const QString &destFolder);
// Other:
//void iconForURL(const KURL &url);
/** @Return true if the source is from a file cutting in Konqueror.
* @Return false if it was just a copy or if it was a drag.
*/
bool isAFileCut(QMimeSource *source);
// Debug
void printChildren(QObject* parent);
}
#endif // TOOLS_H

@ -0,0 +1,325 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qlayout.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qsizegrip.h>
#include <qpushbutton.h>
#include <qstring.h>
#include <qsizepolicy.h>
#include <kopenwith.h>
#include <klocale.h>
#include <qwhatsthis.h>
#include <kiconview.h>
#include <kiconloader.h>
#include <qdragobject.h>
#include <qfontdatabase.h>
#include "variouswidgets.h"
/** class RunCommandRequester: */
RunCommandRequester::RunCommandRequester(const QString &runCommand, const QString &message, QWidget *parent, const char *name)
: QWidget(parent, name)
{
m_message = message;
QHBoxLayout *layout = new QHBoxLayout(this, /*margin=*/0, KDialogBase::spacingHint());
m_runCommand = new QLineEdit(runCommand, this);
QPushButton *pb = new QPushButton(/*"C&hoose..."*/i18n("..."), this);
pb->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
layout->addWidget(m_runCommand);
layout->addWidget(pb);
connect( pb, SIGNAL(clicked()), this, SLOT(slotSelCommand()) );
}
RunCommandRequester::~RunCommandRequester()
{
}
void RunCommandRequester::slotSelCommand()
{
KOpenWithDlg *dlg = new KOpenWithDlg(KURL::List(), m_message, m_runCommand->text(), this);
dlg->exec();
if ( ! dlg->text().isEmpty() )
m_runCommand->setText(dlg->text());
}
QString RunCommandRequester::runCommand()
{
return m_runCommand->text();
}
void RunCommandRequester::setRunCommand(const QString &runCommand)
{
m_runCommand->setText(runCommand);
}
/** class IconSizeCombo: */
IconSizeCombo::IconSizeCombo(bool rw, QWidget *parent, const char *name)
: QComboBox(rw, parent, name)
{
insertItem(i18n("16 by 16 pixels"));
insertItem(i18n("22 by 22 pixels"));
insertItem(i18n("32 by 32 pixels"));
insertItem(i18n("48 by 48 pixels"));
insertItem(i18n("64 by 64 pixels"));
insertItem(i18n("128 by 128 pixels"));
setCurrentItem(2);
}
IconSizeCombo::~IconSizeCombo()
{
}
int IconSizeCombo::iconSize()
{
switch (currentItem()) {
default:
case 0: return 16;
case 1: return 22;
case 2: return 32;
case 3: return 48;
case 4: return 64;
case 5: return 128;
}
}
void IconSizeCombo::setSize(int size)
{
switch (size) {
default:
case 16: setCurrentItem(0); break;
case 22: setCurrentItem(1); break;
case 32: setCurrentItem(2); break;
case 48: setCurrentItem(3); break;
case 64: setCurrentItem(4); break;
case 128: setCurrentItem(5); break;
}
}
/** class ViewSizeDialog: */
ViewSizeDialog::ViewSizeDialog(QWidget *parent, int w, int h)
: QDialog(parent, "ViewSizeDialog")
{
QLabel *label = new QLabel(i18n(
"Resize the window to select the image size\n"
"and close it or press Escape to accept changes."), this);
label->move(8, 8);
label->setFixedSize( label->sizeHint() );
// setSizeGripEnabled(true) doesn't work (the grip stay at the same place), so we emulate it:
m_sizeGrip = new QSizeGrip(this);
m_sizeGrip->setFixedSize( m_sizeGrip->sizeHint() );
setGeometry(x(), y(), w, h);
}
ViewSizeDialog::~ViewSizeDialog()
{
}
void ViewSizeDialog::resizeEvent(QResizeEvent *)
{
setCaption( i18n("%1 by %2 pixels").arg(QString::number(width())).arg(QString::number(height())) );
m_sizeGrip->move( width() - m_sizeGrip->width(), height() - m_sizeGrip->height() );
}
/** class HelpLabel: */
HelpLabel::HelpLabel(const QString &text, const QString &message, QWidget *parent)
: KURLLabel(parent), m_message(message)
{
setText(text);
connect( this, SIGNAL(leftClickedURL()), this, SLOT(showMessage()) );
}
HelpLabel::~HelpLabel()
{
}
void HelpLabel::showMessage()
{
QWhatsThis::display(m_message, mapToGlobal( QPoint(width() / 2, height()) ));
}
void HelpLabel::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Space)
showMessage();
else
KURLLabel::keyPressEvent(event);
}
/** class IconSizeDialog: */
class UndraggableKIconView : public KIconView
{
public:
UndraggableKIconView(QWidget * parent = 0, const char * name = 0, WFlags f = 0) : KIconView(parent, name, f) {}
QDragObject* dragObject() { return 0; }
};
IconSizeDialog::IconSizeDialog(const QString &caption, const QString &message, const QString &icon, int iconSize, QWidget *parent)
: KDialogBase(KDialogBase::Swallow, caption, KDialogBase::Ok | KDialogBase::Cancel,
KDialogBase::Ok, parent, /*name=*/0, /*modal=*/true, /*separator=*/false)
{
QWidget *page = new QWidget(this);
QVBoxLayout *topLayout = new QVBoxLayout(page, /*margin=*/0, spacingHint());
QLabel *label = new QLabel(message, page);
topLayout->addWidget(label);
KIconView *iconView = new UndraggableKIconView(page);
iconView->setItemsMovable(false);
iconView->setSelectionMode(KIconView::Single);
m_size16 = new KIconViewItem(iconView, 0, i18n("16 by 16 pixels"), DesktopIcon(icon, 16));
m_size22 = new KIconViewItem(iconView, m_size16, i18n("22 by 22 pixels"), DesktopIcon(icon, 22));
m_size32 = new KIconViewItem(iconView, m_size22, i18n("32 by 32 pixels"), DesktopIcon(icon, 32));
m_size48 = new KIconViewItem(iconView, m_size32, i18n("48 by 48 pixels"), DesktopIcon(icon, 48));
m_size64 = new KIconViewItem(iconView, m_size48, i18n("64 by 64 pixels"), DesktopIcon(icon, 64));
m_size128 = new KIconViewItem(iconView, m_size64, i18n("128 by 128 pixels"), DesktopIcon(icon, 128));
iconView->setMinimumWidth(m_size16->width() + m_size22->width() + m_size32->width() + m_size48->width() + m_size64->width() + m_size128->width() +
(6+2) * iconView->spacing() + 20);
iconView->setMinimumHeight(m_size128->height() + 2 * iconView->spacing() + 20);
topLayout->addWidget(iconView);
switch (iconSize) {
case 16: iconView->setSelected(m_size16, true); m_iconSize = 16; break;
case 22: iconView->setSelected(m_size22, true); m_iconSize = 22; break;
default:
case 32: iconView->setSelected(m_size32, true); m_iconSize = 32; break;
case 48: iconView->setSelected(m_size48, true); m_iconSize = 48; break;
case 64: iconView->setSelected(m_size64, true); m_iconSize = 64; break;
case 128: iconView->setSelected(m_size128, true); m_iconSize = 128; break;
}
connect( iconView, SIGNAL(executed(QIconViewItem*)), this, SLOT(choose(QIconViewItem*)) );
connect( iconView, SIGNAL(returnPressed(QIconViewItem*)), this, SLOT(choose(QIconViewItem*)) );
connect( iconView, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) );
setMainWidget(page);
}
IconSizeDialog::~IconSizeDialog()
{
}
void IconSizeDialog::slotSelectionChanged()
{
// Change m_iconSize to the new selected one:
if (m_size16->isSelected()) { m_iconSize = 16; return; }
if (m_size22->isSelected()) { m_iconSize = 22; return; }
if (m_size32->isSelected()) { m_iconSize = 32; return; }
if (m_size48->isSelected()) { m_iconSize = 48; return; }
if (m_size64->isSelected()) { m_iconSize = 64; return; }
if (m_size128->isSelected()) { m_iconSize = 128; return; }
// But if user unselected the item (by eg. right clicking a free space), reselect the last one:
switch (m_iconSize) {
case 16: m_size16->setSelected(true); m_iconSize = 16; break;
case 22: m_size22->setSelected(true); m_iconSize = 22; break;
default:
case 32: m_size32->setSelected(true); m_iconSize = 32; break;
case 48: m_size48->setSelected(true); m_iconSize = 48; break;
case 64: m_size64->setSelected(true); m_iconSize = 64; break;
case 128: m_size128->setSelected(true); m_iconSize = 128; break;
}
}
void IconSizeDialog::choose(QIconViewItem*)
{
actionButton(KDialogBase::Ok)->animateClick();
}
void IconSizeDialog::slotCancel()
{
m_iconSize = -1;
KDialogBase::slotCancel();
}
/** class FontSizeCombo: */
FontSizeCombo::FontSizeCombo(bool rw, bool withDefault, QWidget *parent, const char *name)
: KComboBox(rw, parent, name), m_withDefault(withDefault)
{
if (m_withDefault)
insertItem(i18n("(Default)"));
QFontDatabase fontDB;
QValueList<int> sizes = fontDB.standardSizes();
for (QValueList<int>::Iterator it = sizes.begin(); it != sizes.end(); ++it)
insertItem(QString::number(*it));
// connect( this, SIGNAL(acivated(const QString&)), this, SLOT(textChangedInCombo(const QString&)) );
connect( this, SIGNAL(textChanged(const QString&)), this, SLOT(textChangedInCombo(const QString&)) );
// TODO: 01617 void KFontSizeAction::setFontSize( int size )
}
FontSizeCombo::~FontSizeCombo()
{
}
void FontSizeCombo::textChangedInCombo(const QString &text)
{
bool ok = false;
int size = text.toInt(&ok);
if (ok)
emit sizeChanged(size);
}
void FontSizeCombo::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape)
emit escapePressed();
else if (event->key() == Qt::Key_Return)
emit returnPressed2();
else
KComboBox::keyPressEvent(event);
}
void FontSizeCombo::setFontSize(int size)
{
setCurrentText(QString::number(size));
// TODO: SEE KFontSizeAction::setFontSize( int size ) !!! for a more complete method!
}
int FontSizeCombo::fontSize()
{
bool ok = false;
int size = currentText().toInt(&ok);
if (ok)
return size;
size = text(currentItem()).toInt(&ok);
if (ok)
return size;
return font().pointSize();
}
#include "variouswidgets.moc"

@ -0,0 +1,151 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef VARIOUSWIDGETS_H
#define VARIOUSWIDGETS_H
#include <qwidget.h>
#include <kcombobox.h>
#include <qdialog.h>
#include <kurllabel.h>
#include <qstring.h>
#include <kdialogbase.h>
class QLineEdit;
class KIconViewItem;
class QIconViewItem;
class Basket;
/** A widget to select a command to run,
* with a QLineEdit and a QPushButton.
* @author Sébastien Laoût
*/
class RunCommandRequester : public QWidget
{
Q_OBJECT
public:
RunCommandRequester(const QString &runCommand, const QString &message, QWidget *parent = 0, const char *name = 0);
~RunCommandRequester();
QString runCommand();
void setRunCommand(const QString &runCommand);
QLineEdit *lineEdit() { return m_runCommand; }
private slots:
void slotSelCommand();
private:
QLineEdit *m_runCommand;
QString m_message;
};
/** QComboBox to ask icon size
* @author Sébastien Laoût
*/
class IconSizeCombo : public QComboBox
{
Q_OBJECT
public:
IconSizeCombo(bool rw, QWidget *parent = 0, const char *name = 0);
~IconSizeCombo();
int iconSize();
void setSize(int size);
};
/** A window that the user resize to graphically choose a new image size
* TODO: Create a SizePushButton or even SizeWidget
* @author Sébastien Laoût
*/
class ViewSizeDialog : public QDialog
{
Q_OBJECT
public:
ViewSizeDialog(QWidget *parent, int w, int h);
~ViewSizeDialog();
private:
virtual void resizeEvent(QResizeEvent *);
QWidget *m_sizeGrip;
};
/** A label displaying a link that, once clicked, offer a What's This messageBox to help users.
* @author Sébastien Laoût
*/
class HelpLabel : public KURLLabel
{
Q_OBJECT
public:
HelpLabel(const QString &text, const QString &message, QWidget *parent);
~HelpLabel();
QString message() { return m_message; }
public slots:
void setMessage(const QString &message) { m_message = message; }
void showMessage();
protected:
void keyPressEvent(QKeyEvent *event);
private:
QString m_message;
};
/** A dialog to choose the size of an icon.
* @author Sébastien Laoût
*/
class IconSizeDialog : public KDialogBase
{
Q_OBJECT
public:
IconSizeDialog(const QString &caption, const QString &message, const QString &icon, int iconSize, QWidget *parent);
~IconSizeDialog();
int iconSize() { return m_iconSize; } /// << @return the choosen icon size (16, 32, ...) or -1 if canceled!
protected slots:
void slotCancel();
void slotSelectionChanged();
void choose(QIconViewItem*);
private:
KIconViewItem *m_size16;
KIconViewItem *m_size22;
KIconViewItem *m_size32;
KIconViewItem *m_size48;
KIconViewItem *m_size64;
KIconViewItem *m_size128;
int m_iconSize;
};
/**
* A missing class from KDE (and Qt): a combobox to select a font size!
*/
class FontSizeCombo : public KComboBox
{
Q_OBJECT
public:
FontSizeCombo(bool rw, bool withDefault, QWidget *parent = 0, const char *name = 0);
~FontSizeCombo();
void setFontSize(int size);
int fontSize();
protected:
void keyPressEvent(QKeyEvent *event);
signals:
void sizeChanged(int size);
void escapePressed();
void returnPressed2();
private slots:
void textChangedInCombo(const QString &text);
private:
bool m_withDefault;
};
#endif // VARIOUSWIDGETS_H

@ -0,0 +1,110 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <qstring.h>
#include <qdom.h>
#include <qstringlist.h>
#include <qfile.h>
#include "xmlwork.h"
QDomDocument* XMLWork::openFile(const QString &name, const QString &filePath)
{
QDomDocument *doc = new QDomDocument(name);
QFile file(filePath);
if ( ! file.open(IO_ReadOnly) ) {
// QMessageBox::information(this, "Load an XML file", "Error : un-openable file");
delete doc;
return 0;
}
if ( ! doc->setContent(&file) ) {
// QMessageBox::information(this, "Load an XML file", "Error : malformed content");
file.close();
delete doc;
return 0;
}
file.close();
return doc;
}
QDomElement XMLWork::getElement(const QDomElement &startElement, const QString &elementPath)
{
QStringList elements = QStringList::split("/", elementPath, false);
QDomNode n = startElement.firstChild();
for (unsigned int i = 0; i < elements.count(); ++i) { // For each elements
while ( ! n.isNull() ) { // Browse theire sub elements
QDomElement e = n.toElement(); // and search the good one
if ( (!e.isNull()) && e.tagName() == *elements.at(i) ) { // If found
if ( i + 1 == elements.count() ) // And if it is the asked element
return e; // Return the first corresponding
else { // Or if it is an intermediate element
n = e.firstChild(); // Continue with the next sub element
break;
}
}
n = n.nextSibling();
}
}
return QDomElement(); // Not found !
}
QString XMLWork::getElementText(const QDomElement &startElement, const QString &elementPath, const QString &defaultTxt)
{
QDomElement e = getElement(startElement, elementPath);
if (e.isNull())
return defaultTxt;
else
return e.text();
}
void XMLWork::addElement(QDomDocument &document, QDomElement &parent, const QString &name, const QString &text)
{
QDomElement tag = document.createElement(name);
parent.appendChild(tag);
QDomText content = document.createTextNode(text);
tag.appendChild(content);
}
bool XMLWork::trueOrFalse(const QString &value, bool defaultValue)
{
if ( value == "true" || value == "1" || value == "on" || value == "yes" )
return true;
if ( value == "false" || value == "0" || value == "off" || value == "no" )
return false;
return defaultValue;
}
QString XMLWork::trueOrFalse(bool value)
{
return value ? "true" : "false";
}
QString XMLWork::innerXml(QDomElement &element)
{
QString inner;
for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
if (n.isCharacterData())
inner += n.toCharacterData().data();
else if (n.isElement()) {
QDomElement e = n.toElement();
inner += "<" + e.tagName() + ">" + innerXml(e) + "</" + e.tagName() + ">";
}
return inner;
}

@ -0,0 +1,45 @@
/***************************************************************************
* Copyright (C) 2003 by Sébastien Laoût *
* slaout@linux62.org *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef XMLWORKXMLWORK_H
#define XMLWORKXMLWORK_H
class QString;
class QDomDocument;
class QDomElement;
/** All related functions to manage XML files and trees
* @author Sébastien Laoût
*/
namespace XMLWork
{
// Manage XML files :
QDomDocument* openFile(const QString &name, const QString &filePath);
// Manage XML trees :
QDomElement getElement(const QDomElement &startElement, const QString &elementPath);
QString getElementText(const QDomElement &startElement, const QString &elementPath, const QString &defaultTxt = "");
void addElement(QDomDocument &document, QDomElement &parent, const QString &name, const QString &text);
QString innerXml(QDomElement &element);
// Not directly related to XML :
bool trueOrFalse(const QString &value, bool defaultValue = true);
QString trueOrFalse(bool value);
}
#endif // XMLWORKXMLWORK_H

@ -0,0 +1,10 @@
backgrounds
backgrounds-previews
doc
file-integration
images
kontact_plugin
po
src
tags
welcome

@ -0,0 +1,3 @@
tagsdir = $(kde_datadir)/basket/icons
tags_ICON = AUTO
KDE_ICON = AUTO

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

@ -0,0 +1,10 @@
welcomedir = $(kde_datadir)/basket/welcome
welcome_DATA = \
Welcome_de.baskets \
Welcome_en_US.baskets \
Welcome_fr.baskets \
Welcome_it.baskets \
Welcome_ja.baskets \
Welcome_nn.baskets \
Welcome_pt.baskets \
Welcome_ru.baskets

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save