initial import of kde-plasma-addons (4.14.3)

This commit is contained in:
Ivailo Monev 2015-01-15 17:07:43 +00:00
parent 1efad4c65b
commit 9ffe5327b4
1696 changed files with 190284 additions and 0 deletions

View file

@ -0,0 +1,70 @@
project(kdeplasma-addons)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
find_package(KDE4 REQUIRED)
include (KDE4Defaults)
include(MacroLibrary)
include(MacroOptionalDependPackage)
macro_optional_find_package(KDE4Workspace)
macro_log_feature(KDE4WORKSPACE_FOUND "kdebase workspace" "KDE base workspace libraries" "http://www.kde.org" FALSE "" "Needed for building several Plasma plugins")
macro_optional_find_package(QCA2)
macro_log_feature(QCA2_FOUND "QCA2" "Qt Cryptographic Architecture" "http://delta.affinix.com/qca" FALSE "2.0.0" "Needed for building microblog dataengine")
macro_optional_find_package(KdepimLibs)
macro_log_feature(KDEPIMLIBS_FOUND "kdepimlibs" "KDE PIM libraries" "http://www.kde.org" FALSE "" "Needed for building several Plasma plugins")
find_package(Boost)
set(LIBATTICA_MIN_VERSION "0.1.1")
macro_optional_find_package(LibAttica)
macro_log_feature(LIBATTICA_FOUND "libattica" "Attica Library" "http://websvn.kde.org/trunk/kdesupport/attica/" FALSE "" "Needed for building the Open Collaboration Services plasma dataengine and applets")
macro_optional_find_package(OpenGL)
macro_log_feature(OPENGL_FOUND "OpenGL" "API for developing portable, interactive 2D and 3D graphics applications" "http://mesa3d.sourceforge.net" FALSE "" "STRONGLY RECOMMENDED: The 3D hardware acceleration available through the OpenGL API is used in applications ranging from graphics and modellers to screensavers and video players.")
macro_optional_find_package(Nepomuk)
macro_log_feature(NEPOMUK_FOUND "Nepomuk" "Handles all kinds of metadata on the KDE desktop to provide a semantic desktop" "http://nepomuk.kde.org/" FALSE "" "STRONGLY_RECOMMENDED: Nepomuk is used to provide metadata on objects like files, emails etc. to provide a semantic desktop.")
macro_bool_to_01(NEPOMUK_FOUND HAVE_NEPOMUK)
macro_optional_find_package(QJSON)
macro_log_feature(QJSON_FOUND "QJSon" "Used for various Internet runners, for parsing API responses, and the microblog dataengine" "" FALSE "" "")
macro_optional_find_package(QtOAuth)
macro_log_feature(QTOAUTH_FOUND "QtOAuth" "QtOAuth Library - required to build the Plasma Microblog DataEngine" "https://github.com/ayoy/qoauth" FALSE "" "Needed for building Plasma Microblog DataEngine")
macro_optional_depend_package(Marble "Marble")
if (DEPEND_PACKAGE_Marble)
macro_optional_find_package(Marble)
else (DEPEND_PACKAGE_Marble)
set (MARBLE_FOUND FALSE)
endif (DEPEND_PACKAGE_Marble)
macro_log_feature(MARBLE_FOUND "Marble" "Desktop Globe" "http://marble.kde.org" FALSE "" "RECOMMENDED: Marble is used to provide a desktop globe wallpaper for Plasma.")
macro_optional_find_package(DBusMenuQt)
macro_log_feature(DBUSMENUQT_FOUND "DBusMenuQt" "DBusMenu Qt" "https://launchpad.net/libdbusmenu-qt/" FALSE "" "Needed for Unity support in IconTasks.")
if (NEPOMUK_FOUND)
include_directories( ${SOPRANO_INCLUDE_DIR} ${NEPOMUK_INCLUDE_DIR} )
endif (NEPOMUK_FOUND)
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
include_directories (${KDE4_INCLUDES}
${KDE4WORKSPACE_INCLUDE_DIR}
${KDEPIMLIBS_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libs)
add_subdirectory(libs)
add_subdirectory(applets)
add_subdirectory(dataengines)
add_subdirectory(runners)
add_subdirectory(scriptengines)
add_subdirectory(wallpapers)
add_subdirectory(containments)
add_subdirectory(cmake)
macro_display_feature_log()

346
kdeplasma-addons/COPYING Normal file
View file

@ -0,0 +1,346 @@
NOTE! The GPL below is copyrighted by the Free Software Foundation, but
the instance of code that it refers to (the kde programs) are copyrighted
by the authors who actually wrote it.
---------------------------------------------------------------------------
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) 19yy <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) 19yy 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.

View file

@ -0,0 +1,510 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms
of the ordinary General Public License).
To apply these terms, attach the following notices to the library.
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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the library,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View file

@ -0,0 +1,13 @@
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
## # The following are required to uses Dart and the Cdash dashboard
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "kdeplasma-addons")
set(CTEST_NIGHTLY_START_TIME "20:00:00 CET")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=kdeplasma-addons")
set(CTEST_DROP_SITE_CDASH TRUE)

View file

@ -0,0 +1,7 @@
/** @mainpage Plasma Add-Ons
*
* This module contains all kinds of Plasma add-ons.
*
*/
// DOXYGEN_NAME=Plasma Add-Ons
// DOXYGEN_ENABLE=YES

View file

@ -0,0 +1,99 @@
# this works also for the weatherutils include dir, but should be done properly, Alex
include_directories(${PLASMACLOCK_INCLUDE_DIR})
if(KDE4_PLASMA_OPENGL_FOUND)
message(STATUS "libplasma supports OpenGL applets")
else(KDE4_PLASMA_OPENGL_FOUND)
message(STATUS "libplasma doesn't support OpenGL applets")
endif(KDE4_PLASMA_OPENGL_FOUND)
add_subdirectory(bball)
if(KDE4WORKSPACE_FOUND)
add_subdirectory(binary-clock)
add_subdirectory(fuzzy-clock)
add_subdirectory(weather)
if(NOT WIN32 AND DBUSMENUQT_FOUND)
add_subdirectory(icontasks)
endif(NOT WIN32 AND DBUSMENUQT_FOUND)
endif(KDE4WORKSPACE_FOUND)
add_subdirectory(blackboard)
add_subdirectory(bookmarks)
add_subdirectory(bubblemon)
add_subdirectory(calculator)
add_subdirectory(charselect)
add_subdirectory(comic)
add_subdirectory(fifteenPuzzle)
add_subdirectory(fileWatcher)
add_subdirectory(frame)
add_subdirectory(kolourpicker)
add_subdirectory(konqprofiles)
add_subdirectory(konsoleprofiles)
add_subdirectory(life)
add_subdirectory(luna)
add_subdirectory(magnifique)
add_subdirectory(microblog)
add_subdirectory(notes)
add_subdirectory(nowplaying)
if(LIBATTICA_FOUND)
add_subdirectory(knowledgebase)
add_subdirectory(community)
add_subdirectory(social-news)
endif(LIBATTICA_FOUND)
add_subdirectory(pastebin)
add_subdirectory(previewer)
add_subdirectory(rememberthemilk)
add_subdirectory(rssnow)
add_subdirectory(spellcheck)
add_subdirectory(showdashboard)
add_subdirectory(timer)
add_subdirectory(eyes)
add_subdirectory(unitconverter)
add_subdirectory(weatherstation)
if(QT_QTWEBKIT_FOUND)
add_subdirectory(dict)
add_subdirectory(news)
endif(QT_QTWEBKIT_FOUND)
if(PHONON_FOUND)
add_subdirectory(mediaplayer)
endif(PHONON_FOUND)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/qalculate/cmake_modules)
macro_optional_find_package(Qalculate)
if ( QALCULATE_FOUND )
macro_log_feature(QALCULATE_FOUND "Qalculate!" "Qalculate Library" "http://qalculate.sourceforge.net/" FALSE "" "Needed for building the Qalculate plasma applet")
add_subdirectory(qalculate)
endif( QALCULATE_FOUND )
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/kdeobservatory/cmake/modules)
macro_optional_find_package(Qwt)
if ( Qwt5-Qt4_FOUND )
add_subdirectory(kdeobservatory)
endif( Qwt5-Qt4_FOUND )
if(NOT WIN32)
if(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop")
if(KDE4WORKSPACE_FOUND)
add_subdirectory(lancelot)
endif(KDE4WORKSPACE_FOUND)
endif(${KDE_PLATFORM_PROFILE} STREQUAL "Desktop")
add_subdirectory(incomingmsg)
add_subdirectory(leavenote)
add_subdirectory(showdesktop)
add_subdirectory(paste)
add_subdirectory(plasmaboard)
add_subdirectory(systemloadviewer)
endif(NOT WIN32)
if (Q_WS_X11)
if (X11_Xrender_FOUND)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/kimpanel/cmake)
add_subdirectory(kimpanel)
endif (X11_Xrender_FOUND)
endif (Q_WS_X11)
add_subdirectory(webslice)

View file

@ -0,0 +1,20 @@
project(bball)
set(bball_SRCS bball.cpp)
kde4_add_ui_files(bball_SRCS bballConfig.ui)
kde4_add_plugin(plasma_applet_bball ${bball_SRCS})
target_link_libraries(plasma_applet_bball ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDE4_PHONON_LIBS} )
install(TARGETS plasma_applet_bball
DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-bball.desktop
DESTINATION ${SERVICES_INSTALL_DIR})
install(FILES bball.svgz football.svgz bounce.ogg
DESTINATION ${DATA_INSTALL_DIR}/bball/)
kde4_install_icons(${ICON_INSTALL_DIR})

View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC *.ui >> rc.cpp
$XGETTEXT *.cpp -o $podir/plasma_applet_BbalL.pot

View file

@ -0,0 +1,450 @@
/***************************************************************************
* Copyright 2008 by Thomas Gillespie <tomjamesgillespie@googlemail.com> *
* Copyright 2010 by Enrico Ros <enrico.ros@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "bball.h"
#include <QtCore/QSizeF>
#include <QtGui/QPainter>
#include <QtGui/QDesktopWidget>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsSceneMouseEvent>
#include <KSharedConfig>
#include <KLocale>
#include <KStandardDirs>
#include <KIO/NetAccess>
#include <KMessageBox>
#include <stdlib.h>
#ifdef Q_CC_MSVC
#include <iso646.h>
#endif
// default values
static const int initial_ball_radius = 64;
using namespace Plasma;
bballApplet::bballApplet(QObject * parent, const QVariantList & args):
Plasma::Applet(parent, args),
// keep this in sync with readConfiguration's default values
m_overlay_enabled(false),
m_overlay_opacity(0),
m_gravity(1.5),
m_friction(0.03),
m_restitution(0.8),
m_sound_enabled(false),
m_sound_volume(100),
m_auto_bounce_enabled(false),
m_auto_bounce_strength(0),
// more status
m_radius(initial_ball_radius),
m_angle(0),
m_angularVelocity(0),
m_mousePressed(false),
m_soundPlayer(0),
m_audioOutput(0)
{
setHasConfigurationInterface(true);
//TODO figure out why it is not good enough to set it here
// but that it needs to be set in constraintsEvent
// see also the icon applet
// update: apparently it gets reset when the formfactor changes
// this can be caught in constraintsEvent with Plasma::FormFactorConstraint
setBackgroundHints(NoBackground);
resize(contentSizeHint());
}
void bballApplet::init()
{
configChanged();
// monitor the scene for size changes (so we change the bouncing rect)
if (scene())
connect(scene(), SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateScreenRect()));
m_timer.start(25, this);
}
void bballApplet::paintInterface(QPainter * p, const QStyleOptionGraphicsItem * option, const QRect & contentsRect)
{
Q_UNUSED(option);
Q_UNUSED(contentsRect);
if (m_ballPixmap.isNull())
return;
if (m_angle) {
p->translate(m_radius, m_radius);
p->rotate(360 * m_angle / 6.28);
p->translate(-m_radius, -m_radius);
if (m_velocity.length() < 300) {
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);
}
}
p->drawPixmap(QPoint(0, 0), m_ballPixmap);
}
QSizeF bballApplet::contentSizeHint() const
{
return QSizeF(m_radius * 2, m_radius * 2);
}
void bballApplet::createConfigurationInterface(KConfigDialog *parent)
{
QWidget *widget = new QWidget;
ui.setupUi(widget);
// Appearance
ui.imageUrl->setUrl(KUrl::fromPath(m_image_url));
ui.colourizeEnabled->setChecked(m_overlay_enabled);
ui.colourizeLabel->setEnabled(m_overlay_enabled);
ui.colourize->setEnabled(m_overlay_enabled);
ui.colourize->setColor(m_overlay_colour);
ui.colourizeOpacityLabel->setEnabled(m_overlay_enabled);
ui.colourizeOpacitySlider->setEnabled(m_overlay_enabled);
ui.colourizeOpacitySlider->setSliderPosition(static_cast< int >(m_overlay_opacity/2.55)-1);
// Physics
ui.gravity->setSliderPosition(static_cast< int >(m_gravity * 100));
ui.friction->setSliderPosition(static_cast< int >(m_friction * 100));
ui.resitution->setSliderPosition(static_cast < int >(m_restitution * 100));
// Sound
ui.soundEnabled->setChecked(m_sound_enabled);
ui.soundVolumeLabel->setEnabled(m_sound_enabled);
ui.soundVolume->setEnabled(m_sound_enabled);
ui.soundVolume->setSliderPosition(m_sound_volume);
ui.soundFileLabel->setEnabled(m_sound_enabled);
ui.soundFile->setEnabled(m_sound_enabled);
ui.soundFile->setUrl(KUrl::fromPath(m_sound_url));
// Misc
ui.autoBounceEnabled->setChecked(m_auto_bounce_enabled);
ui.autoBounceStrengthLabel->setEnabled(m_auto_bounce_enabled);
ui.autoBounceStrength->setValue(static_cast < int >(m_auto_bounce_strength));
ui.autoBounceStrength->setEnabled(m_auto_bounce_enabled);
parent->addPage(widget, i18n("General"), icon());
connect(ui.imageUrl, SIGNAL(textChanged(QString)), parent, SLOT(settingsModified()));
connect(ui.colourizeEnabled, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.colourize, SIGNAL(changed(QColor)), parent, SLOT(settingsModified()));
connect(ui.colourizeOpacitySlider, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(ui.gravity, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(ui.friction, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(ui.resitution, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(ui.soundEnabled, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.soundVolume, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(ui.soundFile, SIGNAL(textChanged(QString)), parent, SLOT(settingsModified()));
connect(ui.autoBounceEnabled, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.autoBounceStrength, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified()));
connect(parent, SIGNAL(accepted()), this, SLOT(configurationChanged()));
}
void bballApplet::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
if (immutability() != Plasma::Mutable)
return;
if (m_geometry.isNull())
syncGeometry();
// reset timing
m_timer.stop();
m_time = QTime();
update();
// reset physics
m_velocity = QVector2D();
m_angularVelocity = 0;
// save mouse position
m_mouseScenePos = event->scenePos();
m_mousePressed = true;
event->accept();
}
void bballApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if (immutability() != Plasma::Mutable)
return;
// TODO: use real timing instead of the fixed step (1/0.025)
m_velocity = QVector2D(m_mouseScenePos - m_prevMouseScenePos) / 0.025;
m_mousePressed = false;
m_timer.start(25, this);
event->accept();
}
void bballApplet::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
if (immutability() != Plasma::Mutable)
return;
m_prevMouseScenePos = m_mouseScenePos;
m_mouseScenePos = event->scenePos();
m_geometry.translate(m_mouseScenePos - m_prevMouseScenePos);
setGeometry(m_geometry);
event->accept();
}
void bballApplet::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_timer.timerId()) {
updatePhysics();
return;
}
Applet::timerEvent(event);
}
void bballApplet::constraintsEvent(Plasma::Constraints constraints)
{
if (constraints & Plasma::LocationConstraint)
m_geometry = QRectF();
if (constraints & Plasma::FormFactorConstraint)
setBackgroundHints(NoBackground);
if (constraints & Plasma::SizeConstraint)
syncGeometry();
}
void bballApplet::updateScreenRect()
{
m_screenRect = QDesktopWidget().availableGeometry();
m_timer.start(25, this);
}
void bballApplet::configurationChanged()
{
KConfigGroup cg = config();
// Appearance
if (KIO::NetAccess::exists(ui.imageUrl->url(), KIO::NetAccess::SourceSide, NULL)) {
m_image_url = ui.imageUrl->url().path();
cg.writeEntry("ImgURL", m_image_url);
m_ballSvg.setImagePath(m_image_url);
} else
KMessageBox::error(0, i18n("The given image could not be loaded. The image will not be changed."));
m_overlay_enabled = ui.colourizeEnabled->checkState() == Qt::Checked;
cg.writeEntry("OverlayEnabled", m_overlay_enabled);
m_overlay_colour = ui.colourize->color();
cg.writeEntry("OverlayColour", m_overlay_colour);
m_overlay_opacity = static_cast< int >(ui.colourizeOpacitySlider->value() * 2.55);
cg.writeEntry("OverlayOpacity", m_overlay_opacity);
updateScaledBallImage();
// Physics
m_gravity = (qreal)ui.gravity->value() / 100.0;
cg.writeEntry("Gravity", m_gravity);
m_friction = (qreal)ui.friction->value() / 100.0;
cg.writeEntry("Friction", 1.0 - m_friction); // RETROCOMP
m_restitution = ui.resitution->value () / 100.0;
cg.writeEntry("Resitution", m_restitution);
// Sound
m_sound_enabled = ui.soundEnabled->checkState() == Qt::Checked;
cg.writeEntry("SoundEnabled", m_sound_enabled);
if (m_sound_enabled) {
if (KIO::NetAccess::exists(ui.soundFile->url(), KIO::NetAccess::SourceSide, NULL)) {
m_sound_url = ui.soundFile->url().path();
cg.writeEntry("SoundURL", m_sound_url);
if (m_soundPlayer)
m_soundPlayer->setCurrentSource(m_sound_url);
} else
KMessageBox::error(0, i18n("The given sound could not be loaded. The sound will not be changed."));
}
m_sound_volume = ui.soundVolume->value();
cg.writeEntry("SoundVolume", m_sound_volume);
if (m_audioOutput)
m_audioOutput->setVolume(m_sound_volume);
// Misc
m_auto_bounce_enabled = ui.autoBounceEnabled->checkState() == Qt::Checked;
cg.writeEntry("AutoBounceEnabled", m_auto_bounce_enabled);
m_auto_bounce_strength = ui.autoBounceStrength->value();
cg.writeEntry ("AutoBounceStrength", m_auto_bounce_strength);
if (m_auto_bounce_enabled || m_gravity > 0)
m_timer.start(25, this);
// mouse - undo the mouse clicked
m_mousePressed = false;
update();
}
void bballApplet::configChanged()
{
KConfigGroup cg = config ();
// Appearance
m_image_url = cg.readEntry("ImgURL", KStandardDirs::locate("data", QLatin1String( "bball/bball.svgz" )));
m_overlay_enabled = cg.readEntry("OverlayEnabled", false);
m_overlay_colour = cg.readEntry("OverlayColour", QColor(Qt::white));
m_overlay_opacity = cg.readEntry("OverlayOpacity", 0);
m_ballSvg.setImagePath(m_image_url);
updateScaledBallImage();
// Physics
m_gravity = cg.readEntry("Gravity", 1.5);
m_friction = 1.0 - cg.readEntry("Friction", 0.97); // RETROCOMP
m_restitution = cg.readEntry("Resitution", 0.8);
// Sound
m_sound_enabled = cg.readEntry("SoundEnabled", false);
m_sound_url = cg.readEntry("SoundURL", KStandardDirs::locate ("data", QLatin1String( "bball/bounce.ogg" )));
m_sound_volume = cg.readEntry("SoundVolume", 100);
// Misc
m_auto_bounce_enabled = cg.readEntry("AutoBounceEnabled", false);
m_auto_bounce_strength = cg.readEntry("AutoBounceStrength", 0);
}
void bballApplet::updatePhysics()
{
// find out the delta-time since the last call
if (m_time.isNull())
m_time.start();
qreal dT = qMin((qreal)m_time.restart() / 1000.0, 0.5);
// skip progessing if externally moved (disabled because plasma moves this too frequently)
//if (m_geometry != geometry())
// m_geometry = QRectF();
// skip if dragging
if (m_mousePressed || m_geometry.isNull() || m_radius < 1)
return;
if (m_screenRect.isNull())
updateScreenRect();
// add some randomness if autobouncing
if (m_auto_bounce_enabled && rand() < RAND_MAX/35) {
m_velocity += QVector2D(
(rand() - RAND_MAX/2) * m_auto_bounce_strength * 0.0000005,
(rand() - RAND_MAX/2) * m_auto_bounce_strength * 0.0000005);
}
// update velocity and position
m_velocity += QVector2D(0, (qreal)m_screenRect.height() * m_gravity * dT);
m_velocity *= (1.0 - 2 * m_friction * dT);
m_geometry.translate((m_velocity * dT).toPointF());
// floor
bool collision = false;
bool bottom = false;
if (m_geometry.bottom() >= m_screenRect.bottom() && m_velocity.y() > 0) {
m_geometry.moveBottom(m_screenRect.bottom());
m_velocity *= QVector2D(1, -m_restitution);
m_angularVelocity = m_velocity.x() / m_radius;
collision = true;
bottom = true;
}
// ceiling
if (m_geometry.top() <= m_screenRect.top() && m_velocity.y() < 0) {
m_geometry.moveTop(m_screenRect.top ());
m_velocity *= QVector2D(1, -m_restitution);
m_angularVelocity = -m_velocity.x() / m_radius;
collision = true;
}
// right
if (m_geometry.right() >= m_screenRect.right() && m_velocity.x() > 0) {
m_geometry.moveRight(m_screenRect.right() - 0.1);
m_velocity *= QVector2D(-m_restitution, 1);
m_angularVelocity = -m_velocity.y() / m_radius;
if (bottom)
m_velocity.setX(0);
collision = true;
}
// left
if (m_geometry.left() <= m_screenRect.left() && m_velocity.x() < 0) {
m_geometry.moveLeft(m_screenRect.left () + 0.1);
m_velocity *= QVector2D(-m_restitution, 1);
m_angularVelocity = m_velocity.y() / m_radius;
if (bottom)
m_velocity.setX(0);
collision = true;
}
m_angularVelocity *= (0.9999 - 2 * m_friction * dT);
m_angle += m_angularVelocity * dT;
// stop animation if reached bottom and still
if (m_velocity.length() < 10.0 && qAbs(m_angularVelocity) < 0.1 && !m_auto_bounce_enabled) {
m_timer.stop();
update();
return;
}
// move this and update graphics
setGeometry(m_geometry);
update();
if (collision)
playBoingSound();
}
void bballApplet::playBoingSound()
{
if (!m_sound_enabled || m_velocity.x() == 0.0 || m_velocity.y() == 0.0)
return;
// create the player if missing
if (!m_soundPlayer) {
m_soundPlayer = new Phonon::MediaObject(this);
m_soundPlayer->setCurrentSource(m_sound_url);
m_audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
m_audioOutput->setVolume(m_sound_volume);
createPath(m_soundPlayer, m_audioOutput);
}
// play the sound
m_soundPlayer->seek(0);
m_soundPlayer->play();
}
void bballApplet::syncGeometry()
{
m_geometry = geometry();
m_radius = static_cast<int>(geometry().width()) / 2;
updateScaledBallImage();
}
void bballApplet::updateScaledBallImage()
{
// regen m_ballPixmap
m_ballSvg.resize(contentSizeHint());
m_ballPixmap = m_ballSvg.pixmap();
// tint the pixmap if requested
if (m_overlay_enabled) {
QPainter p(&m_ballPixmap);
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(Qt::NoPen);
QColor brush = m_overlay_colour;
brush.setAlpha(m_overlay_opacity);
p.setBrush(brush);
p.drawEllipse(QRectF(0, 0, m_radius * 2, m_radius * 2));
}
}
#include "bball.moc"

View file

@ -0,0 +1,119 @@
/***************************************************************************
* Copyright 2008 by Thomas Gillespie <tomjamesgillespie@googlemail.com> *
* Copyright 2010 by Enrico Ros <enrico.ros@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef bball_HEADER
#define bball_HEADER
#include <QtCore/QBasicTimer>
#include <QtCore/QTime>
#include <QtGui/QVector2D>
#include <KConfigDialog>
#include <Plasma/Applet>
#include <Plasma/Svg>
#include <Phonon/MediaObject>
#include <Phonon/Path>
#include <Phonon/AudioOutput>
#include <Phonon/Global>
#include "ui_bballConfig.h"
class QGraphicsSceneMouseEvent;
class QSizeF;
class bballApplet : public Plasma::Applet
{
Q_OBJECT
public:
bballApplet(QObject * parent, const QVariantList & args);
// ::Plasma::Applet
void init();
void paintInterface(QPainter * painter, const QStyleOptionGraphicsItem * option, const QRect & contentsRect);
QSizeF contentSizeHint() const;
void createConfigurationInterface(KConfigDialog *parent);
// ::QGraphicsItem
void mousePressEvent(QGraphicsSceneMouseEvent * event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
void timerEvent(QTimerEvent *event);
protected:
// ::Plasma::Applet
void constraintsEvent(Plasma::Constraints constraints);
protected Q_SLOTS:
void updateScreenRect();
void configurationChanged();
public slots:
void configChanged();
private:
void updatePhysics();
void playBoingSound();
void syncGeometry();
void updateScaledBallImage();
// config values
QString m_image_url;
bool m_overlay_enabled;
int m_overlay_opacity;
QColor m_overlay_colour;
qreal m_gravity, m_friction, m_restitution;
bool m_sound_enabled;
int m_sound_volume;
QString m_sound_url;
bool m_auto_bounce_enabled;
qreal m_auto_bounce_strength;
// status
QBasicTimer m_timer;
QTime m_time;
QRectF m_screenRect;
int m_radius;
QRectF m_geometry;
QVector2D m_velocity;
qreal m_angle;
qreal m_angularVelocity;
Plasma::Svg m_ballSvg;
QPixmap m_ballPixmap;
bool m_mousePressed;
QPointF m_mouseScenePos;
QPointF m_prevMouseScenePos;
Ui::bballConfig ui;
Phonon::MediaObject * m_soundPlayer;
Phonon::AudioOutput * m_audioOutput;
};
K_EXPORT_PLASMA_APPLET (BbalL, bballApplet)
#endif

Binary file not shown.

View file

@ -0,0 +1,568 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>bballConfig</class>
<widget class="QWidget" name="bballConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>546</width>
<height>437</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure BbalL!</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Appearance</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="KUrlRequester" name="imageUrl">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="filter">
<string>*.png *.gif *.svg *.svgz *.jpeg *.jpg</string>
</property>
<property name="fileDialogModality">
<enum>Qt::NonModal</enum>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<layout class="QHBoxLayout">
<item>
<widget class="KColorButton" name="colourize">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="colourizeEnabled">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QLabel" name="colourizeOpacityLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Colorize opacity:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>colourizeOpacitySlider</cstring>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QSlider" name="colourizeOpacitySlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Physics</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="2">
<widget class="QSlider" name="gravity">
<property name="maximum">
<number>500</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="6" column="2" colspan="2">
<widget class="QSlider" name="friction">
<property name="maximum">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="7" column="2" colspan="2">
<widget class="QSlider" name="resitution">
<property name="maximum">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Sound enabled:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>soundEnabled</cstring>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="QCheckBox" name="soundEnabled">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="2" colspan="2">
<widget class="QSlider" name="soundVolume">
<property name="enabled">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="soundFileLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Bounce effect:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>soundFile</cstring>
</property>
</widget>
</item>
<item row="12" column="2" colspan="2">
<widget class="KUrlRequester" name="soundFile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Auto Bounce</string>
</property>
</widget>
</item>
<item row="18" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>361</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Image:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>imageUrl</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="colourizeLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Colorize:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>colourize</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>Gravity:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>gravity</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Friction:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>friction</cstring>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Restitution:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>resitution</cstring>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Sound</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="soundVolumeLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Volume:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>soundVolume</cstring>
</property>
</widget>
</item>
<item row="15" column="2">
<widget class="QCheckBox" name="autoBounceEnabled">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Auto bounce:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>autoBounceEnabled</cstring>
</property>
</widget>
</item>
<item row="17" column="1">
<widget class="QLabel" name="autoBounceStrengthLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Auto bounce strength:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>autoBounceStrength</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="17" column="2">
<widget class="QSlider" name="autoBounceStrength">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KUrlRequester</class>
<extends>QFrame</extends>
<header>kurlrequester.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>KColorButton</class>
<extends>QPushButton</extends>
<header>kcolorbutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>colourizeEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>colourize</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>302</x>
<y>158</y>
</hint>
<hint type="destinationlabel">
<x>218</x>
<y>160</y>
</hint>
</hints>
</connection>
<connection>
<sender>colourizeEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>colourizeOpacitySlider</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>372</x>
<y>160</y>
</hint>
<hint type="destinationlabel">
<x>375</x>
<y>230</y>
</hint>
</hints>
</connection>
<connection>
<sender>autoBounceEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>autoBounceStrength</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>177</x>
<y>104</y>
</hint>
<hint type="destinationlabel">
<x>182</x>
<y>194</y>
</hint>
</hints>
</connection>
<connection>
<sender>autoBounceEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>autoBounceStrengthLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>212</x>
<y>110</y>
</hint>
<hint type="destinationlabel">
<x>80</x>
<y>200</y>
</hint>
</hints>
</connection>
<connection>
<sender>colourizeEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>colourizeLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>340</x>
<y>145</y>
</hint>
<hint type="destinationlabel">
<x>56</x>
<y>163</y>
</hint>
</hints>
</connection>
<connection>
<sender>colourizeEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>colourizeOpacityLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>404</x>
<y>158</y>
</hint>
<hint type="destinationlabel">
<x>92</x>
<y>219</y>
</hint>
</hints>
</connection>
<connection>
<sender>soundEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>soundVolumeLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>130</x>
<y>103</y>
</hint>
<hint type="destinationlabel">
<x>63</x>
<y>157</y>
</hint>
</hints>
</connection>
<connection>
<sender>soundEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>soundVolume</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>284</x>
<y>101</y>
</hint>
<hint type="destinationlabel">
<x>289</x>
<y>151</y>
</hint>
</hints>
</connection>
<connection>
<sender>soundEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>soundFileLabel</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>233</x>
<y>99</y>
</hint>
<hint type="destinationlabel">
<x>55</x>
<y>224</y>
</hint>
</hints>
</connection>
<connection>
<sender>soundEnabled</sender>
<signal>clicked(bool)</signal>
<receiver>soundFile</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>253</x>
<y>106</y>
</hint>
<hint type="destinationlabel">
<x>269</x>
<y>221</y>
</hint>
</hints>
</connection>
</connections>
</ui>

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

View file

@ -0,0 +1,125 @@
[Desktop Entry]
Encoding=UTF-8
Name=Bouncy Ball
Name[ar]=كرة نطّاطة
Name[bs]=Bouncy Ball
Name[ca]=Una pilota que bota
Name[ca@valencia]=Una pilota que bota
Name[cs]=Poskakující míč
Name[da]=Hoppebold
Name[de]=Springender Ball
Name[el]=Aναπηδώσα μπάλα
Name[en_GB]=Bouncy Ball
Name[es]=Pelota que rebota
Name[et]=Põrkav pall
Name[eu]=Pilota bizia
Name[fi]=Pomppupallo
Name[fr]=Balle rebondissante
Name[gl]=Bóla a rebotar
Name[hr]=Odskakujuća lopta
Name[hu]=Pattogó labda
Name[it]=Palla rimbalzante
Name[ja]=
Name[kk]=Секірмелі доп
Name[km]=Bouncy Ball
Name[ko]=
Name[lt]=Šokinėjantis kamuolys
Name[lv]=Atlecoša bumba
Name[mr]=
Name[nb]=Sprettball
Name[nds]=Jumpen Ball
Name[nl]=Stuiterende bal
Name[nn]=Sprettball
Name[pa]=
Name[pl]=Skacząca piłka
Name[pt]=Bola Saltitante
Name[pt_BR]=Bola saltitante
Name[ro]=Minge săritoare
Name[ru]=Попрыгунчик
Name[sk]=Poskakujúca lopta
Name[sl]=Odbijajoča se žoga
Name[sr]=скочилопта
Name[sr@ijekavian]=скочилопта
Name[sr@ijekavianlatin]=skočilopta
Name[sr@latin]=skočilopta
Name[sv]=Studsande boll
Name[th]=
Name[tr]=Zıplayan Top
Name[ug]=Bouncy Ball
Name[uk]=Мячик-стрибунець
Name[wa]=Ridjiblante bole
Name[x-test]=xxBouncy Ballxx
Name[zh_CN]=
Name[zh_TW]=
Comment=A bouncy ball for plasma
Comment[ar]=كرة نطاطة للبلازما
Comment[ast]=Una pelota que rebota pa plasma
Comment[bs]=Odskačuća lopta za Plazmu
Comment[ca]=Una pilota que bota per al plasma
Comment[ca@valencia]=Una pilota que bota per al plasma
Comment[cs]=Poskakující míč pro Plasmu
Comment[da]=En hoppende bold til Plasma
Comment[de]=Ein Springball für Plasma
Comment[el]=Μια αναπηδώσα μπάλα για το plasma
Comment[en_GB]=A bouncy ball for plasma
Comment[es]=Una pelota que rebota para plasma
Comment[et]=Põrkavad pallid Plasmale
Comment[eu]=Plasmarentzako pilota bizi bat
Comment[fi]=Pomppiva pallo Plasmaan
Comment[fr]=Une balle rebondissante pour KDE
Comment[ga]=Liathróid phreabarnach le haghaidh plasma
Comment[gl]=Unha bóla a rebotar para plasma
Comment[he]=כדור קופצני עבור plasma
Comment[hr]=Odskakujuća lopta za Plasmu
Comment[hu]=Pattogó labda
Comment[is]=Hoppandi plasmabolti
Comment[it]=Una palla rimbalzante per Plasma
Comment[ja]=Plasma
Comment[kk]=Plasma-ның секірмелі добы
Comment[km]=
Comment[ko]=
Comment[ku]=Topa lotikî ji bo plasma
Comment[lt]=Šokinėjantis kamuolys plazmai
Comment[lv]=Atlecoša bumba
Comment[mr]= ि
Comment[nb]=En sprettball for plasma
Comment[nds]=En jumpen Ball för Plasma
Comment[nl]=Een stuiterende bal voor plasma
Comment[nn]=Sprettball til Plasma
Comment[pa]=
Comment[pl]=Skacząca piłka
Comment[pt]=Uma bola saltitante para o Plasma
Comment[pt_BR]=Uma bola saltitante para o Plasma
Comment[ro]=O minge săritoare pentru Plasma
Comment[ru]=Попрыгунчик для Plasma
Comment[sk]=Poskakujúca lopta pre Plasmu
Comment[sl]=Odbijajoča se žoga za Plasmo
Comment[sr]=Одскачућа лопта за Плазму
Comment[sr@ijekavian]=Одскачућа лопта за Плазму
Comment[sr@ijekavianlatin]=Odskačuća lopta za Plasmu
Comment[sr@latin]=Odskačuća lopta za Plasmu
Comment[sv]=En studsande boll för Plasma
Comment[th]=
Comment[tr]=Plasma için bir zıplayan top
Comment[uk]=Мячик-стрибунець для плазми
Comment[wa]=Ene bole ki ridjibele po plasma
Comment[x-test]=xxA bouncy ball for plasmaxx
Comment[zh_CN]= plasma
Comment[zh_TW]=Plasma
Type=Service
ServiceTypes=Plasma/Applet
Icon=bball
X-KDE-Library=plasma_applet_bball
X-KDE-PluginInfo-Author=Thomas Gillespie
X-KDE-PluginInfo-Email=tomjamesgillespie@googlemail.com
X-KDE-PluginInfo-Name=BbalL
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=
X-KDE-PluginInfo-Category=Fun and Games
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused

View file

@ -0,0 +1,12 @@
project(binaryclock)
set(binaryclock_SRCS binaryclock.cpp)
kde4_add_ui_files(binaryclock_SRCS clockConfig.ui)
kde4_add_plugin(plasma_applet_binaryclock ${binaryclock_SRCS})
target_link_libraries(plasma_applet_binaryclock ${KDE4WORKSPACE_PLASMACLOCK_LIBRARY} ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS})
install(TARGETS plasma_applet_binaryclock DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-binaryclock.desktop DESTINATION ${SERVICES_INSTALL_DIR})

View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC *.ui >> rc.cpp
$XGETTEXT *.cpp -o $podir/plasma_applet_binaryclock.pot

View file

@ -0,0 +1,316 @@
/***************************************************************************
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org> *
* Copyright 2007 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 "binaryclock.h"
#include <QPainter>
#include <KConfigDialog>
#include <Plasma/DataEngine>
#include <Plasma/Theme>
BinaryClock::BinaryClock(QObject *parent, const QVariantList &args)
: ClockApplet(parent, args),
m_showSeconds(true),
m_showOffLeds(true),
m_showGrid(true),
m_time(0, 0)
{
KGlobal::locale()->insertCatalog(QLatin1String("libplasmaclock"));
KGlobal::locale()->insertCatalog(QLatin1String("timezones4"));
setHasConfigurationInterface(true);
resize(getWidthFromHeight(128), 128);
}
void BinaryClock::init()
{
ClockApplet::init();
clockConfigChanged();
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(updateColors()));
connectToEngine();
updateColors();
}
BinaryClock::~BinaryClock()
{
}
int BinaryClock::getHeightFromWidth(int w) const
{
int dots = m_showSeconds ? 6 : 4;
int rectSize = (w - 5) * 4;
return (rectSize / dots) + 3;
}
int BinaryClock::getWidthFromHeight(int h) const
{
int dots = m_showSeconds ? 6 : 4;
int rectSize = (h - 3) / 4;
return (rectSize * dots) + (dots - 1);
}
void BinaryClock::constraintsEvent(Plasma::Constraints constraints)
{
if (constraints & Plasma::SizeConstraint) {
qreal top, bottom, left, right;
getContentsMargins(&left, &top, &right, &bottom);
qreal borderHeight = top + bottom;
qreal borderWidth = left + right;
if (formFactor() == Plasma::Vertical) {
setMinimumHeight(getHeightFromWidth((int) contentsRect().width()) + borderHeight);
setMinimumWidth(0);
} else if (formFactor() == Plasma::Horizontal) {
setMinimumWidth(getWidthFromHeight((int) contentsRect().height()) + borderWidth);
setMinimumHeight(0);
} else {
setMinimumWidth(getWidthFromHeight(40));
setMinimumHeight(40);
}
}
}
void BinaryClock::connectToEngine()
{
Plasma::DataEngine* timeEngine = dataEngine(QLatin1String("time"));
if (m_showSeconds) {
timeEngine->connectSource(currentTimezone(), this, 500);
} else {
timeEngine->connectSource(currentTimezone(), this, 6000, Plasma::AlignToMinute);
}
}
void BinaryClock::dataUpdated(const QString& source, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(source);
m_time = data[QLatin1String("Time")].toTime();
if (m_time.minute() == m_lastTimeSeen.minute() &&
m_time.second() == m_lastTimeSeen.second()) {
// avoid unnecessary repaints
return;
}
if (Plasma::ToolTipManager::self()->isVisible(this)) {
updateTipContent();
}
updateClockApplet(data);
m_lastTimeSeen = m_time;
update();
}
void BinaryClock::createClockConfigurationInterface(KConfigDialog *parent)
{
QWidget *widget = new QWidget();
ui.setupUi(widget);
parent->addPage(widget, i18n("Appearance"), QLatin1String("view-media-visualization"));
ui.showSecondHandCheckBox->setChecked(m_showSeconds);
ui.showGridCheckBox->setChecked(m_showGrid);
ui.showOffLedsCheckBox->setChecked(m_showOffLeds);
QButtonGroup *onLedsGroup = new QButtonGroup(widget);
onLedsGroup->addButton(ui.onLedsDefaultColorRadioButton);
onLedsGroup->addButton(ui.onLedsCustomColorRadioButton);
QButtonGroup *offLedsGroup = new QButtonGroup(widget);
offLedsGroup->addButton(ui.offLedsDefaultColorRadioButton);
offLedsGroup->addButton(ui.offLedsCustomColorRadioButton);
ui.onLedsDefaultColorRadioButton->setChecked(!m_customOnLedsColor);
ui.offLedsDefaultColorRadioButton->setChecked(!m_customOffLedsColor);
ui.gridDefaultColorRadioButton->setChecked(!m_customGridColor);
ui.onLedsCustomColorRadioButton->setChecked(m_customOnLedsColor);
ui.offLedsCustomColorRadioButton->setChecked(m_customOffLedsColor);
ui.gridCustomColorRadioButton->setChecked(m_customGridColor);
KConfigGroup cg = config();
ui.onLedsCustomColorButton->setColor(cg.readEntry("onLedsColor", m_onLedsColor));
ui.offLedsCustomColorButton->setColor(cg.readEntry("offLedsColor", m_offLedsColor));
ui.gridCustomColorButton->setColor(cg.readEntry("gridColor", m_gridColor));
connect(ui.showSecondHandCheckBox, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.showGridCheckBox, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.showOffLedsCheckBox, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(onLedsGroup, SIGNAL(buttonReleased(int)), parent, SLOT(settingsModified()));
connect(offLedsGroup, SIGNAL(buttonReleased(int)), parent, SLOT(settingsModified()));
connect(ui.showOffLedsCheckBox, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
connect(ui.showGridCheckBox, SIGNAL(stateChanged(int)), parent, SLOT(settingsModified()));
}
void BinaryClock::clockConfigAccepted()
{
KConfigGroup cg = config();
m_showSeconds = ui.showSecondHandCheckBox->isChecked();
m_showGrid = ui.showGridCheckBox->isChecked();
m_showOffLeds = ui.showOffLedsCheckBox->isChecked();
m_customOnLedsColor = ui.onLedsCustomColorRadioButton->isChecked();
m_customOffLedsColor = ui.offLedsCustomColorRadioButton->isChecked();
m_customGridColor = ui.gridCustomColorRadioButton->isChecked();
if (m_customOnLedsColor){
m_onLedsColor = ui.onLedsCustomColorButton->color();
}
if (m_customOffLedsColor){
m_offLedsColor = ui.offLedsCustomColorButton->color();
}
if (m_customGridColor){
m_gridColor = ui.gridCustomColorButton->color();
}
cg.writeEntry("showSeconds", m_showSeconds);
cg.writeEntry("showGrid", m_showGrid);
cg.writeEntry("showOffLeds", m_showOffLeds);
cg.writeEntry("customOnLedsColor", m_customOnLedsColor);
cg.writeEntry("customOffLedsColor", m_customOffLedsColor);
cg.writeEntry("customGridColor", m_customGridColor);
cg.writeEntry("onLedsColor", ui.onLedsCustomColorButton->color());
cg.writeEntry("offLedsColor", ui.offLedsCustomColorButton->color());
cg.writeEntry("gridColor", ui.gridCustomColorButton->color());
dataEngine(QLatin1String("time"))->disconnectSource(currentTimezone(), this);
connectToEngine();
update();
emit configNeedsSaving();
}
void BinaryClock::clockConfigChanged()
{
KConfigGroup cg = config();
m_showSeconds = cg.readEntry("showSeconds", m_showSeconds);
m_showGrid = cg.readEntry("showGrid", m_showGrid);
m_showOffLeds = cg.readEntry("showOffLeds", m_showOffLeds);
m_customOnLedsColor = cg.readEntry("customOnLedsColor", false);
m_customOffLedsColor = cg.readEntry("customOffLedsColor", false);
m_customGridColor = cg.readEntry("customGridColor", false);
updateColors();
}
void BinaryClock::changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone)
{
dataEngine(QLatin1String("time"))->disconnectSource(oldTimezone, this);
Plasma::DataEngine* timeEngine = dataEngine(QLatin1String("time"));
if (m_showSeconds) {
timeEngine->connectSource(newTimezone, this, 500);
} else {
timeEngine->connectSource(newTimezone, this, 6000, Plasma::AlignToMinute);
}
}
void BinaryClock::updateColors()
{
KConfigGroup cg = config();
m_onLedsColor = QColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
if (m_customOnLedsColor){
m_onLedsColor = cg.readEntry("onLedsColor", m_onLedsColor);
}
m_offLedsColor = QColor(m_onLedsColor);
m_offLedsColor.setAlpha(40);
if (m_customOffLedsColor){
m_offLedsColor = cg.readEntry("offLedsColor", m_offLedsColor);
}
m_gridColor = QColor(m_onLedsColor);
m_gridColor.setAlpha(60);
if (m_customGridColor){
m_gridColor = cg.readEntry("gridColor", m_gridColor);
}
update();
}
void BinaryClock::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option,
const QRect &contentsRect)
{
Q_UNUSED(option);
if (! m_time.isValid()) {
return;
}
QSizeF m_size = contentsRect.size();
int appletHeight = (int) contentsRect.height();
int appletWidth = (int) contentsRect.width();
int dots = m_showSeconds ? 6 : 4;
int rectSize = qMax(1, qMin((appletHeight - 3) / 4, (appletWidth - 3) / dots));
int yPos = ((appletHeight - 4 * rectSize) / 2) + contentsRect.topLeft().y();
int xPos = ((appletWidth - (rectSize * dots) - 5) / 2) + contentsRect.topLeft().x();
int timeDigits[6] = {m_time.hour() / 10, m_time.hour() % 10,
m_time.minute() / 10, m_time.minute() % 10,
m_time.second() / 10, m_time.second() % 10};
for (int i = 0; i < dots; i++) {
for (int j = 0; j < 4; j++) {
if (timeDigits[i] & (1 << (3 - j))) {
p->fillRect(xPos + (i * (rectSize + 1)), yPos + (j * (rectSize + 1)), rectSize, rectSize, m_onLedsColor);
} else if (m_showOffLeds) {
p->fillRect(xPos + (i * (rectSize + 1)), yPos + (j * (rectSize + 1)), rectSize, rectSize, m_offLedsColor);
}
}
}
if (m_showGrid) {
p->setPen(m_gridColor);
p->drawRect((xPos - 1), (yPos - 1),
(dots * (rectSize + 1)), (4 * (rectSize + 1)) );
for (int i = 1; i < dots; i++) {
for (int j = 0; j < 4; j++) {
p->drawLine((xPos + (i * (rectSize + 1)) - 1), (yPos + (j * (rectSize + 1))),
(xPos + (i * (rectSize + 1)) - 1), (yPos + (j * (rectSize + 1)) + rectSize - 1) );
}
}
for (int j = 1; j < 4; j++) {
p->drawLine(xPos, (yPos + (j * (rectSize + 1)) - 1),
(xPos + (dots * (rectSize + 1)) - 2), (yPos + (j * (rectSize + 1)) - 1) );
}
}
}
#include "binaryclock.moc"

View file

@ -0,0 +1,87 @@
/***************************************************************************
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org> *
* Copyright 2007 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 BINARYCLOCK_H
#define BINARYCLOCK_H
#include <Plasma/Applet>
#include <plasmaclock/clockapplet.h>
#include "ui_clockConfig.h"
class QTime;
class QColor;
namespace Plasma {
class DataEngine;
}
class BinaryClock : public ClockApplet
{
Q_OBJECT
public:
BinaryClock(QObject *parent, const QVariantList &args);
~BinaryClock();
void init();
void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect& contentsRect);
void constraintsEvent(Plasma::Constraints constraints);
public slots:
void dataUpdated(const QString &name, const Plasma::DataEngine::Data &data);
protected:
void createClockConfigurationInterface(KConfigDialog *parent);
void clockConfigAccepted();
void clockConfigChanged();
void changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone);
private slots:
void updateColors();
private:
void connectToEngine();
int getWidthFromHeight(int h) const;
int getHeightFromWidth(int w) const;
bool m_showSeconds;
bool m_showOffLeds;
bool m_showGrid;
bool m_customOnLedsColor;
bool m_customOffLedsColor;
bool m_customGridColor;
QColor m_onLedsColor;
QColor m_offLedsColor;
QColor m_gridColor;
QTime m_lastTimeSeen;
QTime m_time;
int m_updateIndex;
Ui::clockConfig ui;
};
K_EXPORT_PLASMA_APPLET(binaryclock, BinaryClock)
#endif

View file

@ -0,0 +1,423 @@
<ui version="4.0" >
<class>clockConfig</class>
<widget class="QWidget" name="clockConfig" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>349</height>
</rect>
</property>
<property name="minimumSize" >
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="Appearance" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Appearance</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Active LEDs:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="4" >
<layout class="QHBoxLayout" name="horizontalLayout_3" >
<item>
<widget class="QRadioButton" name="onLedsCustomColorRadioButton" >
<property name="text" >
<string>Use custom color for active LEDs:</string>
</property>
</widget>
</item>
<item>
<widget class="KColorButton" name="onLedsCustomColorButton" />
</item>
<item>
<spacer name="horizontalSpacer_3" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="4" column="2" >
<spacer name="verticalSpacer_3" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>7</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" colspan="2" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Inactive LEDs:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="2" colspan="3" >
<widget class="QCheckBox" name="showOffLedsCheckBox" >
<property name="toolTip" >
<string>Show the inactive LEDs</string>
</property>
<property name="whatsThis" >
<string>Check this if you want to see the inactive LEDs.</string>
</property>
<property name="text" >
<string>Show</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="4" >
<widget class="QRadioButton" name="offLedsDefaultColorRadioButton" >
<property name="text" >
<string>Use theme color</string>
</property>
</widget>
</item>
<item row="7" column="4" >
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QRadioButton" name="offLedsCustomColorRadioButton" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Use custom color for inactive LEDs:</string>
</property>
</widget>
</item>
<item>
<widget class="KColorButton" name="offLedsCustomColorButton" />
</item>
<item>
<spacer name="horizontalSpacer_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="8" column="2" colspan="2" >
<spacer name="verticalSpacer_2" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>7</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0" colspan="2" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Grid:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="2" colspan="3" >
<widget class="QCheckBox" name="showGridCheckBox" >
<property name="toolTip" >
<string>Show the grid</string>
</property>
<property name="whatsThis" >
<string>Check this if you want to see a grid around leds.</string>
</property>
<property name="text" >
<string>Show</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="4" >
<widget class="QRadioButton" name="gridDefaultColorRadioButton" >
<property name="text" >
<string>Use theme color</string>
</property>
</widget>
</item>
<item row="11" column="4" >
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QRadioButton" name="gridCustomColorRadioButton" >
<property name="text" >
<string>Use custom grid color:</string>
</property>
</widget>
</item>
<item>
<widget class="KColorButton" name="gridCustomColorButton" />
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="12" column="0" >
<spacer name="verticalSpacer_4" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item row="13" column="0" >
<widget class="QLabel" name="label_6" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Information</string>
</property>
</widget>
</item>
<item row="15" column="3" colspan="2" >
<spacer name="verticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="4" >
<widget class="QRadioButton" name="onLedsDefaultColorRadioButton" >
<property name="text" >
<string>Use theme color</string>
</property>
</widget>
</item>
<item row="14" column="1" >
<widget class="QLabel" name="showSecondsLabel" >
<property name="text" >
<string>Seconds:</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="14" column="2" colspan="3" >
<widget class="QCheckBox" name="showSecondHandCheckBox" >
<property name="toolTip" >
<string>Show the seconds LEDs</string>
</property>
<property name="whatsThis" >
<string>Check this if you want to display seconds LEDs in order to see the seconds.</string>
</property>
<property name="text" >
<string>Show</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KColorButton</class>
<extends>QPushButton</extends>
<header>kcolorbutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>onLedsDefaultColorRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>onLedsCustomColorButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>558</x>
<y>55</y>
</hint>
<hint type="destinationlabel" >
<x>423</x>
<y>82</y>
</hint>
</hints>
</connection>
<connection>
<sender>offLedsDefaultColorRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>offLedsCustomColorButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>566</x>
<y>148</y>
</hint>
<hint type="destinationlabel" >
<x>424</x>
<y>172</y>
</hint>
</hints>
</connection>
<connection>
<sender>gridDefaultColorRadioButton</sender>
<signal>toggled(bool)</signal>
<receiver>gridCustomColorButton</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>547</x>
<y>243</y>
</hint>
<hint type="destinationlabel" >
<x>395</x>
<y>267</y>
</hint>
</hints>
</connection>
<connection>
<sender>showOffLedsCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>offLedsDefaultColorRadioButton</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>164</x>
<y>124</y>
</hint>
<hint type="destinationlabel" >
<x>184</x>
<y>147</y>
</hint>
</hints>
</connection>
<connection>
<sender>showOffLedsCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>offLedsCustomColorRadioButton</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>296</x>
<y>120</y>
</hint>
<hint type="destinationlabel" >
<x>296</x>
<y>176</y>
</hint>
</hints>
</connection>
<connection>
<sender>showGridCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>gridDefaultColorRadioButton</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>165</x>
<y>217</y>
</hint>
<hint type="destinationlabel" >
<x>191</x>
<y>238</y>
</hint>
</hints>
</connection>
<connection>
<sender>showGridCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>gridCustomColorRadioButton</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>264</x>
<y>210</y>
</hint>
<hint type="destinationlabel" >
<x>256</x>
<y>268</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,129 @@
[Desktop Entry]
Name=Binary Clock
Name[ar]=ساعة ثنائية
Name[ast]=Reló binariu
Name[bs]=binarni sat
Name[ca]=Rellotge binari
Name[ca@valencia]=Rellotge binari
Name[cs]=Binární hodiny
Name[da]=Binært ur
Name[de]=Binäre Uhr
Name[el]=Δυαδικό ρολόι
Name[en_GB]=Binary Clock
Name[es]=Reloj binario
Name[et]=Binaarkell
Name[eu]=Ordulari bitarra
Name[fi]=Binaarikello
Name[fr]=Horloge binaire
Name[ga]=Clog Dénártha
Name[gl]=Reloxo binario
Name[he]=שעון בִּינָרִי
Name[hr]=Binarni sat
Name[hu]=Bináris óra
Name[is]=Tvíundarklukka
Name[it]=Orologio binario
Name[ja]=
Name[kk]=Бинарлы сағат
Name[km]=
Name[ko]=
Name[ku]=Demjimêra Cot
Name[lt]=Dvejetainis laikrodis
Name[lv]=Binārs pulkstenis
Name[mr]=
Name[nb]=Binær klokke
Name[nds]=Bineerklock
Name[nl]=Binaire klok
Name[nn]=Binærklokke
Name[pa]=
Name[pl]=Zegar dwójkowy
Name[pt]=Relógio Binário
Name[pt_BR]=Relógio binário
Name[ro]=Ceas binar
Name[ru]=Двоичные часы
Name[sk]=Binárne hodiny
Name[sl]=Dvojiška ura
Name[sq]=Orë Bianre
Name[sr]=бинарни сат
Name[sr@ijekavian]=бинарни сат
Name[sr@ijekavianlatin]=binarni sat
Name[sr@latin]=binarni sat
Name[sv]=Binärklocka
Name[th]=
Name[tr]=İkili Saat
Name[uk]=Двійковий годинник
Name[wa]=Ôrlodje binaire
Name[x-test]=xxBinary Clockxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Time displayed in binary format
Comment[ar]=الوقت يظهر بالتنسيق الثنائي
Comment[ast]=Hora amosada en formatu binariu
Comment[bs]=Vrijeme prikazano u binarnom obliku
Comment[ca]=L'hora mostrada en format binari
Comment[ca@valencia]=L'hora mostrada en format binari
Comment[cs]=Zobrazení času v binárním formátu
Comment[da]=Tiden vist i binært format
Comment[de]=Zeitanzeige im Binärformat
Comment[el]=Εμφάνιση της ώρας σε δυαδική μορφή
Comment[en_GB]=Time displayed in binary format
Comment[es]=Hora mostrada en formato binario
Comment[et]=Aja näitamine binaarkujul
Comment[eu]=Ordua formatu bitarrean bistaratuta
Comment[fi]=Binaarimuotoinen ajanesitys
Comment[fr]=Heure affichée au format numérique
Comment[ga]=An t-am i bhformáid dhénártha
Comment[gl]=Mostra a hora no formato binario
Comment[he]=השעה מוצגת בפורמט בִּינָרִי
Comment[hr]=Vrijeme je prikazano u binarnom formatu
Comment[hu]=Bináris formátumban megjelenített idő
Comment[is]=Sýnir tímann á tvíundarformi
Comment[it]=Ora mostrata in formato binario
Comment[ja]=
Comment[kk]=Бинарлы пішімдегі уақыт
Comment[km]=
Comment[ko]=
Comment[ku]=Dem di teşeya cot-bûyî de dê bê nîşandan
Comment[lt]=Laikas rodomas skaitmeniniu formatu
Comment[lv]=Rāda laiku binārā formātā
Comment[mr]= ि ि
Comment[nb]=Tiden vist i binærformat
Comment[nds]=Tiet in Bineerformaat wiest
Comment[nl]=De tijd in binair formaat
Comment[nn]=Klokka vist i binærformat
Comment[pa]= ਿ
Comment[pl]=Czas wyświetlany w formacie dwójkowym
Comment[pt]=Hora mostrada no formato binário
Comment[pt_BR]=Hora exibida em formato binário
Comment[ro]=Ora afișată în format binar
Comment[ru]=Время в двоичной записи
Comment[sk]=Čas zobrazený v binárnom formáte
Comment[sl]=Čas je prikazan v dvojiški obliki
Comment[sr]=Време приказано у бинарном облику
Comment[sr@ijekavian]=Вријеме приказано у бинарном облику
Comment[sr@ijekavianlatin]=Vrijeme prikazano u binarnom obliku
Comment[sr@latin]=Vreme prikazano u binarnom obliku
Comment[sv]=Tid visad med binärformat
Comment[th]=
Comment[tr]=Saati ikili biçimde görüntüle
Comment[uk]=Час, показаний у двійковому форматі
Comment[wa]=Eure håynêye e cogne binaire
Comment[x-test]=xxTime displayed in binary formatxx
Comment[zh_CN]=
Comment[zh_TW]=
Icon=clock
Type=Service
ServiceTypes=Plasma/Applet
X-KDE-Library=plasma_applet_binaryclock
X-KDE-PluginInfo-Author=Davide Bettio
X-KDE-PluginInfo-Email=davide.bettio@kdemail.net
X-KDE-PluginInfo-Name=binaryclock
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Date and Time
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused

View file

@ -0,0 +1,29 @@
# Project needs a name of course
project(blackboard)
# Find the required Libaries
find_package(KDE4 REQUIRED)
include(KDE4Defaults)
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
include_directories(
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${KDE4_INCLUDES}
)
# We add our source code here
set(blackboard_SRCS blackboard.cpp blackboardwidget.cpp)
# Now make sure all files get to the right place
kde4_add_plugin(plasma_applet_blackboard ${blackboard_SRCS})
target_link_libraries(plasma_applet_blackboard
${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS})
install(TARGETS plasma_applet_blackboard
DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-blackboard.desktop
DESTINATION ${SERVICES_INSTALL_DIR})

View file

@ -0,0 +1,95 @@
/***************************************************************************
* Copyright 2009 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 "blackboard.h"
#include <QGraphicsLinearLayout>
#include <KDebug>
#include <KIcon>
#include <Plasma/Theme>
#include <Plasma/ToolButton>
BlackBoard::BlackBoard(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args),
blackBoard(0)
{
setAspectRatioMode(Plasma::IgnoreAspectRatio);
resize(200, 200);
setHasConfigurationInterface(false);
//setBackgroundHints(NoBackground);
}
BlackBoard::~BlackBoard()
{
if (blackBoard) {
blackBoard->saveImage();
}
}
void BlackBoard::init()
{
QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(Qt::Vertical);
blackBoard = new BlackBoardWidget(this);
blackBoard->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
mainLayout->addItem(blackBoard);
buttonsLayout = new QGraphicsLinearLayout(Qt::Horizontal);
addColorButton(QColor(Qt::red));
addColorButton(QColor(Qt::yellow));
addColorButton(QColor(Qt::green));
addColorButton(QColor(Qt::blue));
addColorButton(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
Plasma::ToolButton *eraseB = new Plasma::ToolButton(this);
eraseB->setIcon(KIcon(QLatin1String("edit-delete")));
buttonsLayout->addItem(eraseB);
connect(eraseB, SIGNAL(clicked()), blackBoard, SLOT(erase()));
mainLayout->addItem(buttonsLayout);
setLayout(mainLayout);
}
void BlackBoard::addColorButton(QColor color)
{
QPixmap colorPixmap(22, 22);
colorPixmap.fill(color);
Plasma::ToolButton *tB = new Plasma::ToolButton(this);
tB->setProperty("color", color);
tB->setIcon(colorPixmap);
buttonsLayout->addItem(tB);
connect(tB, SIGNAL(clicked()), this, SLOT(changeColor()));
}
void BlackBoard::changeColor()
{
QObject *sender = QObject::sender();
if (!sender || sender->property("color").type() != QVariant::Color) {
return;
}
blackBoard->setBrushColor(sender->property("color").value<QColor>());
}
#include "blackboard.moc"

View file

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright 2009 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 BLACKBOARD_H
#define BLACKBOARD_H
#include <Plasma/Containment>
#include "blackboardwidget.h"
class QGraphicsLinearLayout;
class BlackBoard : public Plasma::Applet
{
Q_OBJECT
public:
BlackBoard(QObject *parent, const QVariantList &args);
~BlackBoard();
void init();
void addColorButton(QColor color);
private slots:
void changeColor();
private:
BlackBoardWidget *blackBoard;
QGraphicsLinearLayout *buttonsLayout;
};
K_EXPORT_PLASMA_APPLET(blackboard, BlackBoard)
#endif

View file

@ -0,0 +1,182 @@
/***************************************************************************
* Copyright 2009 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 "blackboardwidget.h"
#include <QGraphicsSceneMouseEvent>
#include <QStyleOptionGraphicsItem>
#include <QPainter>
#include <QTimer>
#include <KDebug>
#include <KIO/DeleteJob>
#include <KSaveFile>
#include <KStandardDirs>
#include <Plasma/Applet>
#include <Plasma/Theme>
BlackBoardWidget::BlackBoardWidget(Plasma::Applet *parent)
: QGraphicsWidget(parent)
{
m_changed = false;
setAcceptTouchEvents(true);
m_parentApplet = parent;
m_color = QColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
m_oldPoint = QPointF(-1, 0);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(saveImage()));
timer->start(600000);
QTimer::singleShot(500, this, SLOT(loadImage()));
}
BlackBoardWidget::~BlackBoardWidget()
{
}
void BlackBoardWidget::saveImage()
{
if (m_parentApplet->destroyed()){
KIO::del(imagePath());
}else{
if (m_changed){
KSaveFile imageFile(imagePath());
imageFile.open();
m_pixmap.save(&imageFile, "PNG");
imageFile.finalize();
imageFile.close();
}
}
}
void BlackBoardWidget::loadImage()
{
m_painter.end();
m_pixmap.load(imagePath(), "PNG");
update(contentsRect());
m_painter.begin(&m_pixmap);
m_painter.setPen(QPen(m_color, 3));
}
void BlackBoardWidget::mousePressEvent(QGraphicsSceneMouseEvent *)
{
update(contentsRect());
}
void BlackBoardWidget::drawSegment(QPointF point0, QPointF point1, qreal penRadius)
{
m_painter.setPen(QPen(m_color, penRadius));
m_painter.drawLine(point0, point1);
qreal x = qMin(point0.x(), point1.x()) -(penRadius + 1);
qreal y = qMin(point0.y(), point1.y()) -(penRadius + 1);
qreal w = qMax(point0.x(), point1.x()) + penRadius + 1 - x;
qreal h = qMax(point0.y(), point1.y()) + penRadius + 1 - y;
update(x,y,w,h);
m_changed = true;
}
bool BlackBoardWidget::event(QEvent *event)
{
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd: {
QList<QTouchEvent::TouchPoint> touchPoints = static_cast<QTouchEvent *>(event)->touchPoints();
foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
switch (touchPoint.state()) {
case Qt::TouchPointStationary:
// don't do anything if this touch point hasn't moved
continue;
default:
drawSegment(touchPoint.lastPos(), touchPoint.pos(), 3*touchPoint.pressure());
break;
}
}
break;
}
default:
return QGraphicsWidget::event(event);
}
return true;
}
void BlackBoardWidget::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
QPointF lastPos = event->lastPos();
if (m_oldPoint.x() != -1){
drawSegment(m_oldPoint, lastPos, 1);
}
m_oldPoint = lastPos;
}
void BlackBoardWidget::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
{
mouseMoveEvent(event);
m_oldPoint.setX(-1);
}
void BlackBoardWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
Q_UNUSED(event)
if (m_painter.isActive())
m_painter.end();
QPixmap tmpPixmap = m_pixmap;
m_pixmap = QPixmap(contentsRect().width(), contentsRect().height());
m_pixmap.fill(Qt::transparent);
m_painter.begin(&m_pixmap);
m_painter.drawPixmap(0, 0, tmpPixmap);
m_painter.setPen(QPen(m_color, 3));
}
void BlackBoardWidget::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget)
p->drawPixmap(option->exposedRect, m_pixmap, option->exposedRect);
}
void BlackBoardWidget::setBrushColor(QColor color)
{
m_color = color;
m_painter.setPen(QPen(m_color, 3));
}
void BlackBoardWidget::erase()
{
m_pixmap.fill(Qt::transparent);
update(contentsRect());
KIO::del(imagePath());
}
QString BlackBoardWidget::imagePath()
{
return KStandardDirs::locateLocal("data", QLatin1String("plasma-desktop-datastorage/blackboard-") + QString::number(m_parentApplet->id()) + QLatin1String(".png"));
}
#include "blackboardwidget.moc"

View file

@ -0,0 +1,75 @@
/***************************************************************************
* Copyright 2009 by Davide Bettio <davide.bettio@kdemail.net> *
* *
* 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 BLACKBOARDWIDGET_H
#define BLACKBOARDWIDGET_H
#include <QGraphicsWidget>
#include <QPainter>
#include <QPixmap>
#include <QPointF>
class QGraphicsSceneMouseEvent;
class QStyleOptionGraphicsItem;
namespace Plasma
{
class Applet;
}
class BlackBoardWidget : public QGraphicsWidget
{
Q_OBJECT
public:
BlackBoardWidget(Plasma::Applet *parent);
~BlackBoardWidget();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent ( QGraphicsSceneMouseEvent *event );
void mouseReleaseEvent ( QGraphicsSceneMouseEvent *event );
void resizeEvent(QGraphicsSceneResizeEvent *event);
void setBrushColor(QColor color);
protected:
bool event(QEvent *event);
public Q_SLOTS:
void saveImage();
void erase();
private Q_SLOTS:
void loadImage();
private:
QString imagePath();
void drawSegment(QPointF point0, QPointF point1, qreal penRadius);
bool m_changed;
Plasma::Applet *m_parentApplet;
QString m_id;
QColor m_color;
QPixmap m_pixmap;
QPointF m_oldPoint;
QPainter m_painter;
};
#endif

View file

@ -0,0 +1,110 @@
[Desktop Entry]
Encoding=UTF-8
Name=Black Board
Name[ar]=لوح طباشير
Name[bs]=tabla
Name[ca]=Pissarra
Name[ca@valencia]=Pissarra
Name[cs]=Tabule
Name[da]=Tavle
Name[de]=Tafel
Name[el]=Μαυροπίνακας
Name[en_GB]=Black Board
Name[es]=Pizarra
Name[et]=Tahvel
Name[eu]=Arbela
Name[fi]=Liitutaulu
Name[fr]=Tableau noir
Name[ga]=Clár Dubh
Name[gl]=Encerado
Name[hr]=Školska ploča
Name[hu]=Fekete tábla
Name[it]=Lavagna
Name[ja]=
Name[kk]=Тақта
Name[km]=
Name[ko]=
Name[lt]=Lenta
Name[lv]=Tāfele
Name[mr]=
Name[nb]=Tavle
Name[nds]=Swatt Brett
Name[nl]=Black Board
Name[nn]=Tavle
Name[pa]=
Name[pl]=Czarna tablica
Name[pt]=Quadro Preto
Name[pt_BR]=Quadro negro
Name[ro]=Tablă de scris
Name[ru]=Доска
Name[sk]=Čierna tabuľa
Name[sl]=Tabla
Name[sr]=табла
Name[sr@ijekavian]=табла
Name[sr@ijekavianlatin]=tabla
Name[sr@latin]=tabla
Name[sv]=Svarta tavlan
Name[th]=
Name[tr]=Kara Tahta
Name[uk]=Дошка
Name[wa]=Noer Platea
Name[x-test]=xxBlack Boardxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Draw a quick note or a colorful image
Comment[ar]=ارسم ملاحظة سريعة أو صورة ملونة
Comment[bs]=Napiši brzu napomenu ili obojenu sliku
Comment[ca]=Per dibuixar una nota ràpida o una imatge a tot color
Comment[ca@valencia]=Per dibuixar una nota ràpida o una imatge a tot color
Comment[cs]=Nakreslete rychlou poznámku nebo barevný obrázek
Comment[da]=Tegn en kviknote eller et farverigt billede
Comment[de]=Zeigt eine kurze Notiz oder ein farbiges Bild
Comment[el]=Σχεδιάστε μια γρήγορη σημείωση ή μια χρωματιστή εικόνα
Comment[en_GB]=Draw a quick note or a colourful image
Comment[es]=Dibujar una nota rápida o una imagen a color
Comment[et]=Kiiresti märkuse või värvilise pildi kirjutamine/joonistamine
Comment[fi]=Piirrä pikainen muistiinpano tai värikäs kuva
Comment[fr]=Réaliser une note rapide ou une image colorée
Comment[gl]=Debuxe unha nota rápida ou unha imaxe con moita cor.
Comment[hu]=Gyors jegyzet vagy színes kép rajzolása
Comment[it]=Crea una breve nota o un'immagine colorata
Comment[kk]=Шұғыл жазуды не түрлі-түсті кескінде салу
Comment[ko]=
Comment[mr]= ि ि ि
Comment[nb]=Tegn et raskt notat eller et fargerikt bilde
Comment[nds]=En Kortnotiz oder en klöörriek Bild wiesen
Comment[nl]=Teken een snelle notitie of een kleurrijke afbeelding
Comment[pl]=Rysowanie szybkich notatek lub kolorowych obrazów
Comment[pt]=Desenhar uma nota rápida ou uma imagem colorida
Comment[pt_BR]=Desenha uma nota rápida ou uma imagem colorida
Comment[ro]=Desenează o notă rapidă pe o imagine colorată
Comment[ru]=Быстрая заметка или цветной рисунок
Comment[sk]=Kresliť rýchlu poznámku alebo farebný obrázok
Comment[sl]=Narišite kratko sporočilo ali barvito sliko
Comment[sr]=Нажврљајте брзу белешку или шарену слику
Comment[sr@ijekavian]=Нажврљајте брзу белешку или шарену слику
Comment[sr@ijekavianlatin]=Nažvrljajte brzu belešku ili šarenu sliku
Comment[sr@latin]=Nažvrljajte brzu belešku ili šarenu sliku
Comment[sv]=Skriv en snabb anmärkning eller rita en färgrik bild
Comment[tr]=Hızlı bir not veya renkli bir görüntü çizin
Comment[uk]=Малювання нотатки або кольорового зображення
Comment[x-test]=xxDraw a quick note or a colorful imagexx
Comment[zh_CN]=便
Comment[zh_TW]=
Type=Service
Icon=applications-education
ServiceTypes=Plasma/Applet
X-Plasma-ContainmentCategories=desktop
X-KDE-Library=plasma_applet_blackboard
X-KDE-PluginInfo-Author=Davide Bettio
X-KDE-PluginInfo-Email=davide.bettio@kdemail.net
X-KDE-PluginInfo-Name=blackboard
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Utilities
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused

View file

@ -0,0 +1,18 @@
project( plasma-bookmarks )
set( bookmarks_SRCS
generalconfigeditor.cpp
bookmarksplasmoid.cpp
main.cpp
)
kde4_add_plugin( plasma_applet_bookmarks ${bookmarks_SRCS})
target_link_libraries( plasma_applet_bookmarks
${KDE4_PLASMA_LIBS}
${KDE4_KDEUI_LIBS}
${KDE4_KIO_LIBS}
)
install( TARGETS plasma_applet_bookmarks DESTINATION ${PLUGIN_INSTALL_DIR})
install( FILES plasma-applet-bookmarks.desktop DESTINATION ${SERVICES_INSTALL_DIR} )

View file

@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT *.cpp -o $podir/plasma_applet_bookmarks.pot

View file

@ -0,0 +1,53 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef BOOKMARKOWNER_H
#define BOOKMARKOWNER_H
// KDE
#include <KBookmarkOwner>
#include <KRun>
class BookmarkOwner : public KBookmarkOwner
{
public:
BookmarkOwner();
public: // KBookmarkOwner API
virtual bool enableOption(BookmarkOption) const;
virtual void openBookmark(const KBookmark& bookmark, Qt::MouseButtons, Qt::KeyboardModifiers);
};
inline BookmarkOwner::BookmarkOwner() : KBookmarkOwner() {}
inline bool BookmarkOwner::enableOption(BookmarkOption) const
{
return false;
}
inline void BookmarkOwner::openBookmark(const KBookmark& bookmark, Qt::MouseButtons, Qt::KeyboardModifiers)
{
new KRun(bookmark.url(), (QWidget*)0);
}
#endif

View file

@ -0,0 +1,199 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009-2010 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#include "bookmarksplasmoid.h"
// Plasmoid
#include "generalconfigeditor.h"
#include "bookmarkowner.h"
// Plasma
#include <Plasma/IconWidget>
#include <Plasma/ToolTipManager>
// KDE
#include <KConfigDialog>
#include <KStandardAction>
#include <KIconLoader>
#include <KIcon>
#include <KBookmarkMenu>
#include <KBookmarkGroup>
// Qt
#include <QtGui/QPainter>
#include <QtGui/QGraphicsLinearLayout>
namespace Plasma
{
static const char bookmarkFolderAddressConfigKey[] = "BookmarkFolderAddress";
BookmarksPlasmoid::BookmarksPlasmoid(QObject* parent, const QVariantList& args)
: Applet(parent, args),
mIcon(0),
mBookmarkManager(0),
mBookmarkMenu(0),
mBookmarkOwner(0)
{
}
void BookmarksPlasmoid::init()
{
mBookmarkManager = KBookmarkManager::userBookmarksManager();
mBookmarkManager->setEditorOptions(name(), true);
connect(mBookmarkManager, SIGNAL(changed(QString,QString)), SLOT(onBookmarksChanged(QString)));
// general
setHasConfigurationInterface(true);
connect(this, SIGNAL(activate()), SLOT(toggleMenu()));
Plasma::ToolTipManager::self()->registerWidget(this);
// context menu
KAction* editorOpener = KStandardAction::editBookmarks(this, SLOT(editBookmarks()), this);
mContextualActions.append(editorOpener);
// view
setAspectRatioMode(ConstrainedSquare);
setBackgroundHints(NoBackground);
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
mIcon = new IconWidget(KIcon("bookmarks"),"",this);
mIcon->setFlag(ItemIsMovable, false);
connect(mIcon, SIGNAL(pressed(bool)), SLOT(toggleMenu(bool)));
layout->addItem(mIcon);
configChanged();
}
QList<QAction*> BookmarksPlasmoid::contextualActions()
{
return mContextualActions;
}
void BookmarksPlasmoid::updateFolderData()
{
const KBookmark bookmark = mBookmarkManager->findByAddress(mBookmarkFolderAddress);
KBookmarkGroup bookmarkFolder =
(bookmark.isNull() || ! bookmark.isGroup()) ? mBookmarkManager->root() : bookmark.toGroup();
const bool isRoot = (! bookmarkFolder.hasParent());
const QString iconName = isRoot ? QString::fromLatin1("bookmarks") : bookmarkFolder.icon();
const QString folderName = isRoot ? i18nc("name of the container of all browser bookmarks",
"Bookmarks") :
bookmarkFolder.text();
const QString comment = isRoot ? i18n("Quick access to your bookmarks.") : bookmarkFolder.description();
// icon
mIcon->setIcon(iconName);
// tooltip
Plasma::ToolTipContent toolTipContent(folderName, comment, KIcon(iconName));
Plasma::ToolTipManager::self()->setContent(this, toolTipContent);
}
void BookmarksPlasmoid::toggleMenu(bool toggle)
{
if (! toggle)
return;
Plasma::ToolTipManager::self()->hide(this);
mIcon->setPressed();
const bool isFirstTime = (mBookmarkOwner == 0);
if (isFirstTime)
mBookmarkOwner = new BookmarkOwner();
delete mBookmarkMenu;
KMenu* menu = new KMenu();
menu->setAttribute(Qt::WA_DeleteOnClose);
connect(menu, SIGNAL(aboutToHide()), mIcon, SLOT(setUnpressed()));
// TODO: only renew if manager emits changed
mBookmarkMenu = new KBookmarkMenu(mBookmarkManager, mBookmarkOwner, menu, mBookmarkFolderAddress);
menu->popup(popupPosition(menu->size()));
menu->move(popupPosition(menu->size()));
}
void BookmarksPlasmoid::toggleMenu()
{
toggleMenu(true);
}
void BookmarksPlasmoid::createConfigurationInterface(KConfigDialog* parent)
{
mGeneralConfigEditor = new GeneralConfigEditor(mBookmarkManager, parent);
mGeneralConfigEditor->setBookmarkFolderAddress(mBookmarkFolderAddress);
const QString pageName = i18nc("@title:tab name of settings page with general parameters","General");
parent->addPage(mGeneralConfigEditor, pageName, icon());
connect(parent, SIGNAL(applyClicked()), SLOT(applyConfigChanges()));
connect(parent, SIGNAL(okClicked()), SLOT(applyConfigChanges()));
}
void BookmarksPlasmoid::applyConfigChanges()
{
const QString& bookmarkFolderAddress = mGeneralConfigEditor->bookmarkFolderAddress();
if (mBookmarkFolderAddress != bookmarkFolderAddress) {
KConfigGroup configGroup = config();
configGroup.writeEntry(bookmarkFolderAddressConfigKey, bookmarkFolderAddress);
emit configNeedsSaving();
}
}
void BookmarksPlasmoid::configChanged()
{
// read config
KConfigGroup configGroup = config();
const QString bookmarkFolderAddress = configGroup.readEntry(bookmarkFolderAddressConfigKey, mBookmarkFolderAddress);
if (mBookmarkFolderAddress != bookmarkFolderAddress) {
mBookmarkFolderAddress = bookmarkFolderAddress;
updateFolderData();
}
}
void BookmarksPlasmoid::editBookmarks()
{
mBookmarkManager->slotEditBookmarksAtAddress(mBookmarkFolderAddress);
}
void BookmarksPlasmoid::onBookmarksChanged(const QString& address)
{
Q_UNUSED(address);
updateFolderData();
}
BookmarksPlasmoid::~BookmarksPlasmoid()
{
delete mBookmarkMenu;
delete mBookmarkOwner;
}
}

View file

@ -0,0 +1,85 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef BOOKMARKSPLASMOID_H
#define BOOKMARKSPLASMOID_H
// Plasma
#include <Plasma/Applet>
class GeneralConfigEditor;
class BookmarkOwner;
class KBookmarkMenu;
class KBookmarkManager;
namespace Plasma
{
class IconWidget;
class BookmarksPlasmoid : public Applet
{
Q_OBJECT
public:
BookmarksPlasmoid(QObject* parent, const QVariantList& args);
virtual ~BookmarksPlasmoid();
public: // Plasma::Applet API
virtual void init();
virtual QList<QAction*> contextualActions();
virtual void createConfigurationInterface(KConfigDialog* parent);
public Q_SLOTS:
virtual void configChanged();
protected:
void updateFolderData();
protected Q_SLOTS:
void toggleMenu(bool toggle);
void toggleMenu();
void editBookmarks();
void applyConfigChanges();
void onBookmarksChanged(const QString& address);
private:
QString mBookmarkFolderAddress;
IconWidget* mIcon;
QList<QAction*> mContextualActions;
KBookmarkManager* mBookmarkManager;
KBookmarkMenu* mBookmarkMenu;
BookmarkOwner* mBookmarkOwner;
GeneralConfigEditor* mGeneralConfigEditor;
};
}
#endif

View file

@ -0,0 +1,125 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009-2010 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#include "generalconfigeditor.h"
// KDE
#include <KBookmarkManager>
#include <KBookmarkDialog>
#include <KBookmarkGroup>
#include <KPushButton>
#include <KLocale>
// Qt
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtGui/QLabel>
GeneralConfigEditor::GeneralConfigEditor(KBookmarkManager* bookmarkManager, QWidget* parent)
: QWidget(parent),
mBookmarkFolderAddress(bookmarkManager->root().address()),
mBookmarkManager(bookmarkManager)
{
QVBoxLayout* pageLayout = new QVBoxLayout(this);
pageLayout->setMargin(0);
// folder selection
QHBoxLayout* folderSelectLayout = new QHBoxLayout;
const QString folderSelectLabelText =
i18nc("@label:edit the bookmark folder to show",
"Folder:");
QLabel* label = new QLabel(folderSelectLabelText);
mFolderSelectButton = new KPushButton;
label->setBuddy(mFolderSelectButton);
connect(mFolderSelectButton, SIGNAL(clicked(bool)), SLOT(selectBookmarkFolder()));
const QString folderToolTip =
i18nc("@info:tooltip",
"The folder which will be used as the base for the menu.");
label->setToolTip(folderToolTip);
mFolderSelectButton->setToolTip(folderToolTip);
// const QString folderWhatsThis =
// i18nc( "@info:whatsthis",
// "Select the folder which should be used to in the menu." );
// mFolderSelectButton->setWhatsThis( groupSizeWhatsThis );
folderSelectLayout->addWidget(label);
folderSelectLayout->addWidget(mFolderSelectButton);
folderSelectLayout->addStretch();
pageLayout->addLayout(folderSelectLayout);
pageLayout->addStretch();
connect(mBookmarkManager, SIGNAL(changed(QString,QString)), SLOT(onBookmarksChanged(QString)));
connect(mFolderSelectButton, SIGNAL(clicked(bool)), parent, SLOT(settingsModified()));
updateFolder();
}
void GeneralConfigEditor::setBookmarkFolderAddress(const QString& bookmarkFolderAddress)
{
if (mBookmarkFolderAddress == bookmarkFolderAddress)
return;
mBookmarkFolderAddress = bookmarkFolderAddress;
updateFolder();
}
void GeneralConfigEditor::selectBookmarkFolder()
{
const KBookmark bookmarkFolder = mBookmarkManager->findByAddress(mBookmarkFolderAddress);
KBookmarkDialog* dialog = new KBookmarkDialog(mBookmarkManager, this);
KBookmarkGroup selectedFolder = dialog->selectFolder(bookmarkFolder);
delete dialog;
if (! selectedFolder.isNull()) {
mBookmarkFolderAddress = selectedFolder.address();
updateFolder();
}
}
void GeneralConfigEditor::updateFolder()
{
const KBookmark bookmarkFolder = mBookmarkManager->findByAddress(mBookmarkFolderAddress);
const bool isRoot = (! bookmarkFolder.hasParent());
const QString iconName = isRoot ? QString::fromLatin1("bookmarks") : bookmarkFolder.icon();
const QString folderName = isRoot ? i18nc("name of the container of all browser bookmarks",
"Bookmarks") :
bookmarkFolder.text();
mFolderSelectButton->setIcon(KIcon(iconName));
mFolderSelectButton->setText(folderName);
}
void GeneralConfigEditor::onBookmarksChanged(const QString& address)
{
Q_UNUSED(address);
updateFolder();
}

View file

@ -0,0 +1,69 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
#ifndef GENERALCONFIGEDITOR_H
#define GENERALCONFIGEDITOR_H
// Qt
#include <QtGui/QWidget>
#include <QtCore/QString>
class KBookmarkManager;
class KPushButton;
class GeneralConfigEditor : public QWidget
{
Q_OBJECT
public:
GeneralConfigEditor(KBookmarkManager* bookmarkManager, QWidget* parent);
public: // getter
const QString& bookmarkFolderAddress() const;
public: // setter
void setBookmarkFolderAddress(const QString& bookmarkFolderAddress);
protected:
void updateFolder();
protected Q_SLOTS:
void selectBookmarkFolder();
void onBookmarksChanged(const QString& address);
protected:
QString mBookmarkFolderAddress;
KBookmarkManager* mBookmarkManager;
KPushButton* mFolderSelectButton;
};
inline const QString& GeneralConfigEditor::bookmarkFolderAddress() const
{
return mBookmarkFolderAddress;
}
#endif

View file

@ -0,0 +1,26 @@
/*
This file is part of the Bookmarks plasmoid, part of the KDE project.
Copyright 2009 Friedrich W. H. Kossebau <kossebau@kde.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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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, see <http://www.gnu.org/licenses/>.
*/
// Plasmoid
#include "bookmarksplasmoid.h"
K_EXPORT_PLASMA_APPLET(bookmarks, Plasma::BookmarksPlasmoid)

View file

@ -0,0 +1,122 @@
[Desktop Entry]
Name=Bookmarks
Name[ar]=العلامات
Name[ast]=Marcadores
Name[bs]=obilježivači
Name[ca]=Adreces d'interès
Name[ca@valencia]=Adreces d'interés
Name[cs]=Záložky
Name[da]=Bogmærker
Name[de]=Lesezeichen
Name[el]=Σελιδοδείκτες
Name[en_GB]=Bookmarks
Name[eo]=Legosignoj
Name[es]=Marcadores
Name[et]=Järjehoidjad
Name[eu]=Liburu markak
Name[fi]=Kirjanmerkit
Name[fr]=Signets
Name[ga]=Leabharmharcanna
Name[gl]=Marcadores
Name[hr]=Oznake
Name[hu]=Könyvjelzők
Name[it]=Segnalibri
Name[ja]=
Name[kk]=Бетбелгілер
Name[km]=
Name[ko]=
Name[lt]=Žymelės
Name[lv]=Grāmatzīmes
Name[mr]=ि
Name[nb]=Bokmerker
Name[nds]=Leestekens
Name[nl]=Bladwijzers
Name[nn]=Bokmerke
Name[pa]=
Name[pl]=Zakładki
Name[pt]=Favoritos
Name[pt_BR]=Favoritos
Name[ro]=Semne de carte
Name[ru]=Закладки
Name[sk]=Záložky
Name[sl]=Zaznamki
Name[sr]=обележивачи
Name[sr@ijekavian]=обележивачи
Name[sr@ijekavianlatin]=obeleživači
Name[sr@latin]=obeleživači
Name[sv]=Bokmärken
Name[th]=
Name[tr]=Yer İmleri
Name[ug]=خەتكۈشلەر
Name[uk]=Закладки
Name[wa]=Rimarkes
Name[x-test]=xxBookmarksxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Quick Access to the Bookmarks
Comment[ar]=وصول سريع للعلامات
Comment[ast]=Accesu rápidu a Marcadores
Comment[bs]=Brz pristup do obilježivača
Comment[ca]=Accés ràpid a les adreces d'interès
Comment[ca@valencia]=Accés ràpid a les adreces d'interés
Comment[cs]=Rychlý přístup k záložkám
Comment[da]=Hurtig adgang til bogmærker
Comment[de]=Schnellzugriff auf die Lesezeichen
Comment[el]=Γρήγορη πρόσβαση στους σελιδοδείκτες
Comment[en_GB]=Quick Access to the Bookmarks
Comment[es]=Acceso rápido a los marcadores
Comment[et]=Kiire ligipääs järjehoidjatele
Comment[eu]=Liburu marketara sarbide azkarra
Comment[fi]=Nopea pääsy kirjanmerkkeihin
Comment[fr]=Accès rapide aux signets
Comment[gl]=Acceso rápido aos marcadores.
Comment[hr]=Brzi pristup oznakama
Comment[hu]=Gyors hozzáférés a könyvjelzőkhöz
Comment[it]=Accesso rapido ai segnalibri
Comment[ja]=
Comment[kk]=Бетбелгілерге тез қатынау
Comment[km]=
Comment[ko]=
Comment[lt]=Greita prieiga prie žymių
Comment[lv]=Ātra piekļuve grāmatzīmēm
Comment[mr]=िि
Comment[nb]=Kjapp tilgang til bokmerkene dine
Comment[nds]=Fixtogriep op de Leestekens
Comment[nl]=Snelle toegang tot de bladwijzers
Comment[nn]=Kjapp tilgang til bokmerka
Comment[pa]=
Comment[pl]=Szybki dostęp do zakładek
Comment[pt]=Acesso Rápido aos Favoritos
Comment[pt_BR]=Acesso rápido aos favoritos
Comment[ro]=Acces rapid la semnele de carte
Comment[ru]=Быстрый доступ к закладкам
Comment[sk]=Rýchly prístup k záložkám
Comment[sl]=Hiter dostop do zaznamkov
Comment[sr]=Брз приступ обележивачима
Comment[sr@ijekavian]=Брз приступ обиљеживачима
Comment[sr@ijekavianlatin]=Brz pristup obilježivačima
Comment[sr@latin]=Brz pristup obeleživačima
Comment[sv]=Snabbåtkomst till bokmärken
Comment[th]=
Comment[tr]=Yer İmlerinize Hızlı Erişim
Comment[uk]=Швидкий доступ до закладок
Comment[wa]=Potchî rade dins les rmarkes
Comment[x-test]=xxQuick Access to the Bookmarksxx
Comment[zh_CN]=访
Comment[zh_TW]=
Type=Service
Icon=bookmarks
ServiceTypes=Plasma/Applet
X-KDE-Library=plasma_applet_bookmarks
X-KDE-PluginInfo-Author=Friedrich W. H. Kossebau
X-KDE-PluginInfo-Email=kossebau@kde.org
X-KDE-PluginInfo-Name=bookmarks
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=File System
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Required

View file

@ -0,0 +1,6 @@
project(plasma-applet-bubblemon)
add_subdirectory(src)
add_subdirectory(images)
install(FILES plasma-applet-bubblemon.desktop DESTINATION ${SERVICES_INSTALL_DIR})

View file

@ -0,0 +1 @@
install(FILES bubble.svg DESTINATION ${DATA_INSTALL_DIR}/desktoptheme/default/bubblemon)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 117 KiB

View file

@ -0,0 +1,114 @@
[Desktop Entry]
Encoding=UTF-8
Name=Bubblemon
Name[ar]=Bubblemon
Name[ast]=Bubblemon
Name[bs]=Bubblemon
Name[ca]=Monitor bombolla
Name[ca@valencia]=Monitor bombolla
Name[cs]=Bubblemon
Name[da]=Bobbelmon
Name[de]=Bubblemon
Name[el]=Bubblemon
Name[en_GB]=Bubblemon
Name[eo]=Bubblemon
Name[es]=Bubblemon
Name[et]=Bubblemon
Name[eu]=Bubblemon
Name[fi]=Valvontakupla
Name[fr]=Bubblemon
Name[ga]=Bubblemon
Name[gl]=Bubblemon
Name[hu]=Bubblemon
Name[is]=Bubblemon
Name[it]=Bubblemon
Name[ja]=Bubblemon
Name[kk]=Көпіршік-монитор
Name[km]=Bubblemon
Name[ko]=
Name[lt]=Bubblemon
Name[lv]=Bubblemon
Name[mr]=
Name[nb]=Bubblemon
Name[nds]=Bubblemon
Name[nl]=Bubblemon
Name[nn]=Bobleovervaking
Name[pa]=
Name[pl]=Monitor bąbelkowy
Name[pt]=Bubblemon
Name[pt_BR]=Bubblemon
Name[ro]=Bubblemon
Name[ru]=Пузырьковый монитор
Name[sk]=Bubblemon
Name[sl]=Bubblemon
Name[sq]=Bubblemon
Name[sr]=облакмон
Name[sr@ijekavian]=облакмон
Name[sr@ijekavianlatin]=oblakmon
Name[sr@latin]=oblakmon
Name[sv]=Bubblemon
Name[tr]=Bubblemon
Name[uk]=Bubblemon
Name[wa]=Bubblemon
Name[x-test]=xxBubblemonxx
Name[zh_CN]=Bubblemon
Name[zh_TW]=
Comment=A pretty bubble that monitors your system
Comment[ar]=فقاعة جميلة تراقب نظامك
Comment[bs]=Prijatni balon koji nadzire sistem.
Comment[ca]=Una bombolla graciosa que vigila el sistema
Comment[ca@valencia]=Una bombolla graciosa que vigila el sistema
Comment[cs]=Pěkná bublina monitorující váš systém
Comment[da]=En pæn boble der overvåger dit system
Comment[de]=Eine schicke Blase, die Ihr System überwacht.
Comment[el]=Μια όμορφη φυσαλίδα που εποπτεύει το σύστημά σας.
Comment[en_GB]=A pretty bubble that monitors your system
Comment[es]=Una bonita burbuja que observa su sistema
Comment[et]=Kena mull, mis jälgib süsteemi
Comment[fi]=Sievä järjestelmänvalvontakupla
Comment[fr]=Une jolie bulle supervisant votre système.
Comment[gl]=Unha burbulla que vixía o sistema
Comment[hu]=Rendszerfigyelő buborék
Comment[it]=Una graziosa bolla che controlla il sistema
Comment[kk]=Жүйеңізді бақылайтын ғажайып көпіршік
Comment[ko]=
Comment[nb]=En pen boble som overvåker systemet ditt
Comment[nds]=En smuck Blaas, de Dien Systeem bekieken deit
Comment[nl]=Een prachtige bubbel die uw systeem monitort
Comment[pl]=Uroczy bąbelek, który monitoruje twój system
Comment[pt]=Uma bolha bonita que vigia o seu sistema
Comment[pt_BR]=Uma bonita bolha que monitora o seu sistema
Comment[ro]=Un balon drăguț ce vă monitorizează sistemul
Comment[ru]=Представление загрузки системы в виде пузырьков
Comment[sk]=Pekná bublina, ktorá monitoruje váš systém
Comment[sl]=Lep mehurček, ki nadzira vaš sistem
Comment[sr]=Пријатни балон који надзире систем
Comment[sr@ijekavian]=Пријатни балон који надзире систем
Comment[sr@ijekavianlatin]=Prijatni balon koji nadzire sistem
Comment[sr@latin]=Prijatni balon koji nadzire sistem
Comment[sv]=En snygg bubbla som övervakar systemet
Comment[tr]=Sisteminizi izleyen sevimli bir baloncuk
Comment[uk]=Гарненька бульбашка, яка спостерігає за вашою системою
Comment[x-test]=xxA pretty bubble that monitors your systemxx
Comment[zh_CN]=
Comment[zh_TW]=
ServiceTypes=Plasma/Applet
Type=Service
Icon=utilities-system-monitor
X-KDE-Library=plasma_applet_bubblemon
X-KDE-PluginInfo-Author=Trever Fischer
X-KDE-PluginInfo-Email=tdfischer@fedoraproject.org
X-KDE-PluginInfo-Name=bubblemon
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=System Information
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused
X-Plasma-NotificationArea=true
X-Plasma-DefaultSize=200,200

View file

@ -0,0 +1,9 @@
set(bubblemon_SRCS
bubble.cpp
)
kde4_add_ui_files(bubblemon_SRCS settings.ui)
kde4_add_plugin(plasma_applet_bubblemon ${bubblemon_SRCS})
target_link_libraries(plasma_applet_bubblemon ${KDE4_PLASMA_LIBS})
install(TARGETS plasma_applet_bubblemon DESTINATION ${PLUGIN_INSTALL_DIR})

View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC *.ui >> rc.cpp
$XGETTEXT *.cpp -o $podir/plasma_applet_bubblemon.pot

View file

@ -0,0 +1,531 @@
/*
* Copyright 2009 by Trever Fischer <wm161@wm161.net>
*
* 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, 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 "bubble.h"
#include <QtCore/QTimeLine>
#include <QtCore/QTimer>
#include <QtCore/QPropertyAnimation>
#include <QtGui/QPainter>
#include <QtGui/QStyleOptionGraphicsItem>
#include <QtGui/QGraphicsSceneResizeEvent>
#include <QtGui/QStandardItemModel>
#include <QtGui/QStandardItem>
#include <QtGui/QSortFilterProxyModel>
#include <Plasma/Theme>
#include <Plasma/Svg>
#include <Plasma/ToolTipManager>
#include <Plasma/ToolTipContent>
#include <KDE/KConfigDialog>
#include <KDebug>
K_EXPORT_PLASMA_APPLET(bubblemon, Bubble)
Bubble::Bubble(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args),
m_showText(false),
m_animated(true),
m_val(0),
m_max(0),
m_speed(1000),
m_bubbles(20),
m_bubbleCount(0),
m_labelTransparency(0),
m_rebuildClip(true)
{
m_svg = new Plasma::Svg(this);
m_svg->setImagePath(Plasma::Theme::defaultTheme()->imagePath("bubblemon/bubble"));
connect(m_svg, SIGNAL(repaintNeeded()), this, SLOT(repaintNeeded()));
setAcceptsHoverEvents(true);
setAspectRatioMode(Plasma::Square);
setBackgroundHints(NoBackground);
m_animation = new QPropertyAnimation(this, "labelTransparency", this);
m_animation->setDuration(200);
m_animation->setStartValue(0.0);
m_animation->setEndValue(1.0);
}
Bubble::~Bubble()
{
}
void
Bubble::repaintNeeded()
{
update();
}
void
Bubble::reloadTheme()
{
m_svg->setImagePath(Plasma::Theme::defaultTheme()->imagePath("bubblemon/bubble"));
}
void
Bubble::interpolateValue()
{
m_rebuildClip = true;
update();
}
void
Bubble::init()
{
m_svg->resize(geometry().width(), geometry().height());
m_sensorModel = new QStandardItemModel(this);
connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(reloadTheme()));
m_animator = new QTimer(this);
m_animator->setInterval(75);
connect(m_animator, SIGNAL(timeout()), this, SLOT(moveBubbles()));
m_interpolator = new QTimeLine(m_speed, this);
connect(m_interpolator, SIGNAL(frameChanged(int)), this, SLOT(interpolateValue()));
m_engine = dataEngine("systemmonitor");
if (!m_engine->isValid()) {
setFailedToLaunch(true,
i18nc("@info:status The system monitor data engine could not be found or loaded",
"Could not load the System Monitor data engine."));
} else {
connect(m_engine, SIGNAL(sourceAdded(QString)), this, SLOT(connectSensor()));
}
configChanged();
m_bubbleRect = m_svg->elementSize("bubble");
}
void
Bubble::resizeEvent(QGraphicsSceneResizeEvent *evt)
{
Plasma::Applet::resizeEvent(evt);
qreal size = qMin(contentsRect().size().width(), contentsRect().size().height());
m_svg->resize(size, size);
m_bubbleRect = m_svg->elementSize("bubble");
m_rebuildClip = true;
}
void
Bubble::connectSensor()
{
m_engine->connectSource(m_sensor, this, m_speed);
}
void
Bubble::disconnectSensor()
{
m_engine->disconnectSource(m_sensor, this);
}
void
Bubble::reconnectSensor()
{
disconnectSensor();
connectSensor();
}
void
Bubble::constraintsEvent(Plasma::Constraints constraints)
{
Plasma::Applet::constraintsEvent(constraints);
if (constraints & Plasma::FormFactorConstraint) {
if (formFactor() == Plasma::Horizontal || formFactor() == Plasma::Vertical) {
setPreferredSize(-1,-1);
} else {
setPreferredSize(150, 150);
}
}
if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
setMinimumSize(30,30);
} else {
setMinimumSize(0,0);
}
}
void
Bubble::hoverEnterEvent(QGraphicsSceneHoverEvent *evt)
{
Q_UNUSED(evt)
if (m_showText)
showLabel(true);
}
void
Bubble::hoverLeaveEvent(QGraphicsSceneHoverEvent *evt)
{
Q_UNUSED(evt)
if (m_showText)
showLabel(false);
}
qreal
Bubble::labelTransparency() const
{
return m_labelTransparency;
}
void
Bubble::setLabelTransparency(qreal trans)
{
m_labelTransparency = trans;
update();
}
void
Bubble::showLabel(bool show)
{
if (!show)
m_animation->setDirection(QAbstractAnimation::Backward);
else
m_animation->setDirection(QAbstractAnimation::Forward);
m_animation->start();
}
void
Bubble::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
if (configurationRequired()) {
return;
}
painter->save();
painter->translate(contentsRect.topLeft());
m_svg->paint(painter, m_svg->elementRect("background"), "background");
if (m_max>0 && m_val>0) {
float drawValue;
if (m_animated && !shouldConserveResources())
drawValue = m_interpolator->currentFrame();
else
drawValue = m_val;
if (m_rebuildClip) {
//Clipping the fill is easy. We just stop after some point.
QRectF clipRect(contentsRect);
clipRect.setTop(contentsRect.height()-(contentsRect.height()*((float)drawValue/m_max)));
m_clip = clipRect;
//To clip the individual bubbles, we first build a path of the whole bubble.
//Then we take that path and subtract the empty portion.
//This would be easier of QPainterPath could simply subtract primitives, but alas.
QPainterPath bubbleClipPath;
QPainterPath bubblePath;
QPainterPath filledPath;
QRectF unfilledRect(contentsRect);
unfilledRect.setBottom(clipRect.top());
bubblePath.addEllipse(m_svg->elementRect("fill"));
filledPath.addRect(unfilledRect);
bubbleClipPath = bubblePath - filledPath;
m_bubbleClip = bubbleClipPath;
m_rebuildClip = false;
}
painter->setClipRect(m_clip);
m_svg->paint(painter, m_svg->elementRect("fill"), "fill");
if (m_bubbleCount>0 && m_animated && !shouldConserveResources()) {
painter->setClipPath(m_bubbleClip);
for(int i = 0;i<m_bubbleCount;i++) {
if (m_bubbles.at(i).y()+m_bubbleRect.height()>m_clip.top())
m_svg->paint(painter, QRectF(m_bubbles.at(i), m_bubbleRect), "bubble");
}
}
painter->setClipping(false);
}
m_svg->paint(painter, m_svg->elementRect("glass"), "glass");
if (m_labelTransparency > 0)
drawLabel(painter, option, contentsRect);
painter->restore();
}
void
Bubble::drawLabel(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRectF &contentsRect)
{
Q_UNUSED(option);
QPointF center = contentsRect.center();
QFont font = painter->font();
QFont oldFont = font;
font.setPointSize(font.pointSize()+1);
QRectF labelRect;
do {
font.setPointSize(font.pointSize()-1);
painter->setFont(font);
labelRect = painter->boundingRect(contentsRect,
Qt::TextWordWrap | Qt::AlignCenter | Qt::AlignVCenter, m_label);
labelRect.moveCenter(center);
labelRect.adjust(-3, -3, 3, 3);
} while (labelRect.width() > boundingRect().width() && font.pointSize()>1);
if (font.pointSize()<=1)
return;
painter->setFont(font);
QColor background = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
QColor fontColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
background.setAlphaF(m_labelTransparency);
painter->setPen(background);
background.setAlphaF(m_labelTransparency*0.5);
painter->setBrush(background);
fontColor.setAlphaF(m_labelTransparency);
painter->drawRoundedRect(labelRect, 3, 3);
painter->setPen(fontColor);
painter->drawText(labelRect, Qt::TextWordWrap | Qt::AlignCenter | Qt::AlignVCenter, m_label);
painter->setFont(oldFont);
}
void
Bubble::moveBubbles()
{
if (!boundingRect().isEmpty() && int(m_bubbleRect.height() * m_bubbleCount) > 0 && m_max > 0 && m_animated && !shouldConserveResources()) {
QRectF rect = boundingRect();
QVector<QPoint>::iterator i;
bool needsUpdate = false;
int maxHeight = rect.height()-(m_val/(float)m_max*rect.height()+m_bubbleRect.height());
for(i=m_bubbles.begin();i!=m_bubbles.end();++i) {
(*i).setY((*i).y()-m_bubbleSpeed);
if ((*i).y()<maxHeight-m_bubbleRect.height()) {
(*i).setY(rect.bottom()+(qrand() % (int)( m_bubbleRect.height()*m_bubbleCount ) ) );
(*i).setX(qrand() % (int)rect.width());
needsUpdate = true;
}
if ((*i).y()<rect.bottom() && (*i).y()>maxHeight)
needsUpdate = true;
}
if (needsUpdate)
update();
}
}
QPainterPath
Bubble::shape() const
{
QPainterPath path;
path.addEllipse(boundingRect());
return path;
}
void
Bubble::dataUpdated(QString name, Plasma::DataEngine::Data data)
{
Q_UNUSED(name);
int prev = m_val;
m_val = data["value"].toDouble();
if(prev == m_val)
return;
if (data["max"].toDouble()>0)
m_max = data["max"].toDouble();
else
m_max = qMax(m_max, m_val);
m_label = data["name"].toString();
Plasma::ToolTipContent tip;
tip.setMainText(data["name"].toString());
if (data["units"].toString() == "%")
tip.setSubText(i18nc("@info:status Value as displayed in a percentage format", "%1%", m_val));
else
tip.setSubText(i18nc("@info:status Value for non-percentage units (such as memory usage.)",
"%1%3/%2%3 (%4%)",
KGlobal::locale()->formatNumber(m_val),
KGlobal::locale()->formatNumber(m_max),
data["units"].toString(),
(int)((float)m_val/m_max*100)));
QString section = m_sensor.section('/',0,0);
KIcon tipIcon(icon());
tip.setImage(tipIcon.pixmap(IconSize(KIconLoader::Desktop)));
Plasma::ToolTipManager::self()->setContent(this, tip);
if (m_animated && !shouldConserveResources()) {
m_bubbleCount = ((float)m_val/(float)m_max)*20;
/*int bubbleCount;
if (m_max>0)
bubbleCount = ((float)m_val/(float)m_max)*20;
else
bubbleCount = 0;*/
/*while(m_bubbles.size()<bubbleCount)
m_bubbles.append(QPoint(0, 0));
while(m_bubbles.size()>bubbleCount)
m_bubbles.removeLast();*/
m_bubbleSpeed = (boundingRect().height()/20)*((float)m_val/m_max)*3;
m_interpolator->stop();
m_interpolator->setFrameRange(prev, m_val);
m_interpolator->start();
}
int lower = qMin(m_val, prev);
int upper = qMax(m_val, prev);
//formula taken fron Bubble::paintInterface
QRect toUpdate(0, geometry().height()-(geometry().height()*((float)upper/m_max)),
geometry().width(), geometry().height()-(geometry().height()*((float)lower/m_max)) );
m_rebuildClip = true;
update(toUpdate);
}
QString
Bubble::icon() const
{
QString section = m_sensor.section('/',0,0);
if (section == "cpu")
return "cpu";
if (section == "mem")
return "media-flash";
if (section == "system")
return "computer";
if (section == "partitions" || section == "disk")
return "drive-harddisk";
if (section == "network")
return "network-wired";
if (section == "acpi")
return "battery";
if (section == "lmsensors")
return "media-flash";
return "utilities-system-monitor";
}
void
Bubble::createConfigurationInterface(KConfigDialog* dlg)
{
QWidget *page = new QWidget(dlg);
ui.setupUi(page);
m_sensorModel->clear();
QStandardItem *sensorItem;
QModelIndex currentSensor;
foreach(const QString &sensor, m_engine->sources()) {
Plasma::DataEngine::Data sensorData = m_engine->query(sensor);
sensorItem = new QStandardItem(sensorData["name"].toString());
sensorItem->setData(sensor);
sensorItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
m_sensorModel->appendRow(sensorItem);
if (sensor == m_sensor) {
currentSensor = m_sensorModel->indexFromItem(sensorItem);
}
}
QSortFilterProxyModel *proxy = new QSortFilterProxyModel(m_sensorModel);
proxy->setSourceModel(m_sensorModel);
ui.sensorView->setModel(proxy);
if (currentSensor.isValid()) {
ui.sensorView->selectionModel()->setCurrentIndex(currentSensor, QItemSelectionModel::ClearAndSelect);
ui.sensorView->scrollTo(currentSensor, QAbstractItemView::PositionAtTop);
}
ui.searchBox->setProxy(proxy);
dlg->addPage(page, i18nc("@title:group Title for the bubblemon settings page","General"), icon());
connect(dlg, SIGNAL(applyClicked()), this, SLOT(writeConfig()));
connect(dlg, SIGNAL(okClicked()), this, SLOT(writeConfig()));
ui.animateBubbles->setChecked(m_animated ? Qt::Checked : Qt::Unchecked);
ui.showText->setChecked(m_showText ? Qt::Checked : Qt::Unchecked);
ui.updateSpeed->setValue(m_speed);
connect(ui.updateSpeed, SIGNAL(valueChanged(int)), dlg, SLOT(settingsModified()));
connect(ui.animateBubbles, SIGNAL(toggled(bool)), dlg, SLOT(settingsModified()));
connect(ui.showText, SIGNAL(toggled(bool)), dlg, SLOT(settingsModified()));
connect(ui.sensorView, SIGNAL(activated(QModelIndex)), dlg, SLOT(settingsModified()));
}
void
Bubble::writeConfig()
{
KConfigGroup cg = config();
bool changed = false;
if (m_animated != ui.animateBubbles->isChecked()) {
changed = true;
cg.writeEntry("animated", ui.animateBubbles->isChecked());
}
if (m_showText != ui.showText->isChecked()) {
changed = true;
cg.writeEntry("showText", ui.showText->isChecked());
}
if (m_speed != ui.updateSpeed->value()) {
changed = true;
cg.writeEntry("speed", ui.updateSpeed->value());
}
QItemSelectionModel *selection = ui.sensorView->selectionModel();
const QString sensor = selection->currentIndex().data(Qt::UserRole+1).toString();
if (m_sensor != sensor) {
changed = true;
cg.writeEntry("sensor", sensor);
setConfigurationRequired(false);
}
if (changed) {
emit configNeedsSaving();
m_rebuildClip = true;
}
}
void
Bubble::configChanged()
{
KConfigGroup cg = config();
m_animated = cg.readEntry("animated", true);
m_showText = cg.readEntry("showText", false);
showLabel(m_showText);
const int oldSpeed = m_speed;
m_speed = cg.readEntry("speed", m_speed);
m_interpolator->setDuration(m_speed);
const QString sensor = cg.readEntry("sensor", m_sensor);
if (m_sensor != sensor) {
if (!m_sensor.isEmpty()) {
disconnectSensor();
}
m_sensor = sensor;
connectSensor();
} else if (oldSpeed != m_speed && !m_sensor.isEmpty()) {
reconnectSensor();
}
if (m_sensor.isEmpty())
setConfigurationRequired(true);
if (m_animated)
m_animator->start();
else
m_animator->stop();
update();
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 2009 by Trever Fischer <wm161@wm161.net>
*
* 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, 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 BUBBLE_H
#define BUBBLE_H
#include <Plasma/Applet>
#include <Plasma/DataEngine>
#include "ui_settings.h"
class QTimeLine;
class QGraphicsSceneResizeEvent;
class QTimer;
class QStandardItemModel;
class QPropertyAnimation;
namespace Plasma {
class Svg;
}
class Bubble : public Plasma::Applet {
Q_OBJECT
Q_PROPERTY(qreal labelTransparency READ labelTransparency WRITE setLabelTransparency)
public:
Bubble(QObject *parent, const QVariantList &args);
~Bubble();
void paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect);
void init();
void createConfigurationInterface(KConfigDialog *parent);
QString icon() const;
void setLabelTransparency(qreal);
qreal labelTransparency() const;
public slots:
void dataUpdated(QString name, Plasma::DataEngine::Data data);
void configChanged();
protected:
QPainterPath shape() const;
void constraintsEvent(Plasma::Constraints constraints);
void resizeEvent(QGraphicsSceneResizeEvent *evt);
protected slots:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
private slots:
void writeConfig();
void moveBubbles();
void showLabel(bool);
void interpolateValue();
void connectSensor();
void reconnectSensor();
void disconnectSensor();
void reloadTheme();
void repaintNeeded();
private:
void drawLabel(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRectF &contentsRect);
Ui::Settings ui;
bool m_showText;
bool m_animated;
int m_val;
int m_max;
int m_speed;
QVector<QPoint> m_bubbles;
int m_bubbleCount;
qreal m_labelTransparency;
float m_bubbleSpeed;
QSizeF m_bubbleRect;
QString m_sensor;
Plasma::Svg *m_svg;
QString m_label;
QTimer *m_animator;
QTimeLine *m_interpolator;
Plasma::DataEngine *m_engine;
QStandardItemModel *m_sensorModel;
QPropertyAnimation *m_animation;
QRectF m_clip;
QPainterPath m_bubbleClip;
bool m_rebuildClip;
};
#endif

View file

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings</class>
<widget class="QWidget" name="Settings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>391</width>
<height>294</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Data</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>25</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Update every:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KIntNumInput" name="updateSpeed">
<property name="label">
<string/>
</property>
<property name="value">
<number>100</number>
</property>
<property name="minimum">
<number>50</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="suffix">
<string> ms</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>118</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Sensors:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>sensorView</cstring>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="KFilterProxySearchLine" name="searchBox"/>
</item>
<item row="3" column="3" rowspan="2">
<widget class="QListView" name="sensorView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>10</verstretch>
</sizepolicy>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Appearance</string>
</property>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Animated:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>animateBubbles</cstring>
</property>
</widget>
</item>
<item row="7" column="3">
<widget class="QCheckBox" name="animateBubbles">
<property name="text">
<string comment="@option:check Whether the plasmoid is animated or not"/>
</property>
</widget>
</item>
<item row="8" column="1" colspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Show text:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>showText</cstring>
</property>
</widget>
</item>
<item row="8" column="3">
<widget class="QCheckBox" name="showText">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KFilterProxySearchLine</class>
<extends>QWidget</extends>
<header>kfilterproxysearchline.h</header>
</customwidget>
<customwidget>
<class>KIntNumInput</class>
<extends>QWidget</extends>
<header>knuminput.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,8 @@
project(plasma-calculator)
install(DIRECTORY package/
DESTINATION ${DATA_INSTALL_DIR}/plasma/plasmoids/calculator)
install(FILES package/metadata.desktop
DESTINATION ${SERVICES_INSTALL_DIR}
RENAME plasma-applet-calculator.desktop)

View file

@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT `find . -name \*.qml` -o $podir/plasma_applet_calculator.pot

View file

@ -0,0 +1,394 @@
/*****************************************************************************
* Copyright (C) 2012 by Davide Bettio <davide.bettio@kdemail.net> *
* Copyright (C) 2012 by Luiz Romário Santana Rios <luizromario@gmail.com> *
* Copyright (C) 2007 by Henry Stanaland <stanaland@gmail.com> *
* Copyright (C) 2008 by Laurent Montel <montel@kde.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 . *
*****************************************************************************/
import QtQuick 1.0;
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.locale 0.1 as Locale
Item {
id: main;
property int minimumWidth: 200;
property int minimumHeight: 250;
property int buttonHeight: (height - displayFrame.height - 6 * buttonsGrid.spacing) / 5;
property int buttonWidth: (width / 4) - buttonsGrid.spacing;
property real result: 0;
property bool hasResult: false;
property bool showingInput: true;
property bool showingResult: false;
property string operator: undefined;
property real operand: 0;
property bool commaPressed: false;
property int decimals: 0;
property int inputSize: 0;
property int maxInputLength: 15; // More than that and the number notation turns scientific
// (i.e.: 1.32324e+12)
Keys.onDigit0Pressed: { digitClicked(0); }
Keys.onDigit1Pressed: { digitClicked(1); }
Keys.onDigit2Pressed: { digitClicked(2); }
Keys.onDigit3Pressed: { digitClicked(3); }
Keys.onDigit4Pressed: { digitClicked(4); }
Keys.onDigit5Pressed: { digitClicked(5); }
Keys.onDigit6Pressed: { digitClicked(6); }
Keys.onDigit7Pressed: { digitClicked(7); }
Keys.onDigit8Pressed: { digitClicked(8); }
Keys.onDigit9Pressed: { digitClicked(9); }
Keys.onEscapePressed: { allClearClicked(); }
Keys.onDeletePressed: { clearClicked(); }
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Plus:
setOperator("+");
break;
case Qt.Key_Minus:
setOperator("-");
break;
case Qt.Key_Asterisk:
setOperator("*");
break;
case Qt.Key_Slash:
setOperator("/");
break;
case Qt.Key_Period:
decimalClicked();
break;
case Qt.Key_Equal:
case Qt.Key_Return:
case Qt.Key_Enter:
equalsClicked();
break;
default:
break;
}
}
function digitClicked(digit) {
if (inputSize >= maxInputLength) {
return;
}
if (showingResult) {
allClearClicked();
}
if (commaPressed) {
++decimals;
tenToTheDecimals = Math.pow(10, decimals);
operand = (operand * tenToTheDecimals + digit) / tenToTheDecimals;
} else {
operand = operand * 10 + digit;
}
display.text = operand;
showingInput = true;
++inputSize;
}
function decimalClicked() {
if (showingResult) {
allClearClicked();
}
commaPressed = true;
showingInput = true;
}
function doOperation() {
switch (operator) {
case "+":
result += operand;
break;
case "-":
result -= operand;
break;
case "*":
result *= operand;
break;
case "/":
result /= operand;
break;
default:
return;
}
display.text = algarismCount(result * Math.pow(10, decimals)) > maxInputLength?
"E" : result;
showingInput = false;
}
function clearOperand() {
operand = 0;
commaPressed = false;
decimals = 0;
inputSize = 0;
}
function setOperator(op) {
if (!hasResult) {
result = operand;
hasResult = true;
} else if (showingInput) {
doOperation();
}
clearOperand();
operator = op;
showingResult = false;
}
function equalsClicked() {
showingResult = true;
doOperation();
}
function clearClicked() {
clearOperand();
operator = "";
display.text = operand;
showingInput = true;
showingResult = false;
}
function allClearClicked() {
clearClicked();
result = 0;
hasResult = false;
}
function algarismCount(number) {
return number == 0? 1 :
Math.floor(Math.log(Math.abs(number))/Math.log(10)) + 1;
}
Locale.Locale {
id: locale;
}
PlasmaCore.Theme {
id: plasmaTheme;
}
Connections {
target: plasmoid;
onPopupEvent: {
main.focus = true;
}
}
Column {
focus: true;
spacing: 4;
PlasmaCore.FrameSvgItem {
id: displayFrame;
width: buttonsGrid.width;
height: 2 * display.font.pixelSize;
imagePath: "widgets/frame";
prefix: "sunken";
TextEdit {
id: display;
anchors {
fill: parent;
margins: parent.margins.right;
}
text: "0";
font.pointSize: 16;
font.weight: Font.Bold;
color: plasmaTheme.viewTextColor;
horizontalAlignment: TextEdit.AlignRight;
verticalAlignment: TextEdit.AlignVCenter;
readOnly: true;
}
}
Grid {
id: buttonsGrid;
columns: 4;
rows: 5;
spacing: 4;
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the clear button", "C");
onClicked: clearClicked();
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the division button", "÷");
onClicked: setOperator("/");
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the multiplication button", "×");
onClicked: setOperator("*");
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the all clear button", "AC");
onClicked: allClearClicked();
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "7";
onClicked: digitClicked(7);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "8";
onClicked: digitClicked(8);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "9";
onClicked: digitClicked(9);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the minus button", "-");
onClicked: setOperator("-");
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "4";
onClicked: digitClicked(4);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "5";
onClicked: digitClicked(5);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "6";
onClicked: digitClicked(6);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: i18nc("Text of the plus button", "+");
onClicked: setOperator("+");
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "1";
onClicked: digitClicked(1);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "2";
onClicked: digitClicked(2);
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: "3";
onClicked: digitClicked(3);
}
Item {
id: ansPlaceHolder;
width: buttonWidth;
height: buttonHeight;
}
Item {
id: zeroPlaceHolder;
width: buttonWidth;
height: buttonHeight;
}
Item {
id: zeroPlaceHolder2;
width: buttonWidth;
height: buttonHeight;
}
PlasmaComponents.Button {
width: buttonWidth;
height: buttonHeight;
text: locale.decimalSymbol;
onClicked: decimalClicked();
}
Item {
id: ansPlaceHolder2;
width: buttonWidth;
height: buttonHeight;
}
}
}
PlasmaComponents.Button {
width: buttonWidth * 2 + buttonsGrid.spacing;
height: buttonHeight;
x: zeroPlaceHolder.x + buttonsGrid.x;
y: zeroPlaceHolder.y + buttonsGrid.y;
text: "0";
onClicked: digitClicked(0);
}
PlasmaComponents.Button {
id: ansButton;
width: buttonWidth;
height: buttonHeight * 2 + buttonsGrid.spacing;
x: ansPlaceHolder.x + buttonsGrid.x;
y: ansPlaceHolder.y + buttonsGrid.y;
text: i18nc("Text of the equals button", "=");
onClicked: equalsClicked();
}
}

View file

@ -0,0 +1,135 @@
[Desktop Entry]
Name=Calculator
Name[ar]=آلة حاسبة
Name[ast]=Calculadora
Name[bs]=kalkulator
Name[ca]=Calculadora
Name[ca@valencia]=Calculadora
Name[cs]=Kalkulačka
Name[da]=Lommeregner
Name[de]=Rechner
Name[el]=Αριθμομηχανή
Name[en_GB]=Calculator
Name[eo]=Kalkulilo
Name[es]=Calculadora
Name[et]=Kalkulaator
Name[eu]=Kalkulagailua
Name[fi]=Laskin
Name[fr]=Calculatrice
Name[ga]=Áireamhán
Name[gl]=Calculadora
Name[he]=מחשבון
Name[hr]=Kalkulator
Name[hu]=Számológép
Name[is]=Reiknivél
Name[it]=Calcolatrice
Name[ja]=
Name[kk]=Калькулятор
Name[km]=
Name[ko]=
Name[ku]=Makîneya Hesaban
Name[lt]=Skaičiuotuvas
Name[lv]=Kalkulators
Name[mr]=
Name[nb]=Kalkulator
Name[nds]=Taschenreekner
Name[nl]=Rekenmachine
Name[nn]=Kalkulator
Name[oc]=Calculeta
Name[pa]=
Name[pl]=Kalkulator
Name[pt]=Calculadora
Name[pt_BR]=Calculadora
Name[ro]=Calculator
Name[ru]=Калькулятор
Name[sk]=Kalkulačka
Name[sl]=Računalo
Name[sq]=Makina Llogaritëse
Name[sr]=калкулатор
Name[sr@ijekavian]=калкулатор
Name[sr@ijekavianlatin]=kalkulator
Name[sr@latin]=kalkulator
Name[sv]=Miniräknare
Name[th]=
Name[tr]=Hesap Makinesi
Name[ug]=ھېسابلىغۇچ
Name[uk]=Калькулятор
Name[wa]=Carculete
Name[x-test]=xxCalculatorxx
Name[zh_CN]=
Name[zh_TW]=
Comment=Calculate simple sums
Comment[ar]=احسب عمليات جمع بسيطة
Comment[ast]=Calcular sumes simples
Comment[bs]=Izračunajte jednostavne izraze
Comment[ca]=Calcula sumes senzilles
Comment[ca@valencia]=Calcula sumes senzilles
Comment[cs]=Jednoduché sčítání
Comment[da]=Beregn simple summer.
Comment[de]=Für kleine Rechenaufgaben
Comment[el]=Υπολογισμός απλών πράξεων
Comment[en_GB]=Calculate simple sums
Comment[es]=Calcular sumas sencillas
Comment[et]=Lihtne kalkulaator
Comment[eu]=Gehiketa errazak kalkulatu
Comment[fi]=Laske yksinkertaisia laskuja
Comment[fr]=Calcule des sommes simples
Comment[ga]=Áirigh suimeanna simplí
Comment[gl]=Calcula sumas simples
Comment[he]=מחשב סכומים פשוטים
Comment[hr]=Izračunaj jednostavne sume
Comment[hu]=Egyszerű számológép
Comment[is]=Reiknar einfaldar aðgerðir
Comment[it]=Calcola semplici somme
Comment[ja]=
Comment[kk]=Қарапайым есептерді шығару
Comment[km]=
Comment[ko]=
Comment[ku]=Berhevkirinên hêsan hesab bike
Comment[lt]=Skaičiuoti paprastas sumas
Comment[lv]=Aprēķina vienkāršas summas
Comment[mr]=
Comment[nb]=Regn ut enkle regnestykker
Comment[nds]=Eenfache Saken utreken
Comment[nl]=Eenvoudige berekeningen
Comment[nn]=Grafisk kalkulator
Comment[pa]=
Comment[pl]=Obliczanie prostych sum
Comment[pt]=Calcular somas simples
Comment[pt_BR]=Calcula funções matemáticas básicas
Comment[ro]=Calculează sume simple
Comment[ru]=Вычисление простых выражений
Comment[sk]=Výpočet jednoduchých súm
Comment[sl]=Izračuna preproste vsote
Comment[sr]=Израчунајте једноставне изразе
Comment[sr@ijekavian]=Израчунајте једноставне изразе
Comment[sr@ijekavianlatin]=Izračunajte jednostavne izraze
Comment[sr@latin]=Izračunajte jednostavne izraze
Comment[sv]=Beräkna enkla summor
Comment[th]=
Comment[tr]=Basit hesaplamalar yapın
Comment[uk]=Обчисліть прості суми
Comment[wa]=Cårculez des ptits carculs
Comment[x-test]=xxCalculate simple sumsxx
Comment[zh_CN]=
Comment[zh_TW]=
Icon=accessories-calculator
Type=Service
ServiceTypes=Plasma/Applet,Plasma/PopupApplet
X-KDE-Library=plasma_applet_calculator
X-KDE-PluginInfo-Author=Henry Stanaland
X-KDE-PluginInfo-Email=stanaland@gmail.com
X-KDE-PluginInfo-Name=calculator
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Utilities
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-API=declarativeappletscript
X-Plasma-DefaultSize=200,250
X-Plasma-MainScript=ui/calculator.qml
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused

View file

@ -0,0 +1,12 @@
project(charselect)
set(charselect_SRCS charselect.cpp)
kde4_add_plugin(plasma_applet_charselect ${charselect_SRCS})
target_link_libraries(plasma_applet_charselect ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS})
install(TARGETS plasma_applet_charselect
DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-charselect.desktop
DESTINATION ${SERVICES_INSTALL_DIR})

View file

@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT *.cpp -o $podir/plasma_applet_CharSelectApplet.pot

View file

@ -0,0 +1,92 @@
/***************************************************************************
* Copyright 2008 by Laurent Montel <montel@kde.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 "charselect.h"
#include <QClipboard>
#include <QApplication>
#include <KCharSelect>
#include <KLineEdit>
#include <KPushButton>
#include <QGridLayout>
#include <plasma/widgets/iconwidget.h>
CharSelectApplet::CharSelectApplet(QObject *parent, const QVariantList &args)
: Plasma::PopupApplet(parent, args),
m_mainWidget(0)
{
setPopupIcon(QLatin1String("accessories-character-map"));
}
CharSelectApplet::~CharSelectApplet()
{
delete m_mainWidget;
}
void CharSelectApplet::constraintsEvent(Plasma::Constraints constraints)
{
if (constraints & Plasma::StartupCompletedConstraint) {
if (size().width() < widget()->size().width() ||
size().height() < widget()->size().height()) {
resize(widget()->size());
emit appletTransformedItself();
}
}
}
QWidget *CharSelectApplet::widget()
{
if (!m_mainWidget) {
m_mainWidget = new QWidget;
m_mainWidget->setAttribute(Qt::WA_NoSystemBackground);
QGridLayout *layout = new QGridLayout(m_mainWidget);
m_charselect = new KCharSelect(m_mainWidget, 0, KCharSelect::BlockCombos|KCharSelect::CharacterTable|KCharSelect::FontCombo);
m_charselect->setMinimumSize(300, 250);
connect( m_charselect, SIGNAL(charSelected(QChar)), this, SLOT(slotCharSelect(QChar)) );
layout->addWidget( m_charselect, 0, 0, 1, 2);
m_lineEdit = new KLineEdit(m_mainWidget);
m_lineEdit->setReadOnly( true );
layout->addWidget( m_lineEdit, 1, 0 );
m_addToClipboard = new KPushButton(m_mainWidget);
m_addToClipboard->setText( i18n( "&Add to Clipboard" ) );
connect( m_addToClipboard, SIGNAL(clicked()), this, SLOT(slotAddToClipboard()) );
layout->addWidget( m_addToClipboard, 1, 1 );
}
return m_mainWidget;
}
void CharSelectApplet::slotAddToClipboard()
{
const QString textLine = m_lineEdit->text();
QClipboard *cb = QApplication::clipboard();
cb->setText( textLine,QClipboard::Clipboard );
cb->setText( textLine,QClipboard::Selection );
}
void CharSelectApplet::slotCharSelect( const QChar &c )
{
m_lineEdit->setText( c );
}
#include "charselect.moc"

View file

@ -0,0 +1,56 @@
/***************************************************************************
* Copyright 2008 by Laurent Montel <montel@kde.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 CHARSELECT_H
#define CHARSELECT_H
#include <Plasma/PopupApplet>
class KCharSelect;
class QGraphicsGridLayout;
class KLineEdit;
class KPushButton;
class CharSelectApplet : public Plasma::PopupApplet
{
Q_OBJECT
public:
CharSelectApplet(QObject *parent, const QVariantList &args);
virtual ~CharSelectApplet();
virtual QWidget *widget();
protected:
void constraintsEvent(Plasma::Constraints);
public slots:
void slotAddToClipboard();
void slotCharSelect( const QChar &c );
private:
QWidget *m_mainWidget;
KCharSelect *m_charselect;
QGraphicsGridLayout *m_layout;
KLineEdit *m_lineEdit;
KPushButton *m_addToClipboard;
};
K_EXPORT_PLASMA_APPLET(CharSelectApplet, CharSelectApplet)
#endif

View file

@ -0,0 +1,131 @@
[Desktop Entry]
Encoding=UTF-8
Name=Character Selector
Name[ar]=مختار الأحرف
Name[ast]=Seleutor de caráuter
Name[bs]=birač znakova
Name[ca]=Selector de caràcters
Name[ca@valencia]=Selector de caràcters
Name[cs]=Výběr znaků
Name[da]=Tegnvælger
Name[de]=Tabelle zur Zeichenauswahl
Name[el]=Επιλογέας χαρακτήρων
Name[en_GB]=Character Selector
Name[eo]=Elektilo por signoj
Name[es]=Selector de caracteres
Name[et]=Sümbolivalija
Name[eu]=Karaktere hautatzailea
Name[fi]=Merkkivalitsin
Name[fr]=Sélecteur de caractères
Name[ga]=Roghnóir Carachtar
Name[gl]=Selector de caracteres
Name[he]=בוחר התווים
Name[hr]=Birač znakova
Name[hu]=Karakterválasztó
Name[is]=Stafaval
Name[it]=Selettore dei caratteri
Name[ja]=
Name[kk]=Таңба таңдағышы
Name[km]=
Name[ko]=
Name[ku]=Bijarkerê Tîpan
Name[lt]=Simbolių parinkiklis
Name[lv]=Rakstzīmju atlasītājs
Name[mr]= ि
Name[nb]=Tegnvelger
Name[nds]=Tekenköör
Name[nl]=Speciale tekens
Name[nn]=Teiknveljar
Name[pa]=
Name[pl]=Wybór znaków
Name[pt]=Selector de Caracteres
Name[pt_BR]=Seletor de caracteres
Name[ro]=Selector caractere
Name[ru]=Выбор символа
Name[sk]=Výber znakov
Name[sl]=Izbirnik znakov
Name[sq]=Zgjedhës i Gërmave
Name[sr]=бирач знакова
Name[sr@ijekavian]=бирач знакова
Name[sr@ijekavianlatin]=birač znakova
Name[sr@latin]=birač znakova
Name[sv]=Teckenväljare
Name[th]=
Name[tr]=Karakter Seçici
Name[ug]=ھەرپ تاللىغۇچ
Name[uk]=Таблиця символів
Name[wa]=Tchoezixheu di caracteres
Name[x-test]=xxCharacter Selectorxx
Name[zh_CN]=
Name[zh_TW]=
Comment=View, select, and copy characters from a font collection
Comment[ar]=أظهر، واختر، و انسخ محارف من مجموعة الخط
Comment[ast]=Ver, esbillar y copiar carauteres d'una colección de fontes de lletra
Comment[bs]=Gledajte, birajte i kopirajte znakove iz zbirke fontova
Comment[ca]=Mostra, selecciona i copia caràcters d'una col·lecció de tipus de lletra
Comment[ca@valencia]=Mostra, selecciona i copia caràcters d'una col·lecció de tipus de lletra
Comment[cs]=Zobrazení, výběr a kopírování znaků ze sbírky písem
Comment[da]=Se, udvælg og kopiér tegn fra en skrifttypesamling.
Comment[de]=Zeichen aus einer Sammlung ansehen, auswählen oder kopieren
Comment[el]=Προβολή, επιλογή και αντιγραφή χαρακτήρων από μια συλλογή γραμματοσειρών
Comment[en_GB]=View, select, and copy characters from a font collection
Comment[es]=Ver, seleccionar y copiar caracteres de una colección de tipos de letra
Comment[et]=Fondikogude märkide näitamine, valimine ja kopeerimine
Comment[eu]=Letra-tipo bilduma batetik karaktereak ikusi, hautatu, eta kopiatu
Comment[fi]=Katso, valitse ja kopioi merkkejä fonttivalikoimasta
Comment[fr]=Permet d'afficher, de sélectionner et de copier des caractères
Comment[ga]=Féach ar, roghnaigh, agus cóipeáil carachtair ó bhailiúchán clónna
Comment[gl]=Ver, escoller e copiar caracteres dunha colección de tipografías
Comment[he]=הצג, בחר והעתק תווים מתוך אוסף גופנים
Comment[hr]=Prikaži, odaberi i kopiraj znakove iz kolekcije pisama
Comment[hu]=Karakterek megjelenítése, kiválasztása és másolása a betűkészlet-gyűjteményből
Comment[is]=Skoða, velja og afrita stafi úr letursafni
Comment[it]=Vedi, seleziona e copia caratteri da una collezione di caratteri
Comment[ja]=
Comment[kk]=Қаріп жинағынан таңбаларды қарау, таңдау және көшіріп алу
Comment[km]=
Comment[ko]= , ,
Comment[ku]=Jê berhevoka cure-nivîsê tîpan bibîne, hilbijêre û ji ber bigire
Comment[lt]=Žiūrėti, pasirinkti ir kopijuoti simbolius iš šriftų kolekcijos
Comment[lv]=Apskatiet, izvēlieties un kopējiet rakstzīmes no fontu kolekcijas
Comment[mr]= , ि
Comment[nb]=Vis, velg og kopier tegn fra en samling skrifter
Comment[nds]=Tekens ut en Schriftoordensammlen ankieken, utsöken un koperen
Comment[nl]=Toon, selecteer en kopieer tekens van een lettertypecollectie
Comment[nn]=Vis, merk og kopier teikn frå skrifter
Comment[pa]= ਿ ,
Comment[pl]=Przeglądanie, wybieranie i kopiowanie znaków ze zbioru czcionek
Comment[pt]=Ver, seleccionar e copiar caracteres de uma colecção de tipos de letra
Comment[pt_BR]=Exibe, seleciona e copia caracteres de uma coleção de fontes
Comment[ro]=Vizualizează, alege și copiază caractere dintr-o colecție de fonturi
Comment[ru]=Просмотр, выбор и копирование символов из коллекции шрифтов
Comment[sk]=Zobrazenie, výber a kopírovanie znakov z kolekcie písiem
Comment[sl]=Oglejte si, izberite in kopirajte znake iz zbirke pisav
Comment[sr]=Гледајте, бирајте и копирајте знакове из збирке фонтова
Comment[sr@ijekavian]=Гледајте, бирајте и копирајте знакове из збирке фонтова
Comment[sr@ijekavianlatin]=Gledajte, birajte i kopirajte znakove iz zbirke fontova
Comment[sr@latin]=Gledajte, birajte i kopirajte znakove iz zbirke fontova
Comment[sv]=Visa, markera och kopiera tecken från en samling teckensnitt
Comment[th]=,
Comment[tr]=Bir yazı tipi koleksiyonundan karakterleri seçin, kopyalayın ve görüntüleyin
Comment[uk]=Перегляньте, оберіть і скопіюйте символи зі збірки шрифтів
Comment[wa]=Vey, tchoezi eyet copyî des caracteres a pårti d' ene ramexhnêye di fontes
Comment[x-test]=xxView, select, and copy characters from a font collectionxx
Comment[zh_CN]=
Comment[zh_TW]=
Type=Service
Icon=accessories-character-map
ServiceTypes=Plasma/Applet
X-KDE-Library=plasma_applet_charselect
X-KDE-PluginInfo-Author=Laurent Montel
X-KDE-PluginInfo-Email=montel@kde.org
X-KDE-PluginInfo-Name=charselect
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Utilities
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Unused
X-Plasma-Requires-LaunchApp=Unused

View file

@ -0,0 +1,40 @@
project(plasma-comic)
if(HAVE_NEPOMUK)
add_definitions(-DHAVE_NEPOMUK)
add_definitions(-DDISABLE_NEPOMUK_LEGACY)
endif(HAVE_NEPOMUK)
set(comic_SRCS
comic.cpp
comicmodel.cpp
configwidget.cpp
comicarchivejob.cpp
comicarchivedialog.cpp
checknewstrips.cpp
comicdata.cpp
comicinfo.cpp
comicsaver.cpp
stripselector.cpp
activecomicmodel.cpp
)
kde4_add_ui_files(comic_SRCS
comicSettings.ui
appearanceSettings.ui
advancedsettings.ui
comicarchivedialog.ui
)
kde4_add_plugin(plasma_applet_comic ${comic_SRCS})
target_link_libraries(plasma_applet_comic ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${KDE4_SOLID_LIBS} ${KDE4_KIO_LIBS} ${KDE4_KNEWSTUFF3_LIBS} ${QT_QTDECLARATIVE_LIBRARY})
if(HAVE_NEPOMUK)
target_link_libraries(plasma_applet_comic ${NEPOMUK_LIBRARIES} ${NEPOMUK_UTILS_LIBRARIES} ${SOPRANO_LIBRARIES})
endif(HAVE_NEPOMUK)
install(TARGETS plasma_applet_comic DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-comic-default.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(FILES comic.knsrc DESTINATION ${CONFIG_INSTALL_DIR})
install(DIRECTORY package/ DESTINATION ${DATA_INSTALL_DIR}/plasma/packages/org.kde.comic)

View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC *.ui >> rc.cpp
$XGETTEXT *.cpp `find . -name '*.qml'` -o $podir/plasma_applet_comic.pot

View file

@ -0,0 +1,63 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "activecomicmodel.h"
ActiveComicModel::ActiveComicModel(QObject *parent)
: QStandardItemModel(0, 1, parent)
{
QHash<int, QByteArray> newRoleNames = roleNames();
newRoleNames[ComicKeyRole] = "key";
newRoleNames[ComicTitleRole] = "title";
newRoleNames[ComicIconRole] = "icon";
newRoleNames[ComicHighlightRole] = "highlight";
setRoleNames(newRoleNames);
connect(this, SIGNAL(modelReset()),
this, SIGNAL(countChanged()));
connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)),
this, SIGNAL(countChanged()));
connect(this, SIGNAL(rowsRemoved(QModelIndex, int, int)),
this, SIGNAL(countChanged()));
}
void ActiveComicModel::addComic(const QString &key, const QString &title, const QString &iconPath, bool highlight)
{
QList<QStandardItem *> newRow;
QStandardItem *item = new QStandardItem(title);
item->setData(key, ComicKeyRole);
item->setData(title, ComicTitleRole);
item->setData(iconPath, ComicIconRole);
item->setData(highlight, ComicHighlightRole);
newRow << item;
appendRow(newRow);
}
QVariantHash ActiveComicModel::get(int row) const
{
QModelIndex idx = index(row, 0);
QVariantHash hash;
QHash<int, QByteArray>::const_iterator i;
for (i = roleNames().constBegin(); i != roleNames().constEnd(); ++i) {
hash[i.value()] = data(idx, i.key());
}
return hash;
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTIVE_COMIC_MODEL_H
#define ACTIVE_COMIC_MODEL_H
#include <QtGui/QtGui>
#include <QtCore/QtCore>
class ActiveComicModel : public QStandardItemModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
enum Roles {
ComicKeyRole = Qt::UserRole+1,
ComicTitleRole = Qt::UserRole+2,
ComicIconRole = Qt::UserRole+3,
ComicHighlightRole = Qt::UserRole+4
};
ActiveComicModel(QObject *parent = 0);
void addComic(const QString &key, const QString &title, const QString &iconPath, bool highlight = true);
int count() { return rowCount(QModelIndex()); }
Q_INVOKABLE QVariantHash get(int i) const;
Q_SIGNALS:
void countChanged();
};
#endif

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdvancedSettings</class>
<widget class="QWidget" name="AdvancedSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>468</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string comment="refers to caching of files on the users hd">Cache</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="1">
<widget class="QSpinBox" name="maxComicLimit">
<property name="minimum">
<number>0</number>
</property>
<property name="suffix">
<string> strips per comic</string>
</property>
<property name="specialValueText">
<string>No size limit</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Comic cache:</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Error Handling</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Display error image when getting comic failed:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="errorPicture">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AppearanceSettings</class>
<widget class="QWidget" name="AppearanceSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>280</width>
<height>182</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<layout class="QFormLayout" name="formLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Show arrows only on &amp;hover:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>checkBox_arrows</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBox_arrows">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Information</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Show comic &amp;title:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>checkBox_title</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBox_title">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Show comic &amp;identifier:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>checkBox_identifier</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBox_identifier">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Show comic &amp;author:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>checkBox_author</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkBox_author">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Show comic &amp;URL:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>checkBox_url</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkBox_url">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="KButtonGroup" name="kbuttongroup">
<property name="title">
<string/>
</property>
<property name="flat">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KButtonGroup</class>
<extends>QGroupBox</extends>
<header>kbuttongroup.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>checkBox_arrows</tabstop>
<tabstop>checkBox_title</tabstop>
<tabstop>checkBox_identifier</tabstop>
<tabstop>checkBox_author</tabstop>
<tabstop>checkBox_url</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,79 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "checknewstrips.h"
#include <QtCore/QTimer>
CheckNewStrips::CheckNewStrips( const QStringList &identifiers, Plasma::DataEngine *engine, int minutes, QObject *parent)
: QObject( parent ),
mMinutes( minutes ),
mIndex( 0 ),
mEngine( engine ),
mIdentifiers( identifiers )
{
QTimer *timer = new QTimer( this );
timer->setInterval( minutes * 60 * 1000 );
connect( timer, SIGNAL(timeout()), this, SLOT(start()) );
timer->start();
//start at once, that way the user does not have to wait for minutes to get the initial result
start();
}
void CheckNewStrips::dataUpdated( const QString &source, const Plasma::DataEngine::Data &data )
{
QString lastIdentifierSuffix;
if ( !data[ "Error" ].toBool() ) {
lastIdentifierSuffix = data[ "Identifier" ].toString();
lastIdentifierSuffix.remove( source );
}
mEngine->disconnectSource( source, this );
if ( !lastIdentifierSuffix.isEmpty() ) {
QString temp = source;
temp.remove( ':' );
emit lastStrip( mIndex, temp, lastIdentifierSuffix );
}
++mIndex;
if ( mIndex < mIdentifiers.count() ) {
const QString newSource = mIdentifiers[mIndex] + ':';
mEngine->connectSource( newSource, this );
mEngine->query( newSource );
} else {
mIndex = 0;
}
}
void CheckNewStrips::start()
{
//already running, do nothing
if ( mIndex ) {
return;
}
if ( mIndex < mIdentifiers.count() ) {
const QString newSource = mIdentifiers[mIndex] + ':';
mEngine->connectSource( newSource, this );
mEngine->query( newSource );
}
}

View file

@ -0,0 +1,58 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 CHECK_NEW_STRIPS_H
#define CHECK_NEW_STRIPS_H
#include <Plasma/DataEngine>
/**
* This class searches for the newest comic strips of predefined comics in a defined intervall.
* Once found it emits lastStrip
*/
class CheckNewStrips : public QObject
{
Q_OBJECT
public:
CheckNewStrips( const QStringList &identifiers, Plasma::DataEngine *engine, int minutes, QObject *parent = 0 );
signals:
/**
* @param index of the identifier in identifiers
* @param identifier of the comic
* @param suffix of the last comic strip
* @see CheckNewStrips
*/
void lastStrip( int index, const QString &identifier, const QString &suffix );
public slots:
void dataUpdated( const QString &name, const Plasma::DataEngine::Data &data );
private slots:
void start();
private:
int mMinutes;
int mIndex;
Plasma::DataEngine *mEngine;
const QStringList mIdentifiers;
};
#endif

View file

@ -0,0 +1,804 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008 by Marco Martin <notmart@gmail.com> *
* Copyright (C) 2008-2011 Matthias Fuchs <mat69@gmx.net> *
* Copyright (C) 2012 Reza Fatahilah Shah <rshah0385@kireihana.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "comic.h"
#include "comicarchivedialog.h"
#include "comicarchivejob.h"
#include "checknewstrips.h"
#include "stripselector.h"
#include "comicsaver.h"
#include <QtCore/QTimer>
#include <QtGui/QGraphicsLinearLayout>
#include <QtGui/QGraphicsScene>
#include <QtGui/QGraphicsView>
#include <QtGui/QGraphicsSceneMouseEvent>
#include <QtGui/QGraphicsSceneWheelEvent>
#include <QtGui/QSortFilterProxyModel>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeContext>
#include <KAction>
#include <KConfigDialog>
#include <KDebug>
#include <KNotification>
#include <kuiserverjobtracker.h>
#include <KRun>
#include <KStandardShortcut>
#include <Plasma/Containment>
#include <Plasma/DeclarativeWidget>
#include <Plasma/Package>
#include "comicmodel.h"
#include "configwidget.h"
K_GLOBAL_STATIC( ComicUpdater, globalComicUpdater )
const int ComicApplet::CACHE_LIMIT = 20;
ComicApplet::ComicApplet( QObject *parent, const QVariantList &args )
: Plasma::PopupApplet( parent, args ),
mActiveComicModel(parent),
mDifferentComic( true ),
mShowComicUrl( false ),
mShowComicAuthor( false ),
mShowComicTitle( false ),
mShowComicIdentifier( false ),
mShowErrorPicture( true ),
mArrowsOnHover( true ),
mMiddleClick( true ),
mCheckNewStrips( 0 ),
mDeclarativeWidget( 0 ),
mActionShop( 0 ),
mEngine( 0 ),
mSavingDir(0)
{
setHasConfigurationInterface( true );
resize( 600, 250 );
setAspectRatioMode( Plasma::IgnoreAspectRatio );
setPopupIcon( "face-smile-big" );
}
void ComicApplet::init()
{
globalComicUpdater->init( globalConfig() );
mSavingDir = new SavingDir(config());
configChanged();
//QML
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
mDeclarativeWidget = new Plasma::DeclarativeWidget(this);
layout->addItem(mDeclarativeWidget);
mDeclarativeWidget->engine()->rootContext()->setContextProperty("comicApplet", this);
Plasma::PackageStructure::Ptr structure = Plasma::PackageStructure::load("Plasma/Generic");
Plasma::Package package(QString(), "org.kde.comic", structure);
mDeclarativeWidget->setQmlPath(package.filePath("mainscript"));
//End of QML
mEngine = dataEngine( "comic" );
mModel = new ComicModel( mEngine->query( "providers" ), mTabIdentifier, this );
mProxy = new QSortFilterProxyModel( this );
mProxy->setSourceModel( mModel );
mProxy->setSortCaseSensitivity( Qt::CaseInsensitive );
mProxy->sort( 1, Qt::AscendingOrder );
//set maximum number of cached strips per comic, -1 means that there is no limit
KConfigGroup global = globalConfig();
//convert old values
if ( global.hasKey( "useMaxComicLimit" ) ) {
const bool use = global.readEntry( "useMaxComicLimit", false );
if ( !use ) {
global.writeEntry( "maxComicLimit", 0 );
}
global.deleteEntry( "useMaxComicLimit" );
}
const int maxComicLimit = global.readEntry( "maxComicLimit", CACHE_LIMIT );
mEngine->query( QLatin1String( "setting_maxComicLimit:" ) + QString::number( maxComicLimit ) );
mCurrentDay = QDate::currentDate();
mDateChangedTimer = new QTimer( this );
connect( mDateChangedTimer, SIGNAL(timeout()), this, SLOT(checkDayChanged()) );
mDateChangedTimer->setInterval( 5 * 60 * 1000 ); // every 5 minutes
mActionNextNewStripTab = new KAction( KIcon( "go-next-view" ), i18nc( "here strip means comic strip", "&Next Tab with a new Strip" ), this );
mActionNextNewStripTab->setShortcut( KStandardShortcut::openNew() );
addAction( "next new strip" , mActionNextNewStripTab );
mActions.append( mActionNextNewStripTab );
connect( mActionNextNewStripTab, SIGNAL(triggered(bool)), this, SIGNAL(showNextNewStrip()) );
mActionGoFirst = new QAction( KIcon( "go-first" ), i18n( "Jump to &first Strip" ), this );
mActions.append( mActionGoFirst );
connect( mActionGoFirst, SIGNAL(triggered(bool)), this, SLOT(slotFirstDay()) );
mActionGoLast = new QAction( KIcon( "go-last" ), i18n( "Jump to &current Strip" ), this );
mActions.append( mActionGoLast );
connect( mActionGoLast, SIGNAL(triggered(bool)), this, SLOT(slotCurrentDay()) );
mActionGoJump = new QAction( KIcon( "go-jump" ), i18n( "Jump to Strip ..." ), this );
mActions.append( mActionGoJump );
connect( mActionGoJump, SIGNAL(triggered(bool)), this, SLOT(slotGoJump()) );
if ( hasAuthorization( "LaunchApp" ) ) {
mActionShop = new QAction( i18n( "Visit the shop &website" ), this );
mActionShop->setEnabled( false );
mActions.append( mActionShop );
connect( mActionShop, SIGNAL(triggered(bool)), this, SLOT(slotShop()) );
}
if ( hasAuthorization( "FileDialog" ) ) {
QAction *action = new QAction( KIcon( "document-save-as" ), i18n( "&Save Comic As..." ), this );
mActions.append( action );
connect( action, SIGNAL(triggered(bool)), this , SLOT(slotSaveComicAs()) );
}
if ( hasAuthorization( "FileDialog" ) ) {
QAction *action = new QAction( KIcon( "application-epub+zip" ), i18n( "&Create Comic Book Archive..." ), this );
mActions.append( action );
connect( action, SIGNAL(triggered(bool)), this, SLOT(createComicBook()) );
}
mActionScaleContent = new QAction( KIcon( "zoom-original" ), i18nc( "@option:check Context menu of comic image", "&Actual Size" ), this );
mActionScaleContent->setCheckable( true );
mActionScaleContent->setChecked( mCurrent.scaleComic() );
mActions.append( mActionScaleContent );
connect( mActionScaleContent, SIGNAL(triggered(bool)), this , SLOT(slotScaleToContent()) );
mActionStorePosition = new QAction( KIcon( "go-home" ), i18nc( "@option:check Context menu of comic image", "Store current &Position" ), this);
mActionStorePosition->setCheckable( true );
mActionStorePosition->setChecked(mCurrent.hasStored());
mActions.append( mActionStorePosition );
connect( mActionStorePosition, SIGNAL(triggered(bool)), this, SLOT(slotStorePosition()) );
//make sure that tabs etc. are displayed even if the comic strip in the first tab does not work
updateView();
updateUsedComics();
changeComic( true );
}
ComicApplet::~ComicApplet()
{
delete mSavingDir;
}
QGraphicsWidget *ComicApplet::graphicsWidget()
{
return mDeclarativeWidget;
}
void ComicApplet::dataUpdated( const QString &source, const Plasma::DataEngine::Data &data )
{
//disconnect prefetched comic strips
if ( source != mOldSource ) {
mEngine->disconnectSource( source, this );
return;
}
setBusy( false );
setConfigurationRequired( false );
//there was an error, display information as image
const bool hasError = data[ "Error" ].toBool();
const bool errorAutoFixable = data[ "Error automatically fixable" ].toBool();
if ( hasError ) {
const QString previousIdentifierSuffix = data[ "Previous identifier suffix" ].toString();
if ( !mShowErrorPicture && !previousIdentifierSuffix.isEmpty() ) {
mEngine->disconnectSource( source, this );
updateComic( previousIdentifierSuffix );
return;
}
}
mCurrent.setData(data);
setAssociatedApplicationUrls(mCurrent.websiteUrl());
//looking at the last index, thus not mark it as new
KConfigGroup cg = config();
if (!mCurrent.hasNext() && mCheckNewComicStripsIntervall) {
setTabHighlighted( mCurrent.id(), false );
mActionNextNewStripTab->setEnabled( hasHighlightedTabs() );
}
//call the slot to check if the position needs to be saved
slotStorePosition();
//disconnect if there is either no error, or an error that can not be fixed automatically
if ( !errorAutoFixable ) {
mEngine->disconnectSource( source, this );
}
//prefetch the previous and following comic for faster navigation
if (mCurrent.hasNext()) {
const QString prefetch = mCurrent.id() + ':' + mCurrent.next();
mEngine->connectSource( prefetch, this );
mEngine->query( prefetch );
}
if ( mCurrent.hasPrev()) {
const QString prefetch = mCurrent.id() + ':' + mCurrent.prev();
mEngine->connectSource( prefetch, this );
mEngine->query( prefetch );
}
updateView();
refreshComicData();
}
void ComicApplet::updateView()
{
updateContextMenu();
}
void ComicApplet::createConfigurationInterface( KConfigDialog *parent )
{
mConfigWidget = new ConfigWidget( dataEngine( "comic" ), mModel, mProxy, parent );
mConfigWidget->setShowComicUrl( mShowComicUrl );
mConfigWidget->setShowComicAuthor( mShowComicAuthor );
mConfigWidget->setShowComicTitle( mShowComicTitle );
mConfigWidget->setShowComicIdentifier( mShowComicIdentifier );
mConfigWidget->setShowErrorPicture( mShowErrorPicture );
mConfigWidget->setArrowsOnHover( mArrowsOnHover );
mConfigWidget->setMiddleClick( mMiddleClick );
mConfigWidget->setCheckNewComicStripsIntervall( mCheckNewComicStripsIntervall );
//not storing this value, since other applets might have changed it inbetween
KConfigGroup global = globalConfig();
const int maxComicLimit = global.readEntry( "maxComicLimit", CACHE_LIMIT );
mConfigWidget->setMaxComicLimit( maxComicLimit );
const int updateIntervall = global.readEntry( "updateIntervall", 3 );
mConfigWidget->setUpdateIntervall( updateIntervall );
parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
parent->addPage( mConfigWidget->comicSettings, i18n( "General" ), icon() );
parent->addPage( mConfigWidget->appearanceSettings, i18n( "Appearance" ), "image" );
parent->addPage( mConfigWidget->advancedSettings, i18n( "Advanced" ), "system-run" );
connect( parent, SIGNAL(applyClicked()), this, SLOT(applyConfig()) );
connect( parent, SIGNAL(okClicked()), this, SLOT(applyConfig()) );
connect(mConfigWidget, SIGNAL(enableApply()), parent, SLOT(settingsModified()));
}
void ComicApplet::applyConfig()
{
setShowComicUrl(mConfigWidget->showComicUrl());
setShowComicAuthor(mConfigWidget->showComicAuthor());
setShowComicTitle(mConfigWidget->showComicTitle());
setShowComicIdentifier(mConfigWidget->showComicIdentifier());
setShowErrorPicture(mConfigWidget->showErrorPicture());
setArrowsOnHover(mConfigWidget->arrowsOnHover());
setMiddleClick(mConfigWidget->middleClick());
mCheckNewComicStripsIntervall = mConfigWidget->checkNewComicStripsIntervall();
//not storing this value, since other applets might have changed it inbetween
KConfigGroup global = globalConfig();
const int oldMaxComicLimit = global.readEntry( "maxComicLimit", CACHE_LIMIT );
const int maxComicLimit = mConfigWidget->maxComicLimit();
if ( oldMaxComicLimit != maxComicLimit ) {
global.writeEntry( "maxComicLimit", maxComicLimit );
mEngine->query( QLatin1String( "setting_maxComicLimit:" ) + QString::number( maxComicLimit ) );
}
globalComicUpdater->applyConfig( mConfigWidget );
updateUsedComics();
saveConfig();
//make sure that tabs etc. are displayed even if the comic strip in the first tab does not work
updateView();
changeComic( mDifferentComic );
}
void ComicApplet::changeComic( bool differentComic )
{
if ( differentComic ) {
KConfigGroup cg = config();
mActionStorePosition->setChecked(mCurrent.storePosition());
// assign mScaleComic the moment the new strip has been loaded (dataUpdated) as up to this point
// the old one should be still shown with its scaling settings
mActionScaleContent->setChecked( mCurrent.scaleComic() );
updateComic( mCurrent.stored() );
} else {
updateComic( mCurrent.current() );
}
}
void ComicApplet::updateUsedComics()
{
const QString oldIdentifier = mCurrent.id();
mActiveComicModel.clear();
mTabIdentifier.clear();
mCurrent = ComicData();
bool isFirst = true;
QModelIndex data;
KConfigGroup cg = config();
int tab = 0;
for ( int i = 0; i < mProxy->rowCount(); ++i ) {
if ( mProxy->index( i, 0 ).data( Qt::CheckStateRole) == Qt::Checked ) {
data = mProxy->index( i, 1 );
if ( isFirst ) {
isFirst = false;
const QString id = data.data( Qt::UserRole ).toString();
mDifferentComic = ( oldIdentifier != id );
const QString title = data.data().toString();
mCurrent.init(id, config());
mCurrent.setTitle(title);
}
const QString name = data.data().toString();
const QString identifier = data.data( Qt::UserRole ).toString();
const QString iconPath = data.data( Qt::DecorationRole ).value<QIcon>().name();
//found a newer strip last time, which was not visited
if ( mCheckNewComicStripsIntervall && !cg.readEntry( "lastStripVisited_" + identifier, true ) ) {
mActiveComicModel.addComic(identifier, name, iconPath, true);
} else {
mActiveComicModel.addComic(identifier, name, iconPath);
}
mTabIdentifier << identifier;
++tab;
}
}
mActionNextNewStripTab->setVisible( mCheckNewComicStripsIntervall );
mActionNextNewStripTab->setEnabled( hasHighlightedTabs() );
delete mCheckNewStrips;
mCheckNewStrips = 0;
if ( mCheckNewComicStripsIntervall ) {
mCheckNewStrips = new CheckNewStrips( mTabIdentifier, mEngine, mCheckNewComicStripsIntervall, this );
connect( mCheckNewStrips, SIGNAL(lastStrip(int,QString,QString)), this, SLOT(slotFoundLastStrip(int,QString,QString)) );
}
emit comicModelChanged();
}
void ComicApplet::slotTabChanged(const QString &identifier)
{
bool differentComic = (mCurrent.id() != identifier);
mCurrent = ComicData();
mCurrent.init(identifier, config());
changeComic( differentComic );
}
void ComicApplet::checkDayChanged()
{
if ( ( mCurrentDay != QDate::currentDate() ) || !mCurrent.hasImage() )
updateComic( mCurrent.stored() );
mCurrentDay = QDate::currentDate();
}
void ComicApplet::configChanged()
{
KConfigGroup cg = config();
mTabIdentifier = cg.readEntry( "tabIdentifier", QStringList( QString() ) );
const QString id = mTabIdentifier.count() ? mTabIdentifier.at( 0 ) : QString();
mCurrent = ComicData();
mCurrent.init(id, cg);
mShowComicUrl = cg.readEntry( "showComicUrl", false );
mShowComicAuthor = cg.readEntry( "showComicAuthor", false );
mShowComicTitle = cg.readEntry( "showComicTitle", false );
mShowComicIdentifier = cg.readEntry( "showComicIdentifier", false );
mShowErrorPicture = cg.readEntry( "showErrorPicture", true );
mArrowsOnHover = cg.readEntry( "arrowsOnHover", true );
mMiddleClick = cg.readEntry( "middleClick", true );
mCheckNewComicStripsIntervall = cg.readEntry( "checkNewComicStripsIntervall", 30 );
//use a decent default size
const QSizeF tempMaxSize = isInPanel() ? QSizeF( 600, 250 ) : this->size();
mMaxSize = cg.readEntry( "maxSize", tempMaxSize );
mLastSize = mMaxSize;
globalComicUpdater->load();
}
void ComicApplet::saveConfig()
{
KConfigGroup cg = config();
cg.writeEntry( "comic", mCurrent.id() );
cg.writeEntry( "showComicUrl", mShowComicUrl );
cg.writeEntry( "showComicAuthor", mShowComicAuthor );
cg.writeEntry( "showComicTitle", mShowComicTitle );
cg.writeEntry( "showComicIdentifier", mShowComicIdentifier );
cg.writeEntry( "showErrorPicture", mShowErrorPicture );
cg.writeEntry( "arrowsOnHover", mArrowsOnHover );
cg.writeEntry( "middleClick", mMiddleClick );
cg.writeEntry( "tabIdentifier", mTabIdentifier );
cg.writeEntry( "checkNewComicStripsIntervall", mCheckNewComicStripsIntervall );
globalComicUpdater->save();
}
void ComicApplet::slotNextDay()
{
updateComic(mCurrent.next());
}
void ComicApplet::slotPreviousDay()
{
updateComic(mCurrent.prev());
}
void ComicApplet::slotFirstDay()
{
updateComic(mCurrent.first());
}
void ComicApplet::slotCurrentDay()
{
updateComic(QString());
}
void ComicApplet::slotFoundLastStrip( int index, const QString &identifier, const QString &suffix )
{
KConfigGroup cg = config();
if ( suffix != cg.readEntry( "lastStrip_" + identifier, QString() ) ) {
kDebug() << identifier << "has a newer strip.";
setTabHighlighted( identifier, true );
cg.writeEntry( "lastStripVisited_" + identifier, false );
}
mActionNextNewStripTab->setEnabled( hasHighlightedTabs() );
}
void ComicApplet::slotGoJump()
{
StripSelector *selector = StripSelectorFactory::create(mCurrent.type());
connect(selector, SIGNAL(stripChosen(QString)), this, SLOT(updateComic(QString)));
selector->select(mCurrent);
}
void ComicApplet::slotStorePosition()
{
mCurrent.storePosition(mActionStorePosition->isChecked());
}
void ComicApplet::slotShop()
{
KRun::runUrl(mCurrent.shopUrl(), "text/html", 0);
}
bool ComicApplet::isInPanel() const
{
return ( this->geometry().width() < 70 ) || ( this->geometry().height() < 50 );
}
void ComicApplet::createComicBook()
{
ComicArchiveDialog *dialog = new ComicArchiveDialog(mCurrent.id(), mCurrent.title(), mCurrent.type(), mCurrent.current(),
mCurrent.first(), mSavingDir->getDir());
dialog->setAttribute(Qt::WA_DeleteOnClose);//to have destroyed emitted upon closing
connect( dialog, SIGNAL(archive(int,KUrl,QString,QString)), this, SLOT(slotArchive(int,KUrl,QString,QString)) );
dialog->show();
}
void ComicApplet::slotArchive( int archiveType, const KUrl &dest, const QString &fromIdentifier, const QString &toIdentifier )
{
mSavingDir->setDir(dest.directory());
const QString id = mCurrent.id();
kDebug() << "Archiving:" << id << archiveType << dest << fromIdentifier << toIdentifier;
ComicArchiveJob *job = new ComicArchiveJob(dest, mEngine, static_cast< ComicArchiveJob::ArchiveType >( archiveType ), mCurrent.type(), id, this);
job->setFromIdentifier(id + ':' + fromIdentifier);
job->setToIdentifier(id + ':' + toIdentifier);
if (job->isValid()) {
connect(job, SIGNAL(finished(KJob*)), this, SLOT(slotArchiveFinished(KJob*)));
KIO::getJobTracker()->registerJob(job);
job->start();
} else {
kWarning() << "Archiving job is not valid.";
delete job;
}
}
void ComicApplet::slotArchiveFinished (KJob *job )
{
if ( job->error() ) {
KNotification::event( KNotification::Warning, i18n( "Archiving comic failed" ), job->errorText(), KIcon( "dialog-warning" ).pixmap( KIconLoader::SizeMedium ) );
}
}
QList<QAction*> ComicApplet::contextualActions()
{
return mActions;
}
QSizeF ComicApplet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
if (which != Qt::PreferredSize) {
return Applet::sizeHint(which, constraint);
} else {
QSize imageSize = mCurrent.image().size();
if (!imageSize.isEmpty()) {
return imageSize;
} else {
return Applet::sizeHint(which, constraint);
}
}
}
void ComicApplet::updateComic( const QString &identifierSuffix )
{
mEngine = dataEngine( "comic" );
const QString id = mCurrent.id();
setConfigurationRequired( id.isEmpty() );
if ( !id.isEmpty() && mEngine && mEngine->isValid() ) {
setBusy( true );
const QString identifier = id + ':' + identifierSuffix;
//disconnecting of the oldSource is needed, otherwise you could get data for comics you are not looking at if you use tabs
//if there was an error only disconnect the oldSource if it had nothing to do with the error or if the comic changed, that way updates of the error can come in
if ( !mIdentifierError.isEmpty() && !mIdentifierError.contains( id ) ) {
mEngine->disconnectSource( mIdentifierError, this );
mIdentifierError.clear();
}
if ( ( mIdentifierError != mOldSource ) && ( mOldSource != identifier ) ) {
mEngine->disconnectSource( mOldSource, this );
}
mOldSource = identifier;
mEngine->disconnectSource( identifier, this );
mEngine->connectSource( identifier, this );
const Plasma::DataEngine::Data data = mEngine->query( identifier );
if ( data[ "Error" ].toBool() ) {
dataUpdated( QString(), data );
}
} else {
kError() << "Either no identifier was specified or the engine could not be created:" << "id" << id << "engine valid:" << ( mEngine && mEngine->isValid() );
setConfigurationRequired( true );
}
}
void ComicApplet::updateContextMenu()
{
mActionGoFirst->setVisible(mCurrent.hasFirst());
mActionGoFirst->setEnabled(mCurrent.hasPrev());
mActionGoLast->setEnabled(true);//always enable to have some kind of refresh action
if (mActionShop) {
mActionShop->setEnabled(mCurrent.shopUrl().isValid());
}
}
void ComicApplet::slotSaveComicAs()
{
ComicSaver saver(mSavingDir);
saver.save(mCurrent);
}
void ComicApplet::slotScaleToContent()
{
setShowActualSize(mActionScaleContent->isChecked());
}
//QML
QObject *ComicApplet::comicsModel()
{
return &mActiveComicModel;
}
bool ComicApplet::showComicUrl() const
{
return mShowComicUrl;
}
void ComicApplet::setShowComicUrl(bool show)
{
if (show == mShowComicUrl)
return;
mShowComicUrl = show;
emit showComicUrlChanged();
}
bool ComicApplet::showComicAuthor() const
{
return mShowComicAuthor;
}
void ComicApplet::setShowComicAuthor(bool show)
{
if (show == mShowComicAuthor)
return;
mShowComicAuthor = show;
emit showComicAuthorChanged();
}
bool ComicApplet::showComicTitle() const
{
return mShowComicTitle;
}
void ComicApplet::setShowComicTitle(bool show)
{
if (show == mShowComicTitle)
return;
mShowComicTitle = show;
emit showComicTitleChanged();
}
bool ComicApplet::showComicIdentifier() const
{
return mShowComicIdentifier;
}
void ComicApplet::setShowComicIdentifier(bool show)
{
if (show == mShowComicIdentifier)
return;
mShowComicIdentifier = show;
emit showComicIdentifierChanged();
}
bool ComicApplet::showErrorPicture() const
{
return mShowErrorPicture;
}
void ComicApplet::setShowErrorPicture(bool show)
{
if (show == mShowErrorPicture)
return;
mShowErrorPicture = show;
emit showErrorPictureChanged();
}
bool ComicApplet::arrowsOnHover() const
{
return mArrowsOnHover;
}
void ComicApplet::setArrowsOnHover(bool show)
{
if (show == mArrowsOnHover)
return;
mArrowsOnHover = show;
emit arrowsOnHoverChanged();
}
bool ComicApplet::middleClick() const
{
return mMiddleClick;
}
void ComicApplet::setMiddleClick(bool show)
{
if (show == mMiddleClick)
return;
mMiddleClick = show;
emit middleClickChanged();
}
QVariantHash ComicApplet::comicData()
{
return mComicData;
}
void ComicApplet::refreshComicData()
{
mComicData["image"] = mCurrent.image();
mComicData["prev"] = mCurrent.prev();
mComicData["next"] = mCurrent.next();
mComicData["additionalText"] = mCurrent.additionalText();
mComicData["websiteUrl"] = mCurrent.websiteUrl().prettyUrl();
mComicData["websiteHost"] = mCurrent.websiteUrl().host();
mComicData["imageUrl"] = mCurrent.websiteUrl().prettyUrl();
mComicData["shopUrl"] = mCurrent.websiteUrl().prettyUrl();
mComicData["first"] = mCurrent.first();
mComicData["stripTitle"] = mCurrent.stripTitle();
mComicData["author"] = mCurrent.author();
mComicData["title"] = mCurrent.title();
mComicData["suffixType"] = "Date";
mComicData["current"] = mCurrent.current();
//mComicData["last"] = mCurrent.last();
mComicData["currentReadable"] = mCurrent.currentReadable();
mComicData["firstStripNum"] = mCurrent.firstStripNum();
mComicData["maxStripNum"] = mCurrent.maxStripNum();
mComicData["isLeftToRight"] = mCurrent.isLeftToRight();
mComicData["isTopToBottom"] = mCurrent.isTopToBottom();
emit comicDataChanged();
}
bool ComicApplet::showActualSize() const
{
return mCurrent.scaleComic();
}
void ComicApplet::setShowActualSize(bool show)
{
if (show == mCurrent.scaleComic())
return;
mCurrent.setScaleComic(show);
emit showActualSizeChanged();
}
//Endof QML
void ComicApplet::setTabHighlighted(const QString &id, bool highlight)
{
//Search for matching id
for (int index = 0; index < mActiveComicModel.rowCount(); ++index) {
QStandardItem * item = mActiveComicModel.item(index);
QString currentId = item->data(ActiveComicModel::ComicKeyRole).toString();
if (id == currentId){
if (highlight != item->data(ActiveComicModel::ComicHighlightRole).toBool()) {
item->setData(highlight, ActiveComicModel::ComicHighlightRole);
emit tabHighlightRequest(id, highlight);
}
}
}
}
bool ComicApplet::hasHighlightedTabs()
{
for (int i = 0; i < mActiveComicModel.rowCount(); ++i) {
if (isTabHighlighted(i)) {
return true;
}
}
return false;
}
bool ComicApplet::isTabHighlighted(int index) const
{
if (index < 0 || index >= mActiveComicModel.rowCount()) {
return false;
}
QStandardItem * item = mActiveComicModel.item(index);
return item->data(ActiveComicModel::ComicHighlightRole).toBool();
}
#include "comic.moc"

View file

@ -0,0 +1,209 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008 by Marco Martin <notmart@gmail.com> *
* Copyright (C) 2008-2010 Matthias Fuchs <mat69@gmx.net> *
* Copyright (C) 2012 Reza Fatahilah Shah <rshah0385@kireihana.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef COMIC_H
#define COMIC_H
#include "comicdata.h"
#include <QtCore/QDate>
#include <KUrl>
#include <Plasma/DataEngine>
#include <Plasma/PopupApplet>
#include "activecomicmodel.h"
namespace Plasma {
class DeclarativeWidget;
}
class CheckNewStrips;
class ComicModel;
class ConfigWidget;
class KAction;
class KJob;
class QAction;
class QGraphicsLayout;
class QSortFilterProxyModel;
class QTimer;
class SavingDir;
class ComicApplet : public Plasma::PopupApplet
{
Q_OBJECT
Q_PROPERTY(QObject * comicsModel READ comicsModel NOTIFY comicModelChanged)
Q_PROPERTY(bool showComicUrl READ showComicUrl WRITE setShowComicUrl NOTIFY showComicUrlChanged)
Q_PROPERTY(bool showComicAuthor READ showComicAuthor WRITE setShowComicAuthor NOTIFY showComicAuthorChanged)
Q_PROPERTY(bool showComicTitle READ showComicTitle WRITE setShowComicTitle NOTIFY showComicTitleChanged)
Q_PROPERTY(bool showComicIdentifier READ showComicIdentifier WRITE setShowComicIdentifier NOTIFY showComicIdentifierChanged)
Q_PROPERTY(bool showErrorPicture READ showErrorPicture WRITE setShowErrorPicture NOTIFY showErrorPictureChanged)
Q_PROPERTY(bool arrowsOnHover READ arrowsOnHover WRITE setArrowsOnHover NOTIFY arrowsOnHoverChanged)
Q_PROPERTY(bool middleClick READ middleClick WRITE setMiddleClick NOTIFY middleClickChanged)
Q_PROPERTY(QVariantHash comicData READ comicData NOTIFY comicDataChanged)
Q_PROPERTY(bool showActualSize READ showActualSize WRITE setShowActualSize NOTIFY showActualSizeChanged)
public:
ComicApplet( QObject *parent, const QVariantList &args );
~ComicApplet();
void init();
virtual QList<QAction*> contextualActions();
QGraphicsWidget *graphicsWidget();
//For QML
QObject *comicsModel();
QVariantHash comicData();
bool showComicUrl() const;
void setShowComicUrl(bool show);
bool showComicAuthor() const;
void setShowComicAuthor(bool show);
bool showComicTitle() const;
void setShowComicTitle(bool show);
bool showComicIdentifier() const;
void setShowComicIdentifier(bool show);
bool showErrorPicture() const;
void setShowErrorPicture(bool show);
bool arrowsOnHover() const;
void setArrowsOnHover(bool show);
bool middleClick() const;
void setMiddleClick(bool show);
bool showActualSize() const;
void setShowActualSize(bool show);
Q_INVOKABLE bool checkAuthorization(const QString &permissionName) { return hasAuthorization(permissionName); }
//End for QML
Q_SIGNALS:
void comicModelChanged();
void showComicUrlChanged();
void showComicAuthorChanged();
void showComicTitleChanged();
void showComicIdentifierChanged();
void showErrorPictureChanged();
void arrowsOnHoverChanged();
void middleClickChanged();
void comicDataChanged();
void tabHighlightRequest(const QString &id, bool highlight);
void showNextNewStrip();
void showActualSizeChanged();
public Q_SLOTS:
void dataUpdated( const QString &name, const Plasma::DataEngine::Data &data );
void createConfigurationInterface( KConfigDialog *parent );
private Q_SLOTS:
void slotTabChanged( const QString &newIdentifier );
void slotNextDay();
void slotPreviousDay();
void slotFirstDay();
void slotCurrentDay();
void slotFoundLastStrip( int index, const QString &identifier, const QString &suffix );
void slotGoJump();
void slotSaveComicAs();
void slotScaleToContent();
void slotShop();
void slotStorePosition();
void applyConfig();
void checkDayChanged();
void createComicBook();
void slotArchive( int archiveType, const KUrl &dest, const QString &fromIdentifier, const QString &toIdentifier );
void slotArchiveFinished( KJob *job );
public slots:
void configChanged();
Q_INVOKABLE void updateComic(const QString &identifierSuffix = QString());
Q_INVOKABLE void goJump() { slotGoJump();}
Q_INVOKABLE void shop() { slotShop();}
Q_INVOKABLE void tabChanged(const QString &newIdentifier) { slotTabChanged(newIdentifier);}
protected:
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
private:
void changeComic( bool differentComic );
void updateUsedComics();
void updateContextMenu();
void updateView();
void saveConfig();
bool isInPanel() const;
void refreshComicData();
void setTabHighlighted(const QString &id, bool highlight);
bool hasHighlightedTabs();
bool isTabHighlighted(int index) const;
private:
static const int CACHE_LIMIT;
ComicModel *mModel;
QSortFilterProxyModel *mProxy;
ActiveComicModel mActiveComicModel;
QVariantHash mComicData;
QDate mCurrentDay;
QString mIdentifierError;
QString mOldSource;
ConfigWidget *mConfigWidget;
bool mDifferentComic;
bool mShowComicUrl;
bool mShowComicAuthor;
bool mShowComicTitle;
bool mShowComicIdentifier;
bool mShowErrorPicture;
bool mArrowsOnHover;
bool mMiddleClick;
int mCheckNewComicStripsIntervall;
CheckNewStrips *mCheckNewStrips;
QTimer *mDateChangedTimer;
QList<QAction*> mActions;
Plasma::DeclarativeWidget *mDeclarativeWidget;
QAction *mActionGoFirst;
QAction *mActionGoLast;
QAction *mActionGoJump;
QAction *mActionScaleContent;
QAction *mActionShop;
QAction *mActionStorePosition;
KAction *mActionNextNewStripTab;
QSizeF mMaxSize;
QSizeF mLastSize;
QSizeF mIdealSize;
Plasma::DataEngine *mEngine;
//Tabs
bool mTabAdded;
QStringList mTabIdentifier;
ComicData mCurrent;
SavingDir *mSavingDir;
};
K_EXPORT_PLASMA_APPLET( comic, ComicApplet )
#endif

View file

@ -0,0 +1,8 @@
[KNewStuff3]
ProvidersUrl=http://download.kde.org/ocs/providers.xml
Categories=Plasma Comic
TargetDir=plasma/comics
Uncompress=never
InstallationCommand=plasmapkg -t comic -i %f
UninstallCommand=plasmapkg -t comic -r %f

View file

@ -0,0 +1,238 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ComicSettings</class>
<widget class="QWidget" name="ComicSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>394</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Comic</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTreeView" name="listView_comic">
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="pushButton_GHNS">
<property name="toolTip">
<string>Download new comics</string>
</property>
<property name="text">
<string>&amp;Get New Comics...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="checkBox_middle">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Middle-click on the comic to show it at its original size</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_13">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Update</string>
</property>
</widget>
</item>
<item row="7" column="1">
<layout class="QFormLayout" name="formLayout_4">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Automatically update comic plugins:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="updateIntervall">
<property name="value">
<number>0</number>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>120</number>
</property>
<property name="suffix">
<string> days</string>
</property>
<property name="prefix">
<string>every </string>
</property>
<property name="specialValueText">
<string>never</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Check for new comic strips:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="updateIntervallComicStrips">
<property name="value">
<number>0</number>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1200</number>
</property>
<property name="suffix">
<string> minutes</string>
</property>
<property name="prefix">
<string>every </string>
</property>
<property name="specialValueText">
<string>never</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
</customwidgets>
<tabstops>
<tabstop>pushButton_GHNS</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,200 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicarchivedialog.h"
#include "comicarchivejob.h"
#include <KFileDialog>
ComicArchiveDialog::ComicArchiveDialog( const QString &pluginName, const QString &comicName, IdentifierType identifierType, const QString &currentIdentifierSuffix, const QString &firstIdentifierSuffix, const QString &savingDir, QWidget *parent )
: KDialog( parent ),
mIdentifierType( identifierType ),
mPluginName( pluginName )
{
QWidget *widget = new QWidget(this);
ui.setupUi(widget);
setCaption( i18n( "Create %1 Comic Book Archive", comicName ) );
setMainWidget( widget );
switch ( mIdentifierType ) {
case Date: {
const QDate current = QDate::fromString( currentIdentifierSuffix, "yyyy-MM-dd" );
const QDate first = QDate::fromString( firstIdentifierSuffix, "yyyy-MM-dd" );
const QDate today = QDate::currentDate();
QDate maxDate = today;
if ( current.isValid() ) {
ui.fromDate->setDate( current );
ui.toDate->setDate( current );
maxDate = ( today > current ? today : current );
}
if ( first.isValid() ) {
ui.fromDate->setMinimumDate( first );
ui.toDate->setMinimumDate( first );
}
connect( ui.fromDate, SIGNAL(dateChanged(QDate)), this, SLOT(fromDateChanged(QDate)) );
connect( ui.toDate, SIGNAL(dateChanged(QDate)), this, SLOT(toDateChanged(QDate)) );
break;
}
case Number: {
bool ok;
const int current = currentIdentifierSuffix.toInt( &ok );
if ( ok ) {
ui.fromNumber->setValue( current );
ui.toNumber->setValue( current );
}
const int first = firstIdentifierSuffix.toInt( &ok );
if ( ok ) {
ui.fromNumber->setMinimum( first );
ui.toNumber->setMinimum( first );
}
break;
}
case String: {
ui.fromString->setText( currentIdentifierSuffix );
ui.toString->setText( currentIdentifierSuffix );
connect( ui.fromString, SIGNAL(textEdited(QString)), this, SLOT(updateOkButton()) );
connect( ui.toString, SIGNAL(textEdited(QString)), this, SLOT(updateOkButton()) );
break;
}
}
ui.types->setCurrentIndex( mIdentifierType );
archiveTypeChanged( ComicArchiveJob::ArchiveAll );
//TODO suggest file name!
ui.dest->fileDialog()->setOperationMode( KFileDialog::Saving );
if ( !savingDir.isEmpty() ) {
ui.dest->setStartDir( savingDir );
}
connect( ui.archiveType, SIGNAL(currentIndexChanged(int)), this, SLOT(archiveTypeChanged(int)) );
connect( ui.dest, SIGNAL(textChanged(QString)), this, SLOT(updateOkButton()) );
connect( this, SIGNAL(okClicked()), this, SLOT(slotOkClicked()) );
}
void ComicArchiveDialog::archiveTypeChanged( int newType )
{
switch ( newType ) {
case ComicArchiveJob::ArchiveAll:
setFromVisible( false );
setToVisibile( false );
break;
break;
case ComicArchiveJob::ArchiveEndTo:
case ComicArchiveJob::ArchiveStartTo:
setFromVisible( false );
setToVisibile( true );
break;
case ComicArchiveJob::ArchiveFromTo:
setFromVisible( true );
setToVisibile( true );
break;
}
updateOkButton();
}
void ComicArchiveDialog::fromDateChanged( const QDate &newDate )
{
if ( ui.toDate->date() < newDate ) {
ui.toDate->setDate( newDate );
}
updateOkButton();
}
void ComicArchiveDialog::toDateChanged( const QDate &newDate )
{
if ( ui.fromDate->date() > newDate ) {
ui.fromDate->setDate( newDate );
}
updateOkButton();
}
void ComicArchiveDialog::updateOkButton()
{
const int archiveType = ui.archiveType->currentIndex();
bool okEnabled = true;
//string is handled here, as it is the only identifier which can be invalid (empty)
if ( mIdentifierType == String ) {
if ( archiveType == ComicArchiveJob::ArchiveAll ) {
okEnabled = true ;
} else if ( ui.archiveType->currentIndex() == ComicArchiveJob::ArchiveFromTo ) {
okEnabled = !ui.fromString->text().isEmpty() && !ui.toString->text().isEmpty();
} else {
okEnabled = !ui.toString->text().isEmpty();
}
}
okEnabled = ( okEnabled && !ui.dest->url().isEmpty() );
enableButtonOk( okEnabled );
}
void ComicArchiveDialog::slotOkClicked()
{
const int archiveType = ui.archiveType->currentIndex();
QString fromIdentifier;
QString toIdentifier;
switch ( mIdentifierType ) {
case Date:
fromIdentifier = ui.fromDate->date().toString( "yyyy-MM-dd" );
toIdentifier = ui.toDate->date().toString( "yyyy-MM-dd" );
break;
case Number: {
fromIdentifier = QString::number( ui.fromNumber->value() );
toIdentifier = QString::number( ui.toNumber->value() );
//the user entered from and to wrong, swap them
if ( ( archiveType == ComicArchiveJob::ArchiveFromTo) && ( ui.toNumber->value() < ui.fromNumber->value() ) ) {
QString temp = fromIdentifier;
fromIdentifier = toIdentifier;
toIdentifier = temp;
}
break;
}
case String:
fromIdentifier = ui.fromString->text();
toIdentifier = ui.toString->text();
break;
}
emit archive( archiveType, ui.dest->url(), fromIdentifier, toIdentifier );
}
void ComicArchiveDialog::setFromVisible( bool visible )
{
ui.fromDateLabel->setVisible( visible );
ui.fromDate->setVisible( visible );
ui.fromNumberLabel->setVisible( visible );
ui.fromNumber->setVisible( visible );
ui.fromStringLabel->setVisible( visible );
ui.fromString->setVisible( visible );
}
void ComicArchiveDialog::setToVisibile( bool visible )
{
ui.toDateLabel->setVisible( visible );
ui.toDate->setVisible( visible );
ui.toNumberLabel->setVisible( visible );
ui.toNumber->setVisible( visible );
ui.toStringLabel->setVisible( visible );
ui.toString->setVisible( visible );
}

View file

@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMIC_ARCHIVE_DIALOG_H
#define COMIC_ARCHIVE_DIALOG_H
#include "comicinfo.h"
#include "ui_comicarchivedialog.h"
#include <KDialog>
class ComicArchiveDialog : public KDialog
{
Q_OBJECT
public:
ComicArchiveDialog( const QString &pluginName, const QString &comicName, IdentifierType identifierType, const QString &currentIdentifierSuffix, const QString &firstIdentifierSuffix, const QString &savingDir = QString(), QWidget *parent = 0 );
signals:
void archive( int archiveType, const KUrl &dest, const QString &fromIdentifier, const QString &toIdentifier );
private slots:
void archiveTypeChanged( int newType );
void fromDateChanged( const QDate &newDate );
void toDateChanged( const QDate &newDate );
void slotOkClicked();
void updateOkButton();
private:
void setFromVisible( bool visible );
void setToVisibile( bool visible );
private:
Ui::ComicArchiveDialog ui;
IdentifierType mIdentifierType;
QString mPluginName;
};
#endif

View file

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ComicArchiveDialog</class>
<widget class="QWidget" name="ComicArchiveDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>143</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Destination:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="KUrlRequester" name="dest">
<property name="filter">
<string>*.cbz|Comic Book Archive (Zip)</string>
</property>
<property name="mode">
<set>KFile::File|KFile::LocalOnly</set>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="statusTip">
<string>The range of comic strips to archive.</string>
</property>
<property name="text">
<string>Range:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="KComboBox" name="archiveType">
<item>
<property name="text">
<string>All</string>
</property>
</item>
<item>
<property name="text">
<string>From beginning to ...</string>
</property>
</item>
<item>
<property name="text">
<string>From end to ...</string>
</property>
</item>
<item>
<property name="text">
<string>Manual range</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QStackedWidget" name="types">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="date">
<layout class="QFormLayout" name="formLayout">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="fromDateLabel">
<property name="text">
<string comment="in a range: from to">From:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="toDateLabel">
<property name="text">
<string comment="in a range: from to">To:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDateEdit" name="fromDate">
<property name="displayFormat">
<string>dd.MM.yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDateEdit" name="toDate">
<property name="displayFormat">
<string>dd.MM.yyyy</string>
</property>
<property name="calendarPopup">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="number">
<layout class="QFormLayout" name="formLayout_2">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="fromNumberLabel">
<property name="text">
<string comment="in a range: from to">From:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="toNumberLabel">
<property name="text">
<string comment="in a range: from to">To:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="toNumber">
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="fromNumber">
<property name="maximum">
<number>100000</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="string">
<layout class="QFormLayout" name="formLayout_3">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="fromStringLabel">
<property name="text">
<string comment="in a range: from to">From:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="toStringLabel">
<property name="text">
<string comment="in a range: from to">To:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="KLineEdit" name="fromString"/>
</item>
<item row="1" column="1">
<widget class="KLineEdit" name="toString"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KUrlRequester</class>
<extends>QFrame</extends>
<header>kurlrequester.h</header>
</customwidget>
<customwidget>
<class>KLineEdit</class>
<extends>QLineEdit</extends>
<header>klineedit.h</header>
</customwidget>
<customwidget>
<class>KComboBox</class>
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -0,0 +1,435 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicarchivejob.h"
#include <KDebug>
#include <KIO/NetAccess>
#include <KTemporaryFile>
#include <KZip>
#ifdef HAVE_NEPOMUK
#include <Nepomuk/Resource>
#include <Nepomuk/Tag>
#include <Nepomuk/Variant>
#include <Nepomuk/Vocabulary/NCO>
#include <Nepomuk/Vocabulary/NFO>
#include <Nepomuk/Vocabulary/PIMO>
using namespace Nepomuk::Vocabulary;
#endif
ComicArchiveJob::ComicArchiveJob( const KUrl &dest, Plasma::DataEngine *engine, ComicArchiveJob::ArchiveType archiveType, IdentifierType identifierType, const QString &pluginName, QObject *parent )
: KJob( parent ),
mType( archiveType ),
mDirection( Undefined ),
mIdentifierType( identifierType ),
mSuspend( false ),
mFindAmount( true ),
mHasVariants( false ),
mDone( false ),
mComicNumber( 0 ),
mProcessedFiles( 0 ),
mTotalFiles( -1 ),
mEngine( engine ),
mZipFile( new KTemporaryFile ),
mZip( 0 ),
mPluginName( pluginName ),
mDest( dest )
{
if ( mZipFile->open() ) {
mZip = new KZip( mZipFile->fileName() );
mZip->open( QIODevice::ReadWrite );
mZip->setCompression( KZip::NoCompression );
setCapabilities( Killable | Suspendable );
} else {
kError() << "Could not create a temporary file for the zip file.";
}
}
ComicArchiveJob::~ComicArchiveJob()
{
emitResultIfNeeded();
delete mZip;
delete mZipFile;
qDeleteAll( mBackwardFiles );
}
bool ComicArchiveJob::isValid() const
{
if ( mPluginName.isEmpty() ) {
kWarning() << "No plugin name specified.";
return false;
}
switch ( mType ) {
case ArchiveFromTo:
if ( mToIdentifier.isEmpty() || mFromIdentifier.isEmpty() ) {
kWarning() << "Not enought data provided to archive a range.";
return false;
}
break;
case ArchiveStartTo:
case ArchiveEndTo:
if ( mToIdentifier.isEmpty() ) {
kWarning() << "Not enough data provied to archive StartTo/EndTo.";
return false;
}
break;
default:
break;
}
return mEngine->isValid() && mZip && mZip->isOpen();
}
void ComicArchiveJob::setToIdentifier( const QString &toIdentifier )
{
mToIdentifier = toIdentifier;
mToIdentifierSuffix = mToIdentifier;
mToIdentifierSuffix.remove( mPluginName + ':' );
}
void ComicArchiveJob::setFromIdentifier( const QString &fromIdentifier )
{
mFromIdentifier = fromIdentifier;
mFromIdentifierSuffix = mFromIdentifier;
mFromIdentifierSuffix.remove( mPluginName + ':' );
}
void ComicArchiveJob::start()
{
switch ( mType ) {
case ArchiveAll:
requestComic( suffixToIdentifier( QString() ) );
break;
case ArchiveStartTo:
requestComic( mToIdentifier );
break;
case ArchiveEndTo: {
setFromIdentifier( mToIdentifier );
mToIdentifier.clear();
mToIdentifierSuffix.clear();
requestComic( suffixToIdentifier( QString() ) );
break;
}
case ArchiveFromTo:
mDirection = Foward;
defineTotalNumber();
requestComic( mFromIdentifier );
break;
}
}
void ComicArchiveJob::dataUpdated( const QString &source, const Plasma::DataEngine::Data &data )
{
if ( !mZip ) {
kWarning() << "No zip file, aborting.";
setErrorText( i18n( "No zip file is existing, aborting." ) );
setError( KilledJobError );
emitResultIfNeeded();
return;
}
const QString currentIdentifier = data[ "Identifier" ].toString();
QString currentIdentifierSuffix = currentIdentifier;
currentIdentifierSuffix.remove( mPluginName + ':' );
const QImage image = data[ "Image" ].value<QImage>();
const bool hasError = data[ "Error" ].toBool() || image.isNull();
const QString previousIdentifierSuffix = data[ "Previous identifier suffix" ].toString();
const QString nextIdentifierSuffix = data[ "Next identifier suffix" ].toString();
const QString firstIdentifierSuffix = data[ "First strip identifier suffix" ].toString();
mAuthors << data[ "Comic Author" ].toString().split( ',', QString::SkipEmptyParts );
mAuthors.removeDuplicates();
if ( mComicTitle.isEmpty() ) {
mComicTitle = data[ "Title" ].toString();
}
mEngine->disconnectSource( source, this );
if ( hasError ) {
kWarning() << "An error occured at" << source << "stopping.";
setErrorText( i18n( "An error happened for identifier %1.", source ) );
setError( KilledJobError );
copyZipFileToDestination();
return;
}
if ( mDirection == Undefined ) {
if ( ( mType == ArchiveAll ) || ( mType == ArchiveStartTo ) ) {
if ( !firstIdentifierSuffix.isEmpty() ) {
setFromIdentifier( suffixToIdentifier( firstIdentifierSuffix ) );
}
if ( mType == ArchiveAll ) {
setToIdentifier( currentIdentifier );
}
mDirection = ( firstIdentifierSuffix.isEmpty() ? Backward : Foward );
if ( mDirection == Foward ) {
requestComic( suffixToIdentifier( firstIdentifierSuffix ) );
return;
} else {
//backward, i.e. the to identifier is unknown
mToIdentifier.clear();
mToIdentifierSuffix.clear();
}
} else if ( mType == ArchiveEndTo ) {
mDirection = Foward;
setToIdentifier( currentIdentifier );
requestComic( mFromIdentifier );
return;
}
}
bool worked = false;
++mProcessedFiles;
if ( mDirection == Foward ) {
KTemporaryFile tempFile;
worked = tempFile.open();
worked = worked && tempFile.flush();
worked = ( worked ? image.save( tempFile.fileName(), "PNG" ) : worked );
worked = ( worked ? addFileToZip( tempFile.fileName() ) : worked );
if ( worked ) {
if ( ( currentIdentifier == mToIdentifier ) || ( currentIdentifierSuffix == nextIdentifierSuffix) || nextIdentifierSuffix.isEmpty() ) {
kDebug() << "Done downloading at:" << source;
copyZipFileToDestination();
} else {
requestComic( suffixToIdentifier( nextIdentifierSuffix ) );
}
}
} else if ( mDirection == Backward ) {
KTemporaryFile *tempFile = new KTemporaryFile;
mBackwardFiles << tempFile;
worked = tempFile->open();
worked = worked && tempFile->flush();
worked = ( worked ? image.save( tempFile->fileName(), "PNG" ) : worked );
if ( worked ) {
if ( ( currentIdentifier == mToIdentifier ) || ( currentIdentifierSuffix == previousIdentifierSuffix ) || previousIdentifierSuffix.isEmpty() ) {
kDebug() << "Done downloading at:" << source;
createBackwardZip();
} else {
requestComic( suffixToIdentifier( previousIdentifierSuffix) );
}
}
}
defineTotalNumber( currentIdentifierSuffix );
setProcessedAmount( Files, mProcessedFiles );
if ( mTotalFiles != -1 ) {
setPercent( ( 100 * mProcessedFiles ) / mTotalFiles );
}
if ( !worked ) {
kError() << "Could not write the file, identifier:" << source;
setErrorText( i18n( "Failed creating the file with identifier %1.", source ) );
setError( KilledJobError );
emitResultIfNeeded();
}
}
bool ComicArchiveJob::doKill()
{
mSuspend = true;
return KJob::doKill();
}
bool ComicArchiveJob::doSuspend()
{
mSuspend = true;
return true;
}
bool ComicArchiveJob::doResume()
{
mSuspend = false;
if ( !mRequest.isEmpty() ) {
requestComic( mRequest );
}
return true;
}
void ComicArchiveJob::defineTotalNumber( const QString &currentSuffix )
{
findTotalNumberFromTo();
if ( mTotalFiles == -1 ) {
kDebug() << "Unable to find the total number for" << mPluginName;
return;
}
//calculate a new value for total files, can be different from the previous one,
//if there are no strips for certain days/numbers
if ( !currentSuffix.isEmpty() ) {
if ( mIdentifierType == Date ) {
const QDate current = QDate::fromString( currentSuffix, "yyyy-MM-dd" );
const QDate to = QDate::fromString( mToIdentifierSuffix, "yyyy-MM-dd" );
if ( current.isValid() && to.isValid() ) {
//processed files + files still to download
mTotalFiles = mProcessedFiles + qAbs( current.daysTo( to ) );
}
} else if ( mIdentifierType == Number ) {
bool result = true;
bool ok;
const int current = currentSuffix.toInt( &ok );
result = ( result && ok );
const int to = mToIdentifierSuffix.toInt( &ok );
result = ( result && ok );
if ( result ) {
//processed files + files still to download
mTotalFiles = mProcessedFiles + qAbs( to - current );
}
}
}
if ( mTotalFiles != -1 ) {
setTotalAmount( Files, mTotalFiles );
}
}
void ComicArchiveJob::findTotalNumberFromTo()
{
if ( mTotalFiles != -1 ) {
return;
}
if ( mIdentifierType == Date ) {
const QDate from = QDate::fromString( mFromIdentifierSuffix, "yyyy-MM-dd" );
const QDate to = QDate::fromString( mToIdentifierSuffix, "yyyy-MM-dd" );
if ( from.isValid() && to.isValid() ) {
mTotalFiles = qAbs( from.daysTo( to ) ) + 1;
}
} else if ( mIdentifierType == Number ) {
bool result = true;
bool ok;
const int from = mFromIdentifierSuffix.toInt( &ok );
result = ( result && ok );
const int to = mToIdentifierSuffix.toInt( &ok );
result = ( result && ok );
if ( result ) {
mTotalFiles = qAbs( to - from ) + 1;
}
}
}
QString ComicArchiveJob::suffixToIdentifier( const QString &suffix ) const
{
return mPluginName + ':' + suffix;
}
void ComicArchiveJob::requestComic( QString identifier ) //krazy:exclude=passbyvalue
{
mRequest.clear();
if ( mSuspend ) {
mRequest = identifier;
return;
}
emit description( this, i18n( "Creating Comic Book Archive" ),
qMakePair( QString( "source" ), identifier ),
qMakePair( QString( "destination" ), mDest.prettyUrl() ) );
mEngine->connectSource( identifier, this );
mEngine->query( identifier );
}
bool ComicArchiveJob::addFileToZip( const QString &path )
{
//We use 6 signs, e.g. number 1 --> 000001.png, 123 --> 000123.png
//this way the comics should always be correctly sorted (otherwise evince e.g. has problems)
static const int numSigns = 6;
static const QString zero = QLatin1String( "0" );
QString number = QString::number( ++mComicNumber );
const int length = number.length();
if ( length < numSigns ) {
number = zero.repeated( numSigns - length ) + number;
}
return mZip->addLocalFile( path, number + QLatin1String( ".png" ) );
}
void ComicArchiveJob::createBackwardZip()
{
for ( int i = mBackwardFiles.count() - 1; i >= 0; --i ) {
if ( !addFileToZip( mBackwardFiles[i]->fileName() ) ) {
kWarning() << "Failed adding a file to the archive.";
setErrorText( i18n( "Failed adding a file to the archive." ) );
setError( KilledJobError );
emitResultIfNeeded();
return;
}
}
copyZipFileToDestination();
}
void ComicArchiveJob::copyZipFileToDestination()
{
mZip->close();
const bool worked = KIO::NetAccess::file_copy( KUrl( mZipFile->fileName() ), mDest );
//store additional data using Nepomuk
if (!worked) {
kWarning() << "Could not copy the zip file to the specified destination:" << mDest;
setErrorText( i18n( "Could not create the archive at the specified location." ) );
setError( KilledJobError );
emitResultIfNeeded();
return;
}
#ifdef HAVE_NEPOMUK
//store additional data using Nepomuk
Nepomuk::Resource res( mDest, NFO::FileDataObject() );
Nepomuk::Resource comicTopic( "Comic", PIMO::Topic() );
comicTopic.setLabel( i18n( "Comic" ) );
if ( !mComicTitle.isEmpty() ) {
Nepomuk::Resource topic( mComicTitle, PIMO::Topic() );
topic.setLabel( mComicTitle );
topic.setProperty( PIMO::superTopic(), comicTopic );
res.addTag( topic );
} else {
// res.addTag( comicTopic );//TODO activate this, see below
;
}
//FIXME also set the comic topic as tag, this is redundant, as topic has this as super topic
//though at this point the gui (Dolphin) does not manage to show the correct tags
res.addTag( comicTopic );
foreach ( QString author, mAuthors ) {
author = author.trimmed();
Nepomuk::Resource authorRes( author, NCO::PersonContact() );
authorRes.setProperty( NCO::fullname(), author );
res.addProperty( NCO::creator(), authorRes );
}
#endif
emitResultIfNeeded();
}
void ComicArchiveJob::emitResultIfNeeded()
{
if ( !mDone ) {
mDone = true;
emitResult();
}
}

View file

@ -0,0 +1,144 @@
/***************************************************************************
* Copyright (C) 2011 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMIC_ARCHIVE_JOB_H
#define COMIC_ARCHIVE_JOB_H
#include "comicinfo.h"
#include <KIO/Job>
#include <Plasma/DataEngine>
class KTemporaryFile;
class KZip;
class ComicArchiveJob : public KJob
{
Q_OBJECT
public:
enum ArchiveType {
ArchiveAll = 0,
ArchiveStartTo,
ArchiveEndTo,
ArchiveFromTo
};
/**
* Creates a comic archive job.
* The engine has to be a working comic dataengine.
* The archiveType defines what kind of input is given, e.g. if ArchiveAll is
* used no other parameters need to be defined, while ArchiveFromTo needs
* both toIdentifier and fromIdentifier (from <= to!), the other two types need only the toIdentifier.
* You need to define the plugin name in any case, this is part of the identifier e.g.
* "garfield:2010-03-04", here "garfield" is the plugin name
* @see setToIdentifier, setFromIdentifier
*/
ComicArchiveJob( const KUrl &dest, Plasma::DataEngine *engine, ArchiveType archiveType, IdentifierType identifierType, const QString &pluginName, QObject *parent = 0 );
~ComicArchiveJob();
/**
* Checks if all the needed data has been set
*/
bool isValid() const;
/**
* Sets the end to toIdentifier.
* Keep in mind that depending on the ArchiveType this might be ignored
*/
void setToIdentifier( const QString &toIdentifier );
/**
* Sets the beginning to toIdentifier.
* Keep in mind that depending on the ArchiveType this might be ignored
*/
void setFromIdentifier( const QString &fromIdentifier );
virtual void start();
public slots:
void dataUpdated( const QString &source, const Plasma::DataEngine::Data& data );
protected:
virtual bool doKill();
virtual bool doSuspend();
virtual bool doResume();
private:
/**
* Sets the total number of comics to download.
* @param currentSuffix if empty the from and to identifier suffix will be used.
* If a currentSuffix is defined it will check if the total number is different
* e.g. not a comic defined for every day etc.
*/
void defineTotalNumber( const QString &currentSuffix = QString() );
/**
* Sets mTotalFiles if that is -1 and it can calculate at total number
* base on the from and to identifier suffix
*/
void findTotalNumberFromTo();
QString suffixToIdentifier( const QString &suffix ) const;
void requestComic( QString identifier );
bool addFileToZip( const QString &path );
/**
* If the ArchiveDirection is Backward, this will fill the zip
* with mBackwardFiles (beginning from the back), and will call
* copyZipFileToDestination afterwards
*/
void createBackwardZip();
void copyZipFileToDestination();
void emitResultIfNeeded();
private:
enum ArchiveDirection {
Undefined,
Foward,
Backward
};
ArchiveType mType;
ArchiveDirection mDirection;
IdentifierType mIdentifierType;
bool mSuspend;
bool mFindAmount;
bool mHasVariants;
bool mDone;
int mComicNumber;
int mProcessedFiles;
int mTotalFiles;
Plasma::DataEngine *mEngine;
KTemporaryFile *mZipFile;
KZip *mZip;
QString mPluginName;
QString mToIdentifier;
QString mToIdentifierSuffix;
QString mFromIdentifier;
QString mFromIdentifierSuffix;
QString mComicTitle;
QString mRequest;
const KUrl mDest;
QStringList mAuthors;
QList< KTemporaryFile* > mBackwardFiles;
};
#endif

View file

@ -0,0 +1,159 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicdata.h"
#include <Plasma/Theme>
#include <QtGui/QPainter>
ComicData::ComicData()
{
}
void ComicData::init(const QString &id, const KConfigGroup &config)
{
mId = id;
mCfg = config;
mFirstStripNum = 0;
mMaxStripNum = 0;
mScaleComic = false;
mIsLeftToRight = true;
mIsTopToBottom = true;
load();
}
void ComicData::load()
{
mScaleComic = mCfg.readEntry("scaleToContent_" + mId, false);
mMaxStripNum = mCfg.readEntry("maxStripNum_" + mId, 0);
mStored = mCfg.readEntry("storedPosition_" + mId, QString());
}
void ComicData::save()
{
mCfg.writeEntry("scaleToContent_" + mId, mScaleComic);
mCfg.writeEntry("maxStripNum_" + mId, mMaxStripNum);
mCfg.writeEntry("storedPosition_" + id(), mStored);
// no next, thus the most recent strip
if (!hasNext()) {
mCfg.writeEntry("lastStripVisited_" + mId, true);
mCfg.writeEntry("lastStrip_" + mId, mLast);
}
}
void ComicData::setScaleComic(bool scale)
{
mScaleComic = scale;
save();
}
void ComicData::storePosition(bool store)
{
mStored = (store ? mCurrent : QString());
save();
}
void ComicData::setData(const Plasma::DataEngine::Data &data)
{
const bool hasError = data[ "Error" ].toBool();
if (!hasError) {
mImage = data["Image"].value<QImage>();
mPrev = data["Previous identifier suffix"].toString();
mNext = data["Next identifier suffix"].toString();
mAdditionalText = data["Additional text"].toString();
}
mWebsiteUrl = data[ "Website Url" ].value<KUrl>();
mImageUrl = data["Image Url"].value<KUrl>();
mShopUrl = data[ "Shop Url" ].value<KUrl>();
mFirst = data[ "First strip identifier suffix" ].toString();
mStripTitle = data[ "Strip title" ].toString();
mAuthor = data[ "Comic Author" ].toString();
mTitle = data[ "Title" ].toString();
const QString suffixType = data[ "SuffixType" ].toString();
if ( suffixType == "Date" ) {
mType = Date;
} else if ( suffixType == "Number" ) {
mType = Number;
} else {
mType = String;
}
QString temp = data["Identifier"].toString();
mCurrent = temp.remove(mId + ':');
//found a new last identifier
if (!hasNext()) {
mLast = mCurrent;
}
mCurrentReadable = "";
if ( mType == Number ) {
mCurrentReadable = i18nc("an abbreviation for Number", "# %1", mCurrent);
int tempNum = mCurrent.toInt();
if ( mMaxStripNum < tempNum ) {
mMaxStripNum = tempNum;
}
temp = mFirst.remove(mId + ':');
mFirstStripNum = temp.toInt();
} else if ( mType == Date && QDate::fromString( temp, "yyyy-MM-dd" ).isValid() ) {
mCurrentReadable = mCurrent;
} else if ( mType == String ) {
mCurrentReadable = mCurrent;
}
mIsLeftToRight = data["isLeftToRight"].toBool();
mIsTopToBottom = data["isTopToBottom"].toBool();
save();
}
void ComicData::createErrorPicture(const Plasma::DataEngine::Data &data)
{
QPixmap errorPic( 500, 400 );
errorPic.fill();
QPainter p( &errorPic );
QFont font = Plasma::Theme::defaultTheme()->font( Plasma::Theme::DefaultFont );
font.setPointSize( 24 );
p.setPen( QColor( 0, 0, 0 ) );
p.setFont( font );
QString title = i18n( "Getting comic strip failed:" );
p.drawText( QRect( 10, 10 , 480, 100 ), Qt::TextWordWrap | Qt::AlignHCenter | Qt::AlignVCenter, title );
QString text = i18n( "Maybe there is no Internet connection.\nMaybe the comic plugin is broken.\nAnother reason might be that there is no comic for this day/number/string, so choosing a different one might work." );
mPrev = data["Previous identifier suffix"].toString();
if (hasPrev()) {
if (!data["Identifier"].toString().isEmpty() ) {
mErrorStrip = data["Identifier"].toString();
}
text.append( i18n( "\n\nChoose the previous strip to go to the last cached strip." ) );
}
font.setPointSize( 16 );
p.setFont( font );
p.drawText( QRect( 10, 120 , 480, 270 ), Qt::TextWordWrap | Qt::AlignLeft, text );
mImage = errorPic.toImage();
mAdditionalText = title + text;
}

View file

@ -0,0 +1,157 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMIC_DATA_H
#define COMIC_DATA_H
#include "comicinfo.h"
#include <KUrl>
#include <Plasma/DataEngine>
#include <QtCore/QString>
class ComicData
{
public:
ComicData();
void init(const QString &id, const KConfigGroup &config);
void setData(const Plasma::DataEngine::Data &data);
IdentifierType type() const { return mType; }
/**
* The identifier of the comic, e.g. "garfield"
*/
QString id() const { return mId; }
/**
* The stored comic e.g. "2007-12-21" for a comic of the Date type
*/
QString stored() const { return mStored; }
void storePosition(bool store);
/**
* The previous comic e.g. "2007-12-21" for a comic of the Date type
*/
QString prev() const { return mPrev; }
/**
* The current comic e.g. "2007-12-21" for a comic of the Date type
*/
QString current() const { return mCurrent; }
/**
* The next comic e.g. "2007-12-21" for a comic of the Date type
*/
QString next() const { return mNext; }
QString currentReadable() const { return mCurrentReadable; }
/**
* The first comic e.g. "2007-12-21" for a comic of the Date type
*/
QString first() const { return mFirst; }
bool hasNext() const { return !mNext.isEmpty(); }
bool hasPrev() const { return !mPrev.isEmpty(); }
bool hasFirst() const { return !mFirst.isEmpty(); }
bool hasStored() const { return !mStored.isEmpty(); }
bool hasImage() const { return !mImage.isNull(); }
QString additionalText() const { return mAdditionalText; }
QString title() const { return mTitle; }
void setTitle(const QString &title) { mTitle = title; }
QString stripTitle() const { return mStripTitle; }
KUrl websiteUrl() const { return mWebsiteUrl; }
KUrl imageUrl() const { return mImageUrl; }
KUrl shopUrl() const { return mShopUrl; }
QString author() const { return mAuthor; }
QImage image() const { return mImage; }
bool scaleComic() const { return mScaleComic; }
bool isLeftToRight() const { return mIsLeftToRight; }
bool isTopToBottom() const { return mIsTopToBottom; }
bool storePosition() const { return !mStored.isEmpty(); }
void setScaleComic(bool scale);
QString errorStrip() const { return mErrorStrip; }
int firstStripNum() const { return mFirstStripNum; }
int maxStripNum() const { return mMaxStripNum; }
void save();
private:
void load();
void createErrorPicture(const Plasma::DataEngine::Data &data);
private:
IdentifierType mType;
QString mId;
QString mFirst;
QString mLast;
QString mCurrent;
QString mNext;
QString mPrev;
QString mStored;
QString mCurrentReadable;
QString mErrorStrip;
QString mAuthor;
QString mTitle;
QString mStripTitle;
QString mAdditionalText;
KUrl mWebsiteUrl;
KUrl mImageUrl;
KUrl mShopUrl;
QImage mImage;
// only applicable if the comic is of type Number
int mFirstStripNum;
int mMaxStripNum;
bool mScaleComic;
bool mIsLeftToRight;
bool mIsTopToBottom;
KConfigGroup mCfg;
};
#endif

View file

@ -0,0 +1,115 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicinfo.h"
#include <KConfigGroup>
#include <KGlobalSettings>
#include <QtCore/QDir>
class SavingDir::SavingDirPrivate
{
public:
SavingDirPrivate(const KConfigGroup &cfg);
void init();
QString getDir() const;
void setDir(const QString &dir);
private:
void load();
void save();
bool isValid();
private:
KConfigGroup mCfg;
QString mDir;
};
SavingDir::SavingDirPrivate::SavingDirPrivate(const KConfigGroup &cfg)
: mCfg(cfg)
{
}
void SavingDir::SavingDirPrivate::init()
{
load();
save();
}
QString SavingDir::SavingDirPrivate::getDir() const
{
return mDir;
}
void SavingDir::SavingDirPrivate::setDir(const QString &dir)
{
mDir = dir;
save();
}
void SavingDir::SavingDirPrivate::load()
{
mDir = mCfg.readEntry("savingDir", QString());
if (!isValid()) {
mDir = KGlobalSettings::picturesPath();
}
if (!isValid()) {
mDir = KGlobalSettings::downloadPath();
}
if (!isValid()) {
mDir = QDir::homePath();
}
}
void SavingDir::SavingDirPrivate::save()
{
mCfg.writeEntry("savingDir", mDir);
}
bool SavingDir::SavingDirPrivate::isValid()
{
QDir dir;
return (!mDir.isEmpty() && dir.exists(mDir));
}
SavingDir::SavingDir(const KConfigGroup &cfg)
: d(new SavingDirPrivate(cfg))
{
d->init();
}
SavingDir::~SavingDir()
{
delete d;
}
QString SavingDir::getDir() const
{
return d->getDir();
}
void SavingDir::setDir(const QString &dir)
{
d->setDir(dir);
}

View file

@ -0,0 +1,66 @@
/***************************************************************************
* Copyright (C) 2011-2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMIC_TYPE_H
#define COMIC_TYPE_H
class KConfigGroup;
class QString;
enum IdentifierType {
Date = 0,
Number,
String
};
/**
* Provides access (read/write) to the directory that should be used
* whenever the user is presented with a file selection dialog.
*/
class SavingDir
{
public:
/**
* @param config the config that should be used to retrieve
* the saving directory and to store it to in case of changes
*/
SavingDir(const KConfigGroup &config);
~SavingDir();
/**
* @return the directory to be displayed to the user
*/
QString getDir() const;
/**
* Set the directory that should be displayed to the user first
* when choosing a destination. Automatically writes the directory
* to the config, if one was specified in init.
* @param dir the directory to display the user first
* @see init
*/
void setDir(const QString &dir);
private:
class SavingDirPrivate;
SavingDirPrivate *d;
};
#endif

View file

@ -0,0 +1,137 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008-2010 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicmodel.h"
#include <KIcon>
ComicModel::ComicModel( const Plasma::DataEngine::Data &comics, const QStringList &usedComics, QObject *parent )
: QAbstractTableModel( parent ), mNumSelected( 0 )
{
setComics( comics, usedComics );
}
void ComicModel::setComics( const Plasma::DataEngine::Data &comics, const QStringList &usedComics )
{
beginResetModel();
mNumSelected = 0;
mComics = comics;
mState.clear();
Plasma::DataEngine::Data::const_iterator it;
Plasma::DataEngine::Data::const_iterator itEnd = mComics.constEnd();
for ( it = mComics.constBegin(); it != itEnd; ++it ) {
const bool isChecked = usedComics.contains( it.key() );
mState[ it.key() ] = ( isChecked ? Qt::Checked : Qt::Unchecked );
if ( isChecked ) {
++mNumSelected;
}
}
endResetModel();
}
int ComicModel::rowCount( const QModelIndex &index ) const
{
if ( !index.isValid() ) {
return mComics.count();
}
return 0;
}
int ComicModel::columnCount( const QModelIndex &index ) const
{
Q_UNUSED( index )
return 2;
}
QVariant ComicModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() || index.row() >= mComics.keys().count() ) {
return QVariant();
}
const QString data = mComics.keys()[ index.row() ];
if ( index.column() == 0 ) {
if ( role == Qt::CheckStateRole ) {
return mState[ data ];
}
} else if ( index.column() == 1 ) {
switch( role ) {
case Qt::DisplayRole:
return mComics[ data ].toStringList()[ 0 ];
case Qt::DecorationRole:
return KIcon( mComics[ data ].toStringList()[ 1 ] );
case Qt::UserRole:
return data;
}
}
return QVariant();
}
Qt::ItemFlags ComicModel::flags( const QModelIndex &index ) const
{
if ( index.isValid() && ( index.column() == 0 ) ) {
return QAbstractItemModel::flags( index ) | Qt::ItemIsUserCheckable;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
bool ComicModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
if ( index.isValid() && ( role == Qt::CheckStateRole ) ) {
Qt::CheckState oldState = mState[ mComics.keys()[ index.row() ] ];
Qt::CheckState newState = static_cast< Qt::CheckState >( value.toInt() );
mState[ mComics.keys()[ index.row() ] ] = newState;
if ( newState != oldState ) {
if ( newState == Qt::Checked ) {
++mNumSelected;
} else if ( newState == Qt::Unchecked ) {
--mNumSelected;
}
}
emit dataChanged( index, index );
return true;
}
return false;
}
int ComicModel::numSelected() const
{
return mNumSelected;
}
QStringList ComicModel::selected() const
{
QStringList list;
QHash< QString, Qt::CheckState >::const_iterator it;
QHash< QString, Qt::CheckState >::const_iterator itEnd = mState.constEnd();
for ( it = mState.constBegin(); it != itEnd; ++it ) {
if ( it.value() == Qt::Checked ) {
list << it.key();
}
}
return list;
}

View file

@ -0,0 +1,50 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008-2010 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMICMODEL_H
#define COMICMODEL_H
#include <QtCore/QAbstractTableModel>
#include <Plasma/DataEngine>
class ComicModel : public QAbstractTableModel
{
public:
ComicModel( const Plasma::DataEngine::Data &comics, const QStringList &usedComics, QObject *parent = 0 );
void setComics( const Plasma::DataEngine::Data &comics, const QStringList &usedComics );
int rowCount( const QModelIndex &index = QModelIndex() ) const;
int columnCount( const QModelIndex &index = QModelIndex() ) const;
QVariant data( const QModelIndex &index, int role = Qt::CheckStateRole ) const;
Qt::ItemFlags flags( const QModelIndex &index ) const;
bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole );
int numSelected() const;
QStringList selected() const;
private:
Plasma::DataEngine::Data mComics;
QHash<QString, Qt::CheckState> mState;
int mNumSelected;
};
#endif

View file

@ -0,0 +1,132 @@
/***************************************************************************
* Copyright (C) 2008-2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "comicsaver.h"
#include "comicdata.h"
#include "comicinfo.h"
#include <KFileDialog>
#include <KIO/NetAccess>
#include <KTemporaryFile>
#ifdef HAVE_NEPOMUK
#include <Nepomuk/Resource>
#include <Nepomuk/ResourceManager>
#include <Nepomuk/Tag>
#include <Nepomuk/Variant>
#include <Nepomuk/Vocabulary/NCO>
#include <Nepomuk/Vocabulary/NIE>
#include <Nepomuk/Vocabulary/NFO>
#include <Nepomuk/Vocabulary/PIMO>
#include <nepomuk/utils.h>
using namespace Nepomuk::Vocabulary;
#endif
ComicSaver::ComicSaver(SavingDir *savingDir)
: mSavingDir(savingDir)
{
#ifdef HAVE_NEPOMUK
static bool isInit = false;
if (!isInit) {
isInit = true;
// for manually saving the comics
Nepomuk::ResourceManager::instance()->init();
}
#endif
}
bool ComicSaver::save(const ComicData &comic)
{
KTemporaryFile tempFile;
if (!tempFile.open()) {
return false;
}
// save image to temporary file
comic.image().save(tempFile.fileName(), "PNG");
KUrl srcUrl( tempFile.fileName() );
const QString title = comic.title();
const QString name = title + " - " + comic.current() + ".png";
KUrl destUrl = KUrl(mSavingDir->getDir());
destUrl.addPath( name );
destUrl = KFileDialog::getSaveUrl( destUrl, "*.png" );
if ( !destUrl.isValid() ) {
return false;
}
mSavingDir->setDir(destUrl.directory());
#ifdef HAVE_NEPOMUK
bool worked = KIO::NetAccess::file_copy(srcUrl, destUrl);
//store additional data using Nepomuk
if (worked) {
Nepomuk::Resource res(destUrl, NFO::FileDataObject());
Nepomuk::Resource comicTopic("Comic", PIMO::Topic());
comicTopic.setLabel(i18n("Comic"));
if (!comic.additionalText().isEmpty()) {
res.setProperty(NIE::description(), comic.additionalText());
}
if ((comic.type() == Date) && !comic.current().isEmpty()) {
res.setProperty(NIE::contentCreated(), QDateTime::fromString(comic.current(), Qt::ISODate));
}
if (!title.isEmpty()) {
Nepomuk::Resource topic(title, PIMO::Topic());
topic.setLabel(title);
topic.setProperty(PIMO::superTopic(), comicTopic);
res.addTag(topic);
} else {
// res.addTag(comicTopic);//TODO activate this, see below
;
}
//FIXME also set the comic topic as tag, this is redundant, as topic has this as super topic
//though at this point the gui does not manage to show the correct tags
res.addTag(comicTopic);
if (!comic.stripTitle().isEmpty()) {
res.setProperty(NIE::title(), comic.stripTitle());
}
if (!comic.websiteUrl().isEmpty()) {
Nepomuk::Resource copyEvent = Nepomuk::Utils::createCopyEvent(comic.imageUrl(), destUrl, QDateTime(), comic.websiteUrl());
}
const QStringList authors = comic.author().split(',', QString::SkipEmptyParts);
foreach (const QString &author, authors) {
Nepomuk::Resource authorRes(author, NCO::PersonContact());
authorRes.setProperty(NCO::fullname(), author.trimmed());
res.addProperty(NCO::creator(), authorRes);
}
return true;
}
return false;
#else
KIO::NetAccess::file_copy( srcUrl, destUrl );
return true;
#endif
}

View file

@ -0,0 +1,49 @@
/***************************************************************************
* Copyright (C) 2008-2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 COMIC_SAVER_H
#define COMIC_SAVER_H
class ComicData;
class SavingDir;
/**
* ComicSaver takes care of saving a comic strip to a user chosen
* destination.
* Further if available Nepomuk is used to store the title, author
* etc.
*/
class ComicSaver
{
public:
ComicSaver(SavingDir *savingDir);
/**
* Asks the user for a destination to save the specified
* comic to. If possible writes it to that destination.
* @param comic the comic to save
* @return true if saving worked, false if there was a problem
*/
bool save(const ComicData &comic);
private:
SavingDir *mSavingDir;
};
#endif

View file

@ -0,0 +1 @@
#cmakedefine HAVE_NEPOMUK

View file

@ -0,0 +1,268 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008-2010 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "configwidget.h"
#include "comicmodel.h"
#include <QtCore/QTimer>
#include <QtGui/QSortFilterProxyModel>
#include <KConfigDialog>
#include <KNS3/DownloadDialog>
#include <knewstuff3/downloadmanager.h>
ComicUpdater::ComicUpdater( QObject *parent )
: QObject( parent ),
mDownloadManager( 0 ),
mUpdateIntervall( 3 ),
m_updateTimer( 0 )
{
}
ComicUpdater::~ComicUpdater()
{
}
void ComicUpdater::init(const KConfigGroup &group)
{
mGroup = group;
}
void ComicUpdater::load()
{
//check when the last update happened and update if necessary
mUpdateIntervall = mGroup.readEntry( "updateIntervall", 3 );
if ( mUpdateIntervall ) {
mLastUpdate = mGroup.readEntry( "lastUpdate", QDateTime() );
checkForUpdate();
}
}
void ComicUpdater::save()
{
mGroup.writeEntry( "updateIntervall", mUpdateIntervall );
}
void ComicUpdater::applyConfig( ConfigWidget *widget )
{
mUpdateIntervall = widget->updateIntervall();
}
void ComicUpdater::checkForUpdate()
{
//start a timer to check each hour, if KNS3 should look for updates
if ( !m_updateTimer ) {
m_updateTimer = new QTimer(this);
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdate()));
m_updateTimer->start( 1 * 60 * 60 * 1000 );
}
if ( !mLastUpdate.isValid() || ( mLastUpdate.addDays( mUpdateIntervall ) < QDateTime::currentDateTime() ) ) {
mGroup.writeEntry( "lastUpdate", QDateTime::currentDateTime() );
downloadManager()->checkForUpdates();
}
}
void ComicUpdater::slotUpdatesFound( const KNS3::Entry::List &entries )
{
for ( int i = 0; i < entries.count(); ++i ) {
downloadManager()->installEntry( entries[ i ] );
}
}
KNS3::DownloadManager *ComicUpdater::downloadManager()
{
if ( !mDownloadManager ) {
mDownloadManager = new KNS3::DownloadManager( "comic.knsrc", this );
connect(mDownloadManager, SIGNAL(searchResult(KNS3::Entry::List)), this, SLOT(slotUpdatesFound(KNS3::Entry::List)));
}
return mDownloadManager;
}
ConfigWidget::ConfigWidget( Plasma::DataEngine *engine, ComicModel *model, QSortFilterProxyModel *proxy, KConfigDialog *parent )
: QWidget( parent ), mEngine( engine ), mModel( model ), mProxyModel( proxy ), mNewStuffDialog( 0 )
{
comicSettings = new QWidget( this );
comicUi.setupUi( comicSettings );
comicUi.pushButton_GHNS->setIcon( KIcon( "get-hot-new-stuff" ) );
appearanceSettings = new QWidget();
appearanceUi.setupUi( appearanceSettings );
advancedSettings = new QWidget();
advancedUi.setupUi( advancedSettings );
connect( comicUi.pushButton_GHNS, SIGNAL(clicked()), this, SLOT(getNewStuff()) );
comicUi.listView_comic->setModel( mProxyModel );
comicUi.listView_comic->resizeColumnToContents( 0 );
// "Apply" button connections
connect(comicUi.listView_comic , SIGNAL(clicked(QModelIndex)), this , SIGNAL(enableApply()));
connect(comicUi.pushButton_GHNS , SIGNAL(clicked(bool)), this , SIGNAL(enableApply()));
connect(comicUi.checkBox_middle , SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(comicUi.updateIntervall, SIGNAL(valueChanged(int)), this, SIGNAL(enableApply()));
connect(comicUi.updateIntervallComicStrips, SIGNAL(valueChanged(int)), this, SIGNAL(enableApply()));
connect(appearanceUi.checkBox_arrows, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(appearanceUi.checkBox_title, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(appearanceUi.checkBox_identifier, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(appearanceUi.checkBox_author, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(appearanceUi.checkBox_url, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
connect(appearanceUi.kbuttongroup, SIGNAL(changed(int)), this , SIGNAL(enableApply()));
connect(advancedUi.maxComicLimit, SIGNAL(valueChanged(int)), this, SIGNAL(enableApply()));
connect(advancedUi.errorPicture, SIGNAL(toggled(bool)), this , SIGNAL(enableApply()));
mEngine->connectSource( QLatin1String( "providers" ), this );
}
ConfigWidget::~ConfigWidget()
{
mEngine->disconnectSource( QLatin1String( "providers" ), this );
}
void ConfigWidget::getNewStuff()
{
if (!mNewStuffDialog) {
mNewStuffDialog = new KNS3::DownloadDialog( "comic.knsrc", this );
}
mNewStuffDialog->show();
}
void ConfigWidget::dataUpdated(const QString &name, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(name);
mModel->setComics( data, mModel->selected() );
comicUi.listView_comic->resizeColumnToContents( 0 );
}
void ConfigWidget::setShowComicUrl( bool show )
{
appearanceUi.checkBox_url->setChecked( show );
}
bool ConfigWidget::showComicUrl() const
{
return appearanceUi.checkBox_url->isChecked();
}
void ConfigWidget::setShowComicAuthor( bool show )
{
appearanceUi.checkBox_author->setChecked( show );
}
bool ConfigWidget::showComicAuthor() const
{
return appearanceUi.checkBox_author->isChecked();
}
void ConfigWidget::setShowComicTitle( bool show )
{
appearanceUi.checkBox_title->setChecked( show );
}
bool ConfigWidget::showComicTitle() const
{
return appearanceUi.checkBox_title->isChecked();
}
void ConfigWidget::setShowComicIdentifier( bool show )
{
appearanceUi.checkBox_identifier->setChecked( show );
}
bool ConfigWidget::showComicIdentifier() const
{
return appearanceUi.checkBox_identifier->isChecked();
}
void ConfigWidget::setShowErrorPicture( bool show )
{
advancedUi.errorPicture->setChecked( show );
}
bool ConfigWidget::showErrorPicture() const
{
return advancedUi.errorPicture->isChecked();
}
void ConfigWidget::setArrowsOnHover( bool arrows )
{
return appearanceUi.checkBox_arrows->setChecked( arrows );
}
bool ConfigWidget::arrowsOnHover() const
{
return appearanceUi.checkBox_arrows->isChecked();
}
void ConfigWidget::setMiddleClick( bool checked )
{
comicUi.checkBox_middle->setChecked( checked );
}
bool ConfigWidget::middleClick() const
{
return comicUi.checkBox_middle->isChecked();
}
void ConfigWidget::setTabView(int tabView)
{
appearanceUi.kbuttongroup->setSelected( tabView );
}
int ConfigWidget::tabView() const
{
return appearanceUi.kbuttongroup->selected();
}
int ConfigWidget::maxComicLimit() const
{
return advancedUi.maxComicLimit->value();
}
void ConfigWidget::setMaxComicLimit( int limit )
{
advancedUi.maxComicLimit->setValue( limit );
}
void ConfigWidget::setUpdateIntervall( int days )
{
comicUi.updateIntervall->setValue( days );
}
int ConfigWidget::updateIntervall() const
{
return comicUi.updateIntervall->value();
}
void ConfigWidget::setCheckNewComicStripsIntervall( int minutes )
{
comicUi.updateIntervallComicStrips->setValue( minutes );
}
int ConfigWidget::checkNewComicStripsIntervall() const
{
return comicUi.updateIntervallComicStrips->value();
}
#include "configwidget.moc"

View file

@ -0,0 +1,139 @@
/***************************************************************************
* Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
* Copyright (C) 2008-2010 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 CONFIGWIDGET_H
#define CONFIGWIDGET_H
#include "ui_appearanceSettings.h"
#include "ui_advancedsettings.h"
#include "ui_comicSettings.h"
#include <QtGui/QWidget>
#include <QTime>
#include <KNS3/Entry>
#include <Plasma/DataEngine>
class ComicModel;
class KConfigDialog;
class QCheckBox;
class QComboBox;
class QSortFilterProxyModel;
namespace KNS3 {
class DownloadDialog;
class DownloadManager;
}
namespace Plasma {
class DataEngine;
}
class ConfigWidget;
class ComicUpdater : public QObject
{
Q_OBJECT
public:
explicit ComicUpdater( QObject *parent = 0 );
~ComicUpdater();
void init( const KConfigGroup &group );
void load();
void save();
void applyConfig( ConfigWidget *widget );
private slots:
/**
* Will check if an update is needed, if so will search
* for updates and do them automatically
*/
void checkForUpdate();
void slotUpdatesFound( const KNS3::Entry::List &entries );
private:
KNS3::DownloadManager *downloadManager();
private:
KNS3::DownloadManager *mDownloadManager;
KConfigGroup mGroup;
int mUpdateIntervall;
QDateTime mLastUpdate;
QTimer *m_updateTimer;
};
class ConfigWidget : public QWidget
{
Q_OBJECT
public:
ConfigWidget( Plasma::DataEngine *engine, ComicModel *model, QSortFilterProxyModel *proxy, KConfigDialog *parent );
~ConfigWidget();
void setShowComicUrl( bool show );
bool showComicUrl() const;
void setShowComicAuthor( bool show );
bool showComicAuthor() const;
void setShowComicTitle( bool show );
bool showComicTitle() const;
void setShowComicIdentifier( bool show );
bool showComicIdentifier() const;
void setShowErrorPicture( bool show );
bool showErrorPicture() const;
void setArrowsOnHover( bool arrows );
bool arrowsOnHover() const;
void setMiddleClick( bool checked );
bool middleClick() const;
void setTabView( int tabView );
int tabView() const;
int maxComicLimit() const;
void setMaxComicLimit( int limit );
void setUpdateIntervall( int days );
int updateIntervall() const;
void setCheckNewComicStripsIntervall( int minutes );
int checkNewComicStripsIntervall() const;
QWidget *comicSettings;
QWidget *appearanceSettings;
QWidget *advancedSettings;
Q_SIGNALS:
void maxSizeClicked();
void enableApply();
public slots:
void dataUpdated( const QString &name, const Plasma::DataEngine::Data &data );
protected slots:
void getNewStuff();
private:
Ui::ComicSettings comicUi;
Ui::AppearanceSettings appearanceUi;
Ui::AdvancedSettings advancedUi;
Plasma::DataEngine *mEngine;
ComicModel *mModel;
QSortFilterProxyModel *mProxyModel;
KNS3::DownloadDialog* mNewStuffDialog;
};
#endif

View file

@ -0,0 +1,75 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
Item {
id: root
implicitWidth: rowButton.width + background.margins.left + background.margins.right
implicitHeight: rowButton.height + background.margins.top + background.margins.bottom
signal prevClicked
signal nextClicked
signal zoomClicked
PlasmaCore.FrameSvgItem {
id: background
anchors.fill: parent
imagePath: "widgets/toolbar"
prefix: "raised"
}
Row {
id: rowButton
x: background.margins.left
y: background.margins.top
spacing: 4
//ToolButton or Button in C++ use PushButton?
PlasmaComponents.Button {
id: prevButton
iconSource: "arrow-left"
enabled: (comicData.prev != undefined && comicData.prev.length > 0)
}
PlasmaComponents.Button {
id: zoomButton
iconSource: "zoom-original"
}
PlasmaComponents.Button {
id: nextButton
iconSource: "arrow-right"
enabled: (comicData.next != undefined && comicData.next.length > 0)
}
}
Component.onCompleted: {
prevButton.clicked.connect(root.prevClicked);
nextButton.clicked.connect(root.nextClicked);
zoomButton.clicked.connect(root.zoomClicked);
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.qtextracomponents 0.1
Item {
id: root
implicitWidth: 10
implicitHeight: comicIdentifier.height
property bool showUrl: false
property bool showIdentifier: false
property variant comicData
visible: (comicIdentifier.text.length > 0 || comicUrl.text.length > 0)
PlasmaComponents.Label {
id: comicIdentifier
anchors {
left: root.left
top: root.top
bottom: root.bottom
right: comicUrl.left
leftMargin: 2
}
color: theme.textColor
visible: (showIdentifier && comicIdentifier.text.length > 0)
text: (showIdentifier && comicData.currentReadable != undefined) ? comicData.currentReadable : ""
MouseArea {
id: idLabelArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
parent.color = theme.highlightColor;
}
onExited: {
parent.color = theme.textColor;
}
onClicked: {
comicApplet.goJump();
}
PlasmaCore.ToolTip {
target: idLabelArea
mainText: i18n( "Jump to Strip ..." )
}
}
}
PlasmaComponents.Label {
id:comicUrl
anchors {
top: root.top
bottom: root.bottom
right: root.right
rightMargin: 2
}
color: theme.textColor
visible: (showUrl && comicUrl.text.length > 0)
text: (showUrl && comicData.websiteHost.length > 0) ? comicData.websiteHost : ""
MouseArea {
id: idUrlLabelArea
anchors.fill: parent
hoverEnabled: true
visible: comicApplet.checkAuthorization("LaunchApp")
onEntered: {
parent.color = theme.highlightColor;
}
onExited: {
parent.color = theme.textColor;
}
onClicked: {
comicApplet.shop();
}
PlasmaCore.ToolTip {
target: idUrlLabelArea
mainText: i18n( "Visit the comic website" )
}
}
}
}

View file

@ -0,0 +1,143 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.qtextracomponents 0.1
Item {
id: root
width: 10
height: 10
property variant comicData
PlasmaComponents.ToolButton {
id: arrowLeft
anchors {
left: root.left
verticalCenter: root.verticalCenter
}
iconSource: "go-previous"
visible: (!comicApplet.arrowsOnHover && (comicData.prev !== undefined))
onClicked: {
comicApplet.updateComic(comicData.prev);
}
}
MouseArea {
id: comicImageArea
anchors {
left: arrowLeft.visible ? arrowLeft.right : root.left
right: arrowRight.visible ? arrowRight.left : root.right
leftMargin: arrowLeft.visible ? 4 : 0
rightMargin: arrowRight.visible ? 4 : 0
top: root.top
bottom: root.bottom
}
hoverEnabled: true
preventStealing: false
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
onClicked: {
if (mouse.button == Qt.MiddleButton && comicApplet.middleClick) {
fullDialog.open();
}
}
PlasmaCore.ToolTip {
id: tooltip
target: comicImageArea
mainText: comicApplet.comicData.additionalText
}
ImageWidget {
id: comicImage
anchors.fill: parent
image: comicApplet.comicData.image
actualSize: comicApplet.showActualSize
isLeftToRight: comicApplet.comicData.isLeftToRight
isTopToBottom: comicApplet.comicData.isTopToBottom
}
ButtonBar {
id: buttonBar
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 10
}
visible: comicApplet.arrowsOnHover && comicImageArea.containsMouse//(comicApplet.arrowsOnHover && (comicImageArea.containsMouse || (comicImageArea.containsMouse && buttonBar.visible)) )
opacity: 0
onPrevClicked: {
comicApplet.updateComic(comicData.prev);
}
onNextClicked: {
comicApplet.updateComic(comicData.next);
}
onZoomClicked: {
fullDialog.open();
}
states: State {
name: "show"; when: (comicApplet.arrowsOnHover && comicImageArea.containsMouse)
PropertyChanges { target: buttonBar; opacity: 1; }
}
transitions: Transition {
from: ""; to: "show"; reversible: true
NumberAnimation { properties: "opacity"; duration: 250; easing.type: Easing.InOutQuad }
}
}
}
PlasmaComponents.ToolButton {
id: arrowRight
anchors {
right: root.right
verticalCenter: root.verticalCenter
}
iconSource: "go-next"
visible: (!comicApplet.arrowsOnHover && (comicData.next !== undefined))
onClicked: {
comicApplet.updateComic(comicData.next);
}
}
FullViewWidget {
id: fullDialog
image: comicApplet.comicData.image
}
}

View file

@ -0,0 +1,85 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.plasma.extras 0.1 as PlasmaExtras
import org.kde.qtextracomponents 0.1
PlasmaCore.Dialog {
id: root
property alias image: comicPicture.image
windowFlags: Qt.Popup
visible: false
function open()
{
var pos = root.popupPosition(null, Qt.AlignCenter);
root.x = pos.x;
root.y = pos.y;
root.visible = true;
root.activateWindow();
}
function close() {
root.visible = false;
}
mainItem: PlasmaExtras.ScrollArea {
id: mainScrollArea
anchors.fill: parent
width: comicPicture.nativeWidth
height: comicPicture.nativeHeight
Flickable {
id: viewContainer
anchors.fill:parent
contentWidth: comicPicture.nativeWidth
contentHeight: comicPicture.nativeHeight
//clip: true
QImageItem {
id: comicPicture
anchors.fill: parent
smooth: true
fillMode: QImageItem.PreserveAspectFit
MouseArea {
id: dialogMouseArea
anchors.fill: comicPicture
onClicked: {
root.close();
}
}
}
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.plasma.extras 0.1 as PlasmaExtras
import org.kde.qtextracomponents 0.1
PlasmaExtras.ScrollArea {
id: root
width: comicPicture.nativeWidth
height: comicPicture.nativeHeight
property bool actualSize: false
property bool isLeftToRight: true
property bool isTopToBottom: true
property alias image: comicPicture.image
function calculateContentWidth() {
return actualSize ? (comicPicture.nativeWidth > viewContainer.width ? comicPicture.nativeWidth : viewContainer.width) : viewContainer.width;
}
function calculateContentHeight() {
return actualSize ? (comicPicture.nativeHeight > viewContainer.height ? comicPicture.nativeHeight : viewContainer.height) : viewContainer.height;
}
Flickable {
id: viewContainer
anchors.fill:parent
contentWidth: comicPictureHolder.width
contentHeight: comicPictureHolder.height
clip: true
Item {
id: comicPictureHolder
width: Math.max(comicPicture.width, viewContainer.width);
height: Math.max(comicPicture.height, viewContainer.height);
QImageItem {
id: comicPicture
anchors.centerIn: parent
width: actualSize ? comicPicture.nativeWidth : viewContainer.width
height: actualSize ? comicPicture.nativeHeight : viewContainer.height
onImageChanged: {
viewContainer.contentX = (root.isLeftToRight) ? 0 : ( viewContainer.contentWidth - viewContainer.width);
viewContainer.contentY = (root.isTopToBottom) ? 0 : ( viewContainer.contentHeight - viewContainer.height);
}
smooth: true
fillMode: QImageItem.PreserveAspectFit
}
}
}
}

View file

@ -0,0 +1,228 @@
/*
* Copyright 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 1.1
import org.kde.plasma.core 0.1 as PlasmaCore
import org.kde.plasma.components 0.1 as PlasmaComponents
import org.kde.qtextracomponents 0.1
Item {
id: mainWindow
width: minimumWidth
height: minimumHeight
property int minimumWidth: theme.defaultFont.mSize.width * 35
property int minimumHeight: theme.defaultFont.mSize.height * 12
property bool showComicAuthor: comicApplet.showComicAuthor
property bool showComicTitle: comicApplet.showComicTitle
property bool showErrorPicture: comicApplet.showErrorPicture
property bool middleClick: comicApplet.middleClick
Connections {
target: comicApplet
onComicsModelChanged: {
comicTabbar.currentTab = comicTabbar.layout.children[1];
}
onTabHighlightRequest: {
for (var i = 0; i < comicTabbar.layout.children.length; ++i) {
var button = comicTabbar.layout.children[i];
if (button.key !== undefined && button.key == id) {
button.highlighted = highlight;
}
}
}
onShowNextNewStrip: {
var firstButton = undefined;
for (var i = 0; i < comicTabbar.layout.children.length; ++i) {
var button = comicTabbar.layout.children[i];
if (button.key !== undefined && button.highlighted == true) {
//key is ordered
if (button.key > comicTabbar.currentTab.key) {
comicTabbar.currentTab = button;
return;
} else if (firstButton === undefined){
firstButton = button;
}
}
}
if (firstButton !== undefined) {
comicTabbar.currentTab = firstButton;
}
}
}
PlasmaCore.Theme {
id: theme
}
PlasmaCore.Svg {
id: arrowsSvg
imagePath: "widgets/arrows"
}
PlasmaComponents.TabBar{
id: comicTabbar
anchors {
left: parent.left
right: parent.right
}
visible: (comicApplet.comicsModel.count > 1)
onCurrentTabChanged: {
console.log("onCurrentTabChanged:" + comicTabbar.currentTab.key);
comicApplet.tabChanged(comicTabbar.currentTab.key);
}
Repeater {
model: comicApplet.comicsModel
delegate: PlasmaComponents.TabButton {
id: tabButton
property string key: model.key
property bool highlighted: model.highlight
text: model.title
iconSource: model.icon
Rectangle {
id: highlightMask
anchors {
bottom: parent.bottom
left: parent.left
}
width: Math.max(theme.smallIconSize, tabButton.height)
height: Math.max(theme.smallIconSize, tabButton.height)
color: "white"
opacity: model.highlight ? 0 : 0.5
}
}
}
}
PlasmaComponents.Label {
id: topInfo
anchors {
top: comicTabbar.visible ? comicTabbar.bottom : mainWindow.top
left: mainWindow.left
right: mainWindow.right
}
visible: (topInfo.text.length > 0)
horizontalAlignment: Text.AlignHCenter
text: (showComicAuthor || showComicTitle) ? getTopInfo() : ""
function getTopInfo() {
var tempTop = "";
if ( showComicTitle ) {
tempTop = comicApplet.comicData.title;
tempTop += ( ( (comicApplet.comicData.stripTitle.length > 0) && (comicApplet.comicData.title.length > 0) ) ? " - " : "" ) + comicApplet.comicData.stripTitle;
}
if ( showComicAuthor &&
(comicApplet.comicData.author != undefined || comicApplet.comicData.author.length > 0) ) {
tempTop = ( tempTop.length > 0 ? comicApplet.comicData.author + ": " + tempTop : comicApplet.comicData.author );
}
return tempTop;
}
}
ComicCentralView {
id: centerLayout
anchors {
left: mainWindow.left
right: mainWindow.right
bottom: (bottomInfo.visible) ? bottomInfo.top : mainWindow.bottom
top: (topInfo.visible) ? topInfo.bottom : (comicTabbar.visible ? comicTabbar.bottom : mainWindow.top)
topMargin: (comicTabbar.visible) ? 3 : 0
}
comicData: comicApplet.comicData
}
ComicBottomInfo {
id:bottomInfo
anchors {
left: mainWindow.left
right: mainWindow.right
bottom: mainWindow.bottom
}
comicData: comicApplet.comicData
showUrl: comicApplet.showComicUrl
showIdentifier: comicApplet.showComicIdentifier
}
PlasmaComponents.BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
running: visible
visible: false
}
states: [
State {
name: "topInfoVisible"
when: topInfo.visible && !bottomInfo.visible
AnchorChanges {
target: centerLayout
anchors.top: topInfo.bottom
}
},
State {
name: "bottomInfoVisible"
when: bottomInfo.visible && !topInfo.visible
AnchorChanges {
target: centerLayout
anchors.bottom: bottomInfo.top
}
},
State {
name: "topBottomInfoVisible"
when: bottomInfo.visible && topInfo.visible
AnchorChanges {
target: centerLayout
anchors.top: topInfo.bottom
anchors.bottom: bottomInfo.top
}
}
]
transitions:
Transition {
AnchorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
}

View file

@ -0,0 +1,128 @@
[Desktop Entry]
Name=Comic Strip
Name[ar]=شريط هزلي
Name[ast]=Tira de cómic
Name[bs]=stripovi
Name[ca]=Tira còmica
Name[ca@valencia]=Tira còmica
Name[cs]=Komiksový proužek
Name[csb]=Kòmiksowi sztrépk
Name[da]=Tegneseriestribe
Name[de]=Comic
Name[el]=Σειρά κόμικ
Name[en_GB]=Comic Strip
Name[es]=Tira de cómic
Name[et]=Koomiks
Name[eu]=Komiki zerrenda
Name[fi]=Sarjakuvastrippi
Name[fr]=Bande dessinée
Name[ga]=Stiallchartún
Name[gl]=Banda deseñada
Name[he]=קומיקס
Name[hr]=Strip
Name[hu]=Képregény
Name[is]=Myndasögur
Name[it]=Striscia di fumetti
Name[ja]=
Name[kk]=Комикс
Name[km]=
Name[ko]=
Name[ku]=Pirtûka Qerfî
Name[lv]=Komikss
Name[mr]=ि
Name[nb]=Comic Strip
Name[nds]=Comic
Name[nl]=Stripboek
Name[nn]=Teikneserie
Name[pa]=
Name[pl]=Komiks
Name[pt]=Banda Desenhada
Name[pt_BR]=Tirinha
Name[ro]=Benzi desenate
Name[ru]=Комиксы
Name[sk]=Komiks
Name[sl]=Smešen strip
Name[sr]=стрипови
Name[sr@ijekavian]=стрипови
Name[sr@ijekavianlatin]=stripovi
Name[sr@latin]=stripovi
Name[sv]=Tecknad serie
Name[th]=
Name[tr]=Çizgi Roman
Name[uk]=Комічна стрічка
Name[wa]=Binde d' imådje
Name[x-test]=xxComic Stripxx
Name[zh_CN]=
Name[zh_TW]=
Comment=View comic strips from the Internet
Comment[ar]=اعرض شرائط هزلية من الإنترنت
Comment[ast]=Amuesa tires de cómic d'Internet
Comment[bs]=Pogledajte stripove sa Interneta
Comment[ca]=Mostra una tira còmica des d'Internet
Comment[ca@valencia]=Mostra una tira còmica des d'Internet
Comment[cs]=Ukáže komiksový proužek z internetu
Comment[da]=Se tegneseriestriber fra internettet.
Comment[de]=Comics aus dem Internet anzeigen
Comment[el]=Εμφάνιση σειρών κόμικ από το διαδίκτυο
Comment[en_GB]=View comic strips from the Internet
Comment[es]=Muestra tiras de cómic de Internet
Comment[et]=Internetist hangitud koomiksite näitamine
Comment[eu]=Interneteko komiki zerrendak ikusi
Comment[fi]=Katso sarjakuvia internetistä
Comment[fr]=Affiche une bande dessinée provenant d'Internet
Comment[ga]=Taispeáin stiallchartún ón Idirlíon
Comment[gl]=Mostra bandas deseñadas de internet
Comment[he]=מציג קומיקסים נבחרים מהאינטרנט
Comment[hr]=Prikaži stripove na Internetu
Comment[hu]=Képregények megjelenítése az internetről
Comment[is]=Skoða myndasögur af netinu
Comment[it]=Vedi una striscia di fumetti da Internet.
Comment[ja]=
Comment[kk]=Интернеттен комиксті қарау
Comment[km]=
Comment[ko]=
Comment[ku]=Ji Torê pirtûkên qerfî bibîne
Comment[lv]=Rāda komiksus no interneta
Comment[mr]= ि
Comment[nb]=Vis tegneserier fra Internett
Comment[nds]=Comics ut dat Internet ankieken
Comment[nl]=Toont stripboeken van het internet
Comment[nn]=Vis teikneseriar frå Internett
Comment[pa]=
Comment[pl]=Przeglądanie komiksów z Internetu
Comment[pt]=Mostra bandas desenhadas da Internet
Comment[pt_BR]=Exibe uma tirinha da Internet
Comment[ro]=Afișează benzi desenate din Internet
Comment[ru]=Просмотр комиксов из Интернета
Comment[sk]=Zobrazenie komiksov z internetu
Comment[sl]=Oglejte si smešne stripe z interneta
Comment[sr]=Погледајте стрипове са Интернета
Comment[sr@ijekavian]=Погледајте стрипове са Интернета
Comment[sr@ijekavianlatin]=Pogledajte stripove sa Interneta
Comment[sr@latin]=Pogledajte stripove sa Interneta
Comment[sv]=Visa tecknade serier från Internet
Comment[th]=
Comment[tr]=İnternet'ten çizgi roman karikatürleri göster
Comment[uk]=Показує стрічку з жартами з Інтернету
Comment[wa]=Vey ene binde d' imådje di l' Etrernet
Comment[x-test]=xxView comic strips from the Internetxx
Comment[zh_CN]=
Comment[zh_TW]=
Icon=face-smile-big
Type=Service
X-KDE-ServiceTypes=Plasma/Applet
X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/main.qml
X-Plasma-DefaultSize=600,250
X-KDE-PluginInfo-Author=Reza Fatahilah Shah
X-KDE-PluginInfo-Email=rshah0385@kireihana.com
X-KDE-PluginInfo-Name=comic
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Graphics
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Optional
X-Plasma-Requires-LaunchApp=Optional

View file

@ -0,0 +1,126 @@
[Desktop Entry]
Name=Comic Strip
Name[ar]=شريط هزلي
Name[ast]=Tira de cómic
Name[bs]=stripovi
Name[ca]=Tira còmica
Name[ca@valencia]=Tira còmica
Name[cs]=Komiksový proužek
Name[csb]=Kòmiksowi sztrépk
Name[da]=Tegneseriestribe
Name[de]=Comic
Name[el]=Σειρά κόμικ
Name[en_GB]=Comic Strip
Name[es]=Tira de cómic
Name[et]=Koomiks
Name[eu]=Komiki zerrenda
Name[fi]=Sarjakuvastrippi
Name[fr]=Bande dessinée
Name[ga]=Stiallchartún
Name[gl]=Banda deseñada
Name[he]=קומיקס
Name[hr]=Strip
Name[hu]=Képregény
Name[is]=Myndasögur
Name[it]=Striscia di fumetti
Name[ja]=
Name[kk]=Комикс
Name[km]=
Name[ko]=
Name[ku]=Pirtûka Qerfî
Name[lv]=Komikss
Name[mr]=ि
Name[nb]=Comic Strip
Name[nds]=Comic
Name[nl]=Stripboek
Name[nn]=Teikneserie
Name[pa]=
Name[pl]=Komiks
Name[pt]=Banda Desenhada
Name[pt_BR]=Tirinha
Name[ro]=Benzi desenate
Name[ru]=Комиксы
Name[sk]=Komiks
Name[sl]=Smešen strip
Name[sr]=стрипови
Name[sr@ijekavian]=стрипови
Name[sr@ijekavianlatin]=stripovi
Name[sr@latin]=stripovi
Name[sv]=Tecknad serie
Name[th]=
Name[tr]=Çizgi Roman
Name[uk]=Комічна стрічка
Name[wa]=Binde d' imådje
Name[x-test]=xxComic Stripxx
Name[zh_CN]=
Name[zh_TW]=
Comment=View comic strips from the Internet
Comment[ar]=اعرض شرائط هزلية من الإنترنت
Comment[ast]=Amuesa tires de cómic d'Internet
Comment[bs]=Pogledajte stripove sa Interneta
Comment[ca]=Mostra una tira còmica des d'Internet
Comment[ca@valencia]=Mostra una tira còmica des d'Internet
Comment[cs]=Ukáže komiksový proužek z internetu
Comment[da]=Se tegneseriestriber fra internettet.
Comment[de]=Comics aus dem Internet anzeigen
Comment[el]=Εμφάνιση σειρών κόμικ από το διαδίκτυο
Comment[en_GB]=View comic strips from the Internet
Comment[es]=Muestra tiras de cómic de Internet
Comment[et]=Internetist hangitud koomiksite näitamine
Comment[eu]=Interneteko komiki zerrendak ikusi
Comment[fi]=Katso sarjakuvia internetistä
Comment[fr]=Affiche une bande dessinée provenant d'Internet
Comment[ga]=Taispeáin stiallchartún ón Idirlíon
Comment[gl]=Mostra bandas deseñadas de internet
Comment[he]=מציג קומיקסים נבחרים מהאינטרנט
Comment[hr]=Prikaži stripove na Internetu
Comment[hu]=Képregények megjelenítése az internetről
Comment[is]=Skoða myndasögur af netinu
Comment[it]=Vedi una striscia di fumetti da Internet.
Comment[ja]=
Comment[kk]=Интернеттен комиксті қарау
Comment[km]=
Comment[ko]=
Comment[ku]=Ji Torê pirtûkên qerfî bibîne
Comment[lv]=Rāda komiksus no interneta
Comment[mr]= ि
Comment[nb]=Vis tegneserier fra Internett
Comment[nds]=Comics ut dat Internet ankieken
Comment[nl]=Toont stripboeken van het internet
Comment[nn]=Vis teikneseriar frå Internett
Comment[pa]=
Comment[pl]=Przeglądanie komiksów z Internetu
Comment[pt]=Mostra bandas desenhadas da Internet
Comment[pt_BR]=Exibe uma tirinha da Internet
Comment[ro]=Afișează benzi desenate din Internet
Comment[ru]=Просмотр комиксов из Интернета
Comment[sk]=Zobrazenie komiksov z internetu
Comment[sl]=Oglejte si smešne stripe z interneta
Comment[sr]=Погледајте стрипове са Интернета
Comment[sr@ijekavian]=Погледајте стрипове са Интернета
Comment[sr@ijekavianlatin]=Pogledajte stripove sa Interneta
Comment[sr@latin]=Pogledajte stripove sa Interneta
Comment[sv]=Visa tecknade serier från Internet
Comment[th]=
Comment[tr]=İnternet'ten çizgi roman karikatürleri göster
Comment[uk]=Показує стрічку з жартами з Інтернету
Comment[wa]=Vey ene binde d' imådje di l' Etrernet
Comment[x-test]=xxView comic strips from the Internetxx
Comment[zh_CN]=
Comment[zh_TW]=
Icon=face-smile-big
Type=Service
X-KDE-ServiceTypes=Plasma/Applet
X-KDE-Library=plasma_applet_comic
X-KDE-PluginInfo-Author=Tobias Koenig
X-KDE-PluginInfo-Email=tokoe@kde.org
X-KDE-PluginInfo-Name=comic
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://plasma.kde.org/
X-KDE-PluginInfo-Category=Graphics
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-Plasma-Requires-FileDialog=Optional
X-Plasma-Requires-LaunchApp=Optional

View file

@ -0,0 +1,179 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 "stripselector.h"
#include "stripselector_p.h"
#include "comicdata.h"
#include <KDatePicker>
#include <KDialog>
#include <KInputDialog>
#include <KNumInput>
#include <QtCore/QScopedPointer>
#include <QtCore/QTimer>
#include <QtGui/QLabel>
#include <QtGui/QVBoxLayout>
//NOTE based on GotoPageDialog KDE/kdegraphics/okular/part.cpp
//BEGIN choose a strip dialog
class ChooseStripNumDialog : public KDialog
{
public:
ChooseStripNumDialog(QWidget *parent, int current, int min, int max)
: KDialog( parent )
{
setCaption(i18n("Go to Strip"));
setButtons(Ok | Cancel);
setDefaultButton(Ok);
QWidget *widget = new QWidget(this);
setMainWidget(widget);
QVBoxLayout *topLayout = new QVBoxLayout(widget);
topLayout->setMargin(0);
topLayout->setSpacing(spacingHint());
numInput = new KIntNumInput(current, widget);
numInput->setRange(min, max);
numInput->setEditFocus(true);
numInput->setSliderEnabled(true);
QLabel *label = new QLabel(i18n("&Strip Number:"), widget);
label->setBuddy(numInput);
topLayout->addWidget(label);
topLayout->addWidget(numInput) ;
// A little bit extra space
topLayout->addSpacing(spacingHint());
topLayout->addStretch(10);
numInput->setFocus();
}
int getStripNumber() const
{
return numInput->value();
}
protected:
KIntNumInput *numInput;
};
//END choose a strip dialog
StripSelector::StripSelector(QObject *parent)
: QObject(parent)
{
}
StripSelector::~StripSelector()
{
}
StripSelector *StripSelectorFactory::create(IdentifierType type)
{
switch (type) {
case Number:
return new NumberStripSelector();
case Date:
return new DateStripSelector();
case String:
return new StringStripSelector();
}
return 0;
}
StringStripSelector::StringStripSelector(QObject *parent)
: StripSelector(parent)
{
}
StringStripSelector::~StringStripSelector()
{
}
void StringStripSelector::select(const ComicData &currentStrip)
{
bool ok;
const QString strip = KInputDialog::getText(i18n("Go to Strip"), i18n("Strip identifier:"),
currentStrip.current(), &ok);
if (ok) {
emit stripChosen(strip);
}
deleteLater();
}
NumberStripSelector::NumberStripSelector(QObject *parent)
: StripSelector(parent)
{
}
NumberStripSelector::~NumberStripSelector()
{
}
void NumberStripSelector::select(const ComicData &currentStrip)
{
QScopedPointer<ChooseStripNumDialog> pageDialog(new ChooseStripNumDialog(0, currentStrip.current().toInt(),
currentStrip.firstStripNum(), currentStrip.maxStripNum()));
if (pageDialog->exec() == QDialog::Accepted) {
emit stripChosen(QString::number(pageDialog->getStripNumber()));
}
deleteLater();
}
DateStripSelector::DateStripSelector(QObject *parent)
: StripSelector(parent)
{
}
DateStripSelector::~DateStripSelector()
{
}
void DateStripSelector::select(const ComicData &currentStrip)
{
mFirstIdentifierSuffix = currentStrip.first();
KDatePicker *calendar = new KDatePicker;
calendar->setAttribute(Qt::WA_DeleteOnClose);//to have destroyed emitted upon closing
calendar->setMinimumSize(calendar->sizeHint());
calendar->setDate(QDate::fromString(currentStrip.current(), "yyyy-MM-dd"));
connect(calendar, SIGNAL(dateSelected(QDate)), this, SLOT(slotChosenDay(QDate)));
connect(calendar, SIGNAL(dateEntered(QDate)), this, SLOT(slotChosenDay(QDate)));
// only delete this if the dialog got closed
connect(calendar, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()));
calendar->show();
}
void DateStripSelector::slotChosenDay(const QDate &date)
{
if (date <= QDate::currentDate()) {
QDate temp = QDate::fromString(mFirstIdentifierSuffix, "yyyy-MM-dd");
// only update if date >= first strip date, or if there is no first
// strip date
if (temp.isValid() || date >= temp) {
emit stripChosen(date.toString("yyyy-MM-dd"));
}
}
}
#include "stripselector.moc"
#include "stripselector_p.moc"

View file

@ -0,0 +1,72 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 STRIP_SELECTOR_H
#define STRIP_SELECTOR_H
#include <QtCore/QObject>
#include "comicinfo.h"
class ComicData;
class QDate;
/**
* Enables users to visually select a strip they want to navigate to.
* Subclasses implement different Selectors for the different comic
* types.
* @note use the StripSelectorFactory to retrieve an appropriate
* StripSelector
*/
class StripSelector : public QObject
{
Q_OBJECT
public:
virtual ~StripSelector();
/**
* Select a strip depending on the subclass
* @param currentStrip the currently active strip
* @note StripSelector takes care to delete itself
*/
virtual void select(const ComicData &currentStrip) = 0;
signals:
/**
* @param strip the selected strip, can be empty
*
*/
void stripChosen(const QString &strip);
protected:
explicit StripSelector(QObject *parent = 0);
};
/**
* Class to retrrieve the correct StripSelector depending on the
* specified IdentifierType
*/
class StripSelectorFactory
{
public:
static StripSelector *create(IdentifierType type);
};
#endif

View file

@ -0,0 +1,62 @@
/***************************************************************************
* Copyright (C) 2012 Matthias Fuchs <mat69@gmx.net> *
* *
* 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 STRIP_SELECTOR_P_H
#define STRIP_SELECTOR_P_H
#include "stripselector.h"
#include <QtCore/QString>
class StringStripSelector : public StripSelector
{
public:
explicit StringStripSelector(QObject *parent = 0);
virtual ~StringStripSelector();
virtual void select(const ComicData &currentStrip);
};
class NumberStripSelector : public StripSelector
{
public:
explicit NumberStripSelector(QObject *parent = 0);
virtual ~NumberStripSelector();
virtual void select(const ComicData &currentStrip);
};
class DateStripSelector : public StripSelector
{
Q_OBJECT
public:
explicit DateStripSelector(QObject *parent = 0);
virtual ~DateStripSelector();
virtual void select(const ComicData &currentStrip);
private slots:
void slotChosenDay(const QDate &date);
private:
QString mFirstIdentifierSuffix;
};
#endif

View file

@ -0,0 +1,43 @@
project(plasma-opendesktop)
set(opendesktop_SRCS
actionstack.cpp
loginwidget.cpp
friendlist.cpp
contactcontainer.cpp
friendmanagementcontainer.cpp
friendmanagementwidget.cpp
messagecounter.cpp
requestfriendshipwidget.cpp
messagelist.cpp
messagewatchlist.cpp
messagewidget.cpp
personwatch.cpp
personwatchlist.cpp
sourcewatchlist.cpp
utils.cpp
sendmessagewidget.cpp
opendesktop.cpp
contactwidget.cpp
userwidget.cpp
contactimage.cpp
stylesheet.cpp
contactlist.cpp
)
kde4_add_ui_files(opendesktop_SRCS opendesktopConfig.ui opendesktopLocationConfig.ui )
kde4_add_plugin(plasma_applet_opendesktop ${opendesktop_SRCS})
target_link_libraries(
plasma_applet_opendesktop
${KDE4_KIO_LIBS}
${KDE4_PLASMA_LIBS}
${KDE4_KCMUTILS_LIBS}
${QT_QTWEBKIT_LIBRARY}
)
install(TARGETS plasma_applet_opendesktop DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-applet-opendesktop.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(FILES user.css DESTINATION ${DATA_INSTALL_DIR}/plasma-applet-opendesktop/)

Some files were not shown because too many files have changed in this diff Show more