initial import of ark
4
ark/.reviewboardrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
REPOSITORY = "git://anongit.kde.org/ark"
|
||||||
|
REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
|
||||||
|
TARGET_GROUPS = "kdeutils"
|
||||||
|
TARGET_PEOPLE = "rkcosta"
|
50
ark/CMakeLists.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
project(ark)
|
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
find_package(KDE4)
|
||||||
|
include( KDE4Defaults )
|
||||||
|
include_directories(${KDE4_INCLUDES})
|
||||||
|
|
||||||
|
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||||
|
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
|
||||||
|
|
||||||
|
# If definitions like -D_GNU_SOURCE are needed for these checks they
|
||||||
|
# should be added to _KDE4_PLATFORM_DEFINITIONS when it is originally
|
||||||
|
# defined outside this file. Here we include these definitions in
|
||||||
|
# CMAKE_REQUIRED_DEFINITIONS so they will be included in the build of
|
||||||
|
# checks below.
|
||||||
|
set( CMAKE_REQUIRED_DEFINITIONS ${_KDE4_PLATFORM_DEFINITIONS} )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include( MacroLibrary )
|
||||||
|
list(APPEND CMAKE_MODULE_PATH ${ark_SOURCE_DIR}/cmake/modules)
|
||||||
|
|
||||||
|
macro_optional_find_package(LibArchive)
|
||||||
|
macro_log_feature(LIBARCHIVE_FOUND "LibArchive" "A library for dealing with a wide variety of archive file formats" "http://code.google.com/p/libarchive/" FALSE "" "Required for among others tar, tar.gz, tar.bz2 formats in Ark.")
|
||||||
|
|
||||||
|
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake)
|
||||||
|
|
||||||
|
add_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||||
|
|
||||||
|
option(WITH_TEST_COVERAGE "Build with test coverage support" OFF)
|
||||||
|
if (WITH_TEST_COVERAGE)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
|
||||||
|
endif (WITH_TEST_COVERAGE)
|
||||||
|
|
||||||
|
set(SUPPORTED_ARK_MIMETYPES "")
|
||||||
|
|
||||||
|
add_subdirectory(plugins)
|
||||||
|
add_subdirectory(kerfuffle)
|
||||||
|
add_subdirectory(part)
|
||||||
|
add_subdirectory(app)
|
||||||
|
add_subdirectory(doc)
|
||||||
|
|
||||||
|
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
message(STATUS "Supported MIME types: ${SUPPORTED_ARK_MIMETYPES}")
|
||||||
|
macro_display_feature_log()
|
||||||
|
endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
|
346
ark/COPYING
Normal 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.
|
216
ark/COPYING.icons
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
The Oxygen Icon Theme
|
||||||
|
Copyright (C) 2007 Nuno Pinheiro <nuno@oxygen-icons.org>
|
||||||
|
Copyright (C) 2007 David Vignoni <david@icon-king.com>
|
||||||
|
Copyright (C) 2007 David Miller <miller@oxygen-icons.org>
|
||||||
|
Copyright (C) 2007 Johann Ollivier Lapeyre <johann@oxygen-icons.org>
|
||||||
|
Copyright (C) 2007 Kenneth Wimer <kwwii@bootsplash.org>
|
||||||
|
Copyright (C) 2007 Riccardo Iaconelli <riccardo@oxygen-icons.org>
|
||||||
|
|
||||||
|
|
||||||
|
and others
|
||||||
|
|
||||||
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Clarification:
|
||||||
|
|
||||||
|
The GNU Lesser General Public License or LGPL is written for
|
||||||
|
software libraries in the first place. We expressly want the LGPL to
|
||||||
|
be valid for this artwork library too.
|
||||||
|
|
||||||
|
KDE Oxygen theme icons is a special kind of software library, it is an
|
||||||
|
artwork library, it's elements can be used in a Graphical User Interface, or
|
||||||
|
GUI.
|
||||||
|
|
||||||
|
Source code, for this library means:
|
||||||
|
- where they exist, SVG;
|
||||||
|
- otherwise, if applicable, the multi-layered formats xcf or psd, or
|
||||||
|
otherwise png.
|
||||||
|
|
||||||
|
The LGPL in some sections obliges you to make the files carry
|
||||||
|
notices. With images this is in some cases impossible or hardly useful.
|
||||||
|
|
||||||
|
With this library a notice is placed at a prominent place in the directory
|
||||||
|
containing the elements. You may follow this practice.
|
||||||
|
|
||||||
|
The exception in section 5 of the GNU Lesser General Public License covers
|
||||||
|
the use of elements of this art library in a GUI.
|
||||||
|
|
||||||
|
kde-artists [at] kde.org
|
||||||
|
|
||||||
|
-----
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
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 that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU 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 as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
13
ark/CTestConfig.cmake
Normal 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 "ark")
|
||||||
|
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=ark")
|
||||||
|
set(CTEST_DROP_SITE_CDASH TRUE)
|
1
ark/CTestCustom.cmake.in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
set(CTEST_CUSTOM_COVERAGE_EXCLUDE ".moc$" "moc_" "ui_")
|
52
ark/HACKING
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
== Coding Style ==
|
||||||
|
Ark follows the kdelibs/Qt coding style. For more information about them,
|
||||||
|
please see:
|
||||||
|
|
||||||
|
- http://techbase.kde.org/Policies/Kdelibs_Coding_Style
|
||||||
|
- http://wiki.qt-project.org/Coding_Style
|
||||||
|
- http://wiki.qt-project.org/Coding_Conventions
|
||||||
|
|
||||||
|
== Sending patches ==
|
||||||
|
To send patches for Ark, you can either use git's send-email command and send
|
||||||
|
it to the kde-utils-devel@kde.org mailing list, or use KDE's ReviewBoard tool
|
||||||
|
in <https://git.reviewboard.kde.org>. In case you choose the latter, the
|
||||||
|
review should be sent for the Ark product, and the `kdeutils' group should be
|
||||||
|
added to the review request.
|
||||||
|
|
||||||
|
If you already have a KDE commit account, it is still preferrable to contact
|
||||||
|
the maintainer instead of committing directly, at least to be a good citizen
|
||||||
|
and especially so that git mistakes are not made (see the `Using git' section).
|
||||||
|
|
||||||
|
== Using git ==
|
||||||
|
The development model adopted by Ark is simple and rely on git's easy merging
|
||||||
|
and branching capabilities. If in doubt, do not hesitate to ask!
|
||||||
|
|
||||||
|
First of all, you should do your work in a separate branch, and each commit
|
||||||
|
should be as atomic as possible. This way, if you are asked to make changes to
|
||||||
|
them, the rest of your work is not disturbed and you can easily rebase.
|
||||||
|
|
||||||
|
New features are committed to the `master' branch, respecting KDE's Release
|
||||||
|
Schedule policies. This means the soft and hard freeze periods must be
|
||||||
|
respected, as well as the string freeze policy.
|
||||||
|
|
||||||
|
Bug fixes are committed to the latest stable branch (for example, KDE/4.8),
|
||||||
|
which is then merged into the `master' branch. Do *NOT* cherry-pick commits
|
||||||
|
into multiple branches! It makes following history unnecessarily harder for no
|
||||||
|
reason.
|
||||||
|
|
||||||
|
To merge the stable branch into `master', the following steps can be followed:
|
||||||
|
|
||||||
|
$ git checkout KDE/4.8 # Whatever the stable branch is
|
||||||
|
$ # hack, hack, hack
|
||||||
|
$ # commit
|
||||||
|
$ git checkout master
|
||||||
|
$ git merge --log --edit -s recursive -Xours KDE/4.8
|
||||||
|
|
||||||
|
Do not worry if unrelated commits (such as translation ones made by KDE's
|
||||||
|
translation infrastructure) are also merged: translation commits are
|
||||||
|
automatically reverted when needed, and other commits being merged should be
|
||||||
|
bug fixes by definition.
|
||||||
|
|
||||||
|
When committing your changes, do *NOT* create unnecessary merge commits with
|
||||||
|
`git pull', as these commits are completely avoidable and make following
|
||||||
|
history harder. If you are committing your changes, *rebase* first.
|
8
ark/Mainpage.dox
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/** @mainpage ark
|
||||||
|
|
||||||
|
The ark application
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DOXYGEN_REFERENCES = kdecore
|
||||||
|
// DOXYGEN_SET_PROJECT_NAME = ark
|
6
ark/Messages.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#! /bin/sh
|
||||||
|
$EXTRACTRC $(find . -name '*.rc') >> rc.cpp || exit 11
|
||||||
|
$EXTRACTRC $(find . -name '*.ui') >> rc.cpp || exit 12
|
||||||
|
$EXTRACTRC $(find . -name '*.kcfg') >> rc.cpp
|
||||||
|
$XGETTEXT app/*.cpp kerfuffle/*.cpp part/*.cpp plugins/*/*.cpp rc.cpp -o $podir/ark.pot
|
||||||
|
rm -f rc.cpp
|
50
ark/app/CMakeLists.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
add_subdirectory(icons)
|
||||||
|
|
||||||
|
set(ark_SRCS
|
||||||
|
batchextract.cpp
|
||||||
|
main.cpp
|
||||||
|
mainwindow.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# For Mac and Windows.
|
||||||
|
kde4_add_app_icon(ark_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/hi*-apps-ark.png")
|
||||||
|
|
||||||
|
kde4_add_executable( ark ${ark_SRCS} )
|
||||||
|
|
||||||
|
target_link_libraries( ark kerfuffle ${KDE4_KFILE_LIBS} ${KDE4_KPARTS_LIBS} )
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ark.desktop.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/ark.desktop
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ark_dndextract.desktop.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/ark_dndextract.desktop
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ark_servicemenu.desktop.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/ark_servicemenu.desktop
|
||||||
|
)
|
||||||
|
|
||||||
|
install( TARGETS ark ${INSTALL_TARGETS_DEFAULT_ARGS} )
|
||||||
|
install(FILES ark_addtoservicemenu.desktop ${CMAKE_CURRENT_BINARY_DIR}/ark_servicemenu.desktop DESTINATION ${SERVICES_INSTALL_DIR}/ServiceMenus)
|
||||||
|
install( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ark.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
|
||||||
|
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/ark.appdata.xml DESTINATION share/appdata )
|
||||||
|
install( FILES arkui.rc DESTINATION ${DATA_INSTALL_DIR}/ark )
|
||||||
|
|
||||||
|
########### konqueror ark_extract_here plugin ###############
|
||||||
|
macro_optional_find_package( LibKonq )
|
||||||
|
macro_log_feature( LIBKONQ_FOUND "LIBKONQ" "libkonq library" "kdebase" FALSE "" "Need to integrate in konqueror" )
|
||||||
|
|
||||||
|
|
||||||
|
if (LIBKONQ_FOUND)
|
||||||
|
set(extracthere_SRCS batchextract.cpp extractHereDndPlugin.cpp)
|
||||||
|
kde4_add_plugin(extracthere WITH_PREFIX ${extracthere_SRCS})
|
||||||
|
target_link_libraries(extracthere kerfuffle ${KDE4_KDECORE_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KFILE_LIBS} ${LIBKONQ_LIBRARY} )
|
||||||
|
include_directories(${LIBKONQ_INCLUDE_DIR})
|
||||||
|
install( TARGETS extracthere DESTINATION ${PLUGIN_INSTALL_DIR} )
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/ark_dndextract.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
||||||
|
endif (LIBKONQ_FOUND)
|
||||||
|
|
226
ark/app/ark.appdata.xml
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<component type="desktop">
|
||||||
|
<id>ark.desktop</id>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>GPL-2.0+</project_license>
|
||||||
|
<name>Ark</name>
|
||||||
|
<name xml:lang="ar">آرك</name>
|
||||||
|
<name xml:lang="bg">Ark</name>
|
||||||
|
<name xml:lang="ca">Ark</name>
|
||||||
|
<name xml:lang="cs">Ark</name>
|
||||||
|
<name xml:lang="da">Ark</name>
|
||||||
|
<name xml:lang="de">Ark</name>
|
||||||
|
<name xml:lang="en-GB">Ark</name>
|
||||||
|
<name xml:lang="es">Ark</name>
|
||||||
|
<name xml:lang="et">Ark</name>
|
||||||
|
<name xml:lang="fi">Ark</name>
|
||||||
|
<name xml:lang="fr">Ark</name>
|
||||||
|
<name xml:lang="hu">Ark</name>
|
||||||
|
<name xml:lang="it">Ark</name>
|
||||||
|
<name xml:lang="ko">Ark</name>
|
||||||
|
<name xml:lang="lt">Ark</name>
|
||||||
|
<name xml:lang="nb">Ark</name>
|
||||||
|
<name xml:lang="nds">Ark</name>
|
||||||
|
<name xml:lang="nl">Ark</name>
|
||||||
|
<name xml:lang="pl">Ark</name>
|
||||||
|
<name xml:lang="pt">Ark</name>
|
||||||
|
<name xml:lang="pt-BR">Ark</name>
|
||||||
|
<name xml:lang="sk">Ark</name>
|
||||||
|
<name xml:lang="sl">Ark</name>
|
||||||
|
<name xml:lang="sr">Арк</name>
|
||||||
|
<name xml:lang="sr-Latn">Ark</name>
|
||||||
|
<name xml:lang="sr-ijekavian">Арк</name>
|
||||||
|
<name xml:lang="sr-ijekavianlatin">Ark</name>
|
||||||
|
<name xml:lang="sv">Ark</name>
|
||||||
|
<name xml:lang="tr">Ark</name>
|
||||||
|
<name xml:lang="uk">Ark</name>
|
||||||
|
<name xml:lang="x-test">xxArkxx</name>
|
||||||
|
<name xml:lang="zh-CN">Ark</name>
|
||||||
|
<name xml:lang="zh-TW">檔案壓縮_Ark</name>
|
||||||
|
<summary>Archiving Tool</summary>
|
||||||
|
<summary xml:lang="ar">أداة أرشفة</summary>
|
||||||
|
<summary xml:lang="bg">Работа с архиви</summary>
|
||||||
|
<summary xml:lang="ca">Eina d'arxivament</summary>
|
||||||
|
<summary xml:lang="cs">Archivační nástroj</summary>
|
||||||
|
<summary xml:lang="da">Arkiveringsværktøj</summary>
|
||||||
|
<summary xml:lang="de">Archivprogramm</summary>
|
||||||
|
<summary xml:lang="en-GB">Archiving Tool</summary>
|
||||||
|
<summary xml:lang="es">Herramienta de archivado</summary>
|
||||||
|
<summary xml:lang="et">Arhiivide haldamise rakendus</summary>
|
||||||
|
<summary xml:lang="fi">Pakkausohjelma</summary>
|
||||||
|
<summary xml:lang="fr">Outil d'archivage</summary>
|
||||||
|
<summary xml:lang="hu">Fájltömörítő</summary>
|
||||||
|
<summary xml:lang="it">Strumento di archiviazione</summary>
|
||||||
|
<summary xml:lang="ko">압축 도구</summary>
|
||||||
|
<summary xml:lang="lt">Archyvavimo įrankis</summary>
|
||||||
|
<summary xml:lang="nb">Arkiveringsverktøy</summary>
|
||||||
|
<summary xml:lang="nds">Archievwarktüüch</summary>
|
||||||
|
<summary xml:lang="nl">Archiefgereedschap</summary>
|
||||||
|
<summary xml:lang="pl">Narzędzie do archiwizowania</summary>
|
||||||
|
<summary xml:lang="pt">Ferramenta de Arquivo</summary>
|
||||||
|
<summary xml:lang="pt-BR">Ferramenta de arquivamento</summary>
|
||||||
|
<summary xml:lang="sk">Archivačný nástroj</summary>
|
||||||
|
<summary xml:lang="sl">Orodje za ravnanje z arhivi</summary>
|
||||||
|
<summary xml:lang="sr">Алатка за архивирање</summary>
|
||||||
|
<summary xml:lang="sr-Latn">Alatka za arhiviranje</summary>
|
||||||
|
<summary xml:lang="sr-ijekavian">Алатка за архивирање</summary>
|
||||||
|
<summary xml:lang="sr-ijekavianlatin">Alatka za arhiviranje</summary>
|
||||||
|
<summary xml:lang="sv">Arkiveringsverktyg</summary>
|
||||||
|
<summary xml:lang="tr">Arşivleme Aracı</summary>
|
||||||
|
<summary xml:lang="uk">Інструмент роботи з архівами</summary>
|
||||||
|
<summary xml:lang="x-test">xxArchiving Toolxx</summary>
|
||||||
|
<summary xml:lang="zh-CN">压缩工具</summary>
|
||||||
|
<summary xml:lang="zh-TW">壓縮工具</summary>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Ark is a graphical file compression/decompression utility with support for multiple formats,
|
||||||
|
including tar, gzip, bzip2, rar and zip, as well as CD-ROM images.
|
||||||
|
Ark can be used to browse, extract, create, and modify archives.
|
||||||
|
</p>
|
||||||
|
<p xml:lang="ar">آرك أداة رسوميّة لضغط وفكّ ضغط الملفات مع دعم لصيغ متعدّدة، منها tar، وgzip، وbzip2، وrar، وzip، إضافة إلى صور الأقراص الضوئيّة. يمكن استخدام آرك لتصفح، واستخراج، وإنشاء، وتعديل الأرشيفات.</p>
|
||||||
|
<p xml:lang="bg">Ark е графичен инструмент за архивиране/разархивиране, поддържащ множество формати, включително tar, gzip, bzip2, rar и zip, както и образи на CD-ROM. Ark може да се използва за разглеждане, извличане, създаване и променяне на архиви.</p>
|
||||||
|
<p xml:lang="ca">L'Ark és una utilitat gràfica de compressió/descompressió de fitxers que implementa múltiples formats, incloent tar, gzip, bzip2, rar i zip, i també imatges de CD-ROM. L'Ark es pot utilitzar per explorar, extreure, crear, i modificar arxiua.</p>
|
||||||
|
<p xml:lang="da">Ark er et grafisk værktøj til komprimering/dekomprimering, med understøttelse for flere formater, derunder tar, gzip, bzip2, rar og zip, såvel som cd-rom-imagefiler. Ark kan bruges til at gennemse, udtrække, oprette og redigere.</p>
|
||||||
|
<p xml:lang="de">Ark ist ein grafisches Dienstprogramm zum Packen/Entpacken von Dateien mit Unterstützung für mehrere Formate wie tar, gzip, bzip2, rar, zip und auch CD-Abbilder. Mit Ark können Sie können Sie Archive durchsehen, entpacken, erstellen und bearbeiten.</p>
|
||||||
|
<p xml:lang="en-GB">Ark is a graphical file compression/decompression utility with support for multiple formats, including tar, gzip, bzip2, rar and zip, as well as CD-ROM images. Ark can be used to browse, extract, create, and modify archives.</p>
|
||||||
|
<p xml:lang="es">Ark es una utilidad gráfica de compresión y descompresión de archivos que permite usar diversos formatos, como tar, gzip, bzip2, rar y zip, así como imágenes de CD-ROM. Ark se puede usar para explorar, extraer, crear y modificar archivos comprimidos.</p>
|
||||||
|
<p xml:lang="et">Ark on graafiline failide tihendamise ehk kokkupakkimise ja nende lahtipakkimise tööriist, mis toetab väga paljusid vorminguid, sealhulgas tar, gzip, bzip2, rar and zip, samuti CD-ROM-i tõmmised. Arki abil saab arhiivifaile sirvida, lahti pakkida, luua ja muuta.</p>
|
||||||
|
<p xml:lang="fi">Ark on graafinen tiedostojen pakkaus-/purkuohjelma, joka tukee useita tiedostomuotoja kuten tar, gzip, bzip2, rar and zip sekä myös CD-ROM-levykuvia. Arkilla voi selata, purkaa, luoda ja muuttaa paketteja.</p>
|
||||||
|
<p xml:lang="fr">Ark est un utilitaire graphique de compression/décompression de fichier prenant en charge de multiples formats, notamment tar, gzip, bzip2, rar et zip, ainsi que les images de CD-ROM. Ark peut être utilisé pour parcourir, extraire, créer et modifier des archives.</p>
|
||||||
|
<p xml:lang="hu">Az Ark egy grafikus fájltömörítő és kibontó segédprogram többféle formátum támogatásával, beleértve a tar, gzip, bzip2, rar és zip formátumokat, valamint a CD-ROM képfájlokat. Az Ark használható archívumok böngészéséhez, kibontásához, létrehozásához és módosításához.</p>
|
||||||
|
<p xml:lang="it">Ark è uno strumento grafico per la compressione/decompressione dei file che supporta molti formati, tra i quali tar, gzip, bzip2, rar e zip, così come le immagini dei CD-ROM. Ark può essere utilizzato per sfogliare, estrarre, creare e modificare archivi.</p>
|
||||||
|
<p xml:lang="ko">Ark는 그래픽 압축 파일 관리 도구이며, tar, gzip, bzip2, rar, zip, CD-ROM 이미지를 포함한 여러 파일 형식을 지원합니다. Ark를 사용하여 압축 파일을 열고, 생성하고, 수정하고, 압축을 풀 수 있습니다.</p>
|
||||||
|
<p xml:lang="nb">Ark er et verktøy med grafisk brukerflate, for komprimering/dekomprimering, med støtte for mange formater, deriblant tar, gzip, rar og zip, samt CD-ROM-bilder. Ark kan brukes til å bla i, pakke opp, opprette og endre arkiver.</p>
|
||||||
|
<p xml:lang="nds">Ark is en graafsch Komprimeer- un Dekomprimeerwarktüüch, dat en Barg Formaten ünnerstütten deit. Dor sünd tar, gzip, bzip2, rar un zip bi, un ok CD-ROM-Afbiller. Mit Ark kannst Du Archiven dörkieken, opstellen un ännern un Dateien dor ruttrecken.</p>
|
||||||
|
<p xml:lang="nl">Ark is een grafisch hulpmiddel om bestanden te comprimeren/uit te pakken met ondersteuning van meerdere formaten, inclusief tar, gzip, bzip2, rar en zip, evenals cd-ROM images. Ark kan gebruikt worden om door archieven te bladeren, deze uit te pakken, te maken en te wijzigen.</p>
|
||||||
|
<p xml:lang="pl">Ark jest graficznym narzędziem do pakowania/rozpakowywania plików wraz z obsługą różnych formatów, włączając w to tar, gzip, bzip2, rar oraz zip, a także obrazy CD-ROM. Programu Ark można używać do przeglądania, tworzenia, zmieniania oraz wydobywania z archiwów</p>
|
||||||
|
<p xml:lang="pt">O Ark é um utilitário de compressão/descompressão com o suporte para diversos formatos, incluindo o 'tar', 'gzip', 'bzip2', 'rar' e 'zip', assim como imagens de CD-ROM. O Ark pode ser usado para navegar, extrair, criar e modificar esses pacotes.</p>
|
||||||
|
<p xml:lang="pt-BR">O Ark é um utilitário de compressão/descompressão com o suporte a diversos formatos, incluindo tar, gzip, bzip2, rar e zip, assim como imagens de CD-ROM. O Ark pode ser usado para navegar, extrair, criar e modificar esses arquivos.</p>
|
||||||
|
<p xml:lang="sk">Ark je grafický nástroj na kompresiu a dekompresiu súborov s podporou pre mnoho formátov, vrátane tar, gzip bzip2, rar a zip, ako ako CD-ROM obrazy. Ark sa dá použiť na prehliadanie, rozbaľovanie vytváranie a úpravu archívov.</p>
|
||||||
|
<p xml:lang="sl">Ark je grafično orodje za stiskanje/razširjanje datotek, ki podpira večje število arhivov (med podprtimi so tudi tar, gzip, bzip2, rar in zip) kot tudi odtise CD-ROM. Ark lahko uporabite za brskanje po, razširjanje, ustvarjanje in spreminjanje arhivov.</p>
|
||||||
|
<p xml:lang="sr">Арк је графичка алатка за компресовање и декомпресовање фајлова. Подржава више формата, међу њима и: тар, гзип, бзип2, РАР, ЗИП, као и ЦД одразе. Може се користити за прегледање, распакивање, стварање и мењање архива.</p>
|
||||||
|
<p xml:lang="sr-Latn">Ark je grafička alatka za kompresovanje i dekompresovanje fajlova. Podržava više formata, među njima i: tar, gzip, bzip2, RAR, ZIP, kao i CD odraze. Može se koristiti za pregledanje, raspakivanje, stvaranje i menjanje arhiva.</p>
|
||||||
|
<p xml:lang="sr-ijekavian">Арк је графичка алатка за компресовање и декомпресовање фајлова. Подржава више формата, међу њима и: тар, гзип, бзип2, РАР, ЗИП, као и ЦД одразе. Може се користити за прегледање, распакивање, стварање и мењање архива.</p>
|
||||||
|
<p xml:lang="sr-ijekavianlatin">Ark je grafička alatka za kompresovanje i dekompresovanje fajlova. Podržava više formata, među njima i: tar, gzip, bzip2, RAR, ZIP, kao i CD odraze. Može se koristiti za pregledanje, raspakivanje, stvaranje i menjanje arhiva.</p>
|
||||||
|
<p xml:lang="sv">Ark är ett grafiskt verktyg för komprimering och uppackning av filer med stöd för flera format, inklusive tar, gzip, bzip2, rar och zip, samt cd-rom avbilder. Ark kan användas för att bläddra i, packa upp, skapa och ändra arkiv.</p>
|
||||||
|
<p xml:lang="tr">Ark; tar, gzip, bzip2, rar ve zip dosyalarının yanında CD-ROM kalıplarını da destekleyen grafiksel bir dosya sıkıştırma/açma yardımcısıdır. Ark arşivlerde gezinmek, arşiv ayıklamak, oluşturmak ve değiştirmek için kullanılabilir.</p>
|
||||||
|
<p xml:lang="uk">Ark — програма з графічним інтерфейсом, призначена для стискання даних у архіви та видобування даних з архівів. Передбачено підтримку декількох форматів архівів, зокрема tar, gzip, bzip2, rar та zip, а також образів дисків. Ark можна використовувати для перегляду, видобування, створення та внесення змін до архівів.</p>
|
||||||
|
<p xml:lang="x-test">xxArk is a graphical file compression/decompression utility with support for multiple formats, including tar, gzip, bzip2, rar and zip, as well as CD-ROM images. Ark can be used to browse, extract, create, and modify archives.xx</p>
|
||||||
|
<p xml:lang="zh-CN">Ark 是图形文件压缩和解压工具,支持多种格式,包括 tar, gzip, bzip2, rar and zip 以及 CD-ROM 镜像。Ark 可以用来浏览、解压、创建和修改压缩包。</p>
|
||||||
|
<p xml:lang="zh-TW">Ark 是一套圖形介面的檔案壓縮/解壓縮工具,支援多種格式,包括 tar, gzip, bzip2, rar 與 zip 等,還有 CD-ROM 映像檔等。Ark 有瀏覽、解開、建立與變更壓縮檔的功能。</p>
|
||||||
|
<p>Features:</p>
|
||||||
|
<p xml:lang="ar">المزايا</p>
|
||||||
|
<p xml:lang="bg">Функции:</p>
|
||||||
|
<p xml:lang="ca">Característiques:</p>
|
||||||
|
<p xml:lang="cs">Vlastnosti:</p>
|
||||||
|
<p xml:lang="da">Funktioner:</p>
|
||||||
|
<p xml:lang="de">Leistungsmerkmale:</p>
|
||||||
|
<p xml:lang="en-GB">Features:</p>
|
||||||
|
<p xml:lang="es">Funcionalidades:</p>
|
||||||
|
<p xml:lang="et">Omadused:</p>
|
||||||
|
<p xml:lang="fi">Ominaisuudet:</p>
|
||||||
|
<p xml:lang="fr">Fonctionnalités :</p>
|
||||||
|
<p xml:lang="hu">Szolgáltatások:</p>
|
||||||
|
<p xml:lang="it">Funzionalità:</p>
|
||||||
|
<p xml:lang="ko">기능:</p>
|
||||||
|
<p xml:lang="lt">Galimybės:</p>
|
||||||
|
<p xml:lang="nb">Egenskaper:</p>
|
||||||
|
<p xml:lang="nds">Markmalen:</p>
|
||||||
|
<p xml:lang="nl">Mogelijkheden:</p>
|
||||||
|
<p xml:lang="pl">Cechy:</p>
|
||||||
|
<p xml:lang="pt">Características:</p>
|
||||||
|
<p xml:lang="pt-BR">Funcionalidades:</p>
|
||||||
|
<p xml:lang="sk">Funkcie:</p>
|
||||||
|
<p xml:lang="sl">Zmožnosti:</p>
|
||||||
|
<p xml:lang="sr">Могућности:</p>
|
||||||
|
<p xml:lang="sr-Latn">Mogućnosti:</p>
|
||||||
|
<p xml:lang="sr-ijekavian">Могућности:</p>
|
||||||
|
<p xml:lang="sr-ijekavianlatin">Mogućnosti:</p>
|
||||||
|
<p xml:lang="sv">Funktioner:</p>
|
||||||
|
<p xml:lang="tr">Özellikler:</p>
|
||||||
|
<p xml:lang="uk">Можливості:</p>
|
||||||
|
<p xml:lang="x-test">xxFeatures:xx</p>
|
||||||
|
<p xml:lang="zh-CN">功能:</p>
|
||||||
|
<p xml:lang="zh-TW">特色:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Several formats supported: gzip, bzip2, zip, rar, 7z and more</li>
|
||||||
|
<li xml:lang="ar">دعم صيغ متعدّدة: مثل gzip، و bzip2، و zip، و rar، و 7z وغيرها</li>
|
||||||
|
<li xml:lang="bg">Поддържани са много формати: gzip, bzip2, zip, rar, 7z и други</li>
|
||||||
|
<li xml:lang="ca">Diversos formats implementats: gzip, bzip2, zip, rar, 7z i més</li>
|
||||||
|
<li xml:lang="cs">Je podporováno několik formátů: gzip, bzip2, zip, rar, 7z a další</li>
|
||||||
|
<li xml:lang="da">Flere understøttede formater: gzip, bzip2, zip, rar, 7z og flere</li>
|
||||||
|
<li xml:lang="de">Mehrere unterstützte Formate wie gzip, bzip2, zip, rar, 7z und mehr</li>
|
||||||
|
<li xml:lang="en-GB">Several formats supported: gzip, bzip2, zip, rar, 7z and more</li>
|
||||||
|
<li xml:lang="es">Permite el uso de diversos formatos: gzip, bzip2, zip, rar, 7z y más</li>
|
||||||
|
<li xml:lang="et">Paljude vormingute toetus: gzip, bzip2, zip, rar, 7z ja veel paljud.</li>
|
||||||
|
<li xml:lang="fi">Tukee useita tiedostomuotoja: gzip, bzip2, zip, rar, 7z ja monia muita</li>
|
||||||
|
<li xml:lang="fr">Plusieurs formats sont pris en charge : gzip, bzip2, zip, rar, 7z et d'autres</li>
|
||||||
|
<li xml:lang="hu">Számos formátum támogatott: gzip, bzip2, zip, rar, 7z és továbbiak</li>
|
||||||
|
<li xml:lang="it">Diversi formati supportati: gzip, bzip2, zip, rar, 7z e altri</li>
|
||||||
|
<li xml:lang="ko">다양한 형식 지원: gzip, bzip2, zip, rar, 7z 등</li>
|
||||||
|
<li xml:lang="nb">Mange formater støttet: gzip, bzip2, zip, rar, 7z og mer</li>
|
||||||
|
<li xml:lang="nds">En Reeg Fomaten warrt ünnerstütt: gzip, bzip2, zip, rar, 7z un anner</li>
|
||||||
|
<li xml:lang="nl">Ondersteuning voor een aantal formaten: gzip, bzip2, zip, rar, 7z en meer</li>
|
||||||
|
<li xml:lang="pl">Obsługa kilku formatów: gzip, bzip2, zip, rar, 7z oraz więcej</li>
|
||||||
|
<li xml:lang="pt">Diversos formatos suportados: gzip, bzip2, zip, rar, 7z, entre outros</li>
|
||||||
|
<li xml:lang="pt-BR">Diversos formatos suportados: gzip, bzip2, zip, rar, 7z, entre outros</li>
|
||||||
|
<li xml:lang="sk">Niektoré z podporovaných formátov: gzip, bzip2, zip, rar, 7z a viac</li>
|
||||||
|
<li xml:lang="sl">Številne podprte vrste arhivov: gzip, bzip2, zip, rar, 7z in več</li>
|
||||||
|
<li xml:lang="sr">Више подржаних формата: гзип, бзип2, ЗИП, РАР, 7зип, итд.</li>
|
||||||
|
<li xml:lang="sr-Latn">Više podržanih formata: gzip, bzip2, ZIP, RAR, 7zip, itd.</li>
|
||||||
|
<li xml:lang="sr-ijekavian">Више подржаних формата: гзип, бзип2, ЗИП, РАР, 7зип, итд.</li>
|
||||||
|
<li xml:lang="sr-ijekavianlatin">Više podržanih formata: gzip, bzip2, ZIP, RAR, 7zip, itd.</li>
|
||||||
|
<li xml:lang="sv">En mängd format stöds: gzip, bzip2, zip, rar, 7z med flera</li>
|
||||||
|
<li xml:lang="tr">Çeşitli biçimler destekleniyor: gzip, bzip2, zip, rar, 7z ve dahası</li>
|
||||||
|
<li xml:lang="uk">Підтримка декількох форматів: gzip, bzip2, zip, rar, 7z тощо</li>
|
||||||
|
<li xml:lang="x-test">xxSeveral formats supported: gzip, bzip2, zip, rar, 7z and morexx</li>
|
||||||
|
<li xml:lang="zh-CN">支持多种格式:gzip, bzip2, zip, rar, 7z 等</li>
|
||||||
|
<li xml:lang="zh-TW">支援格式:gzip, bzip2, zip, rar, 7z 等等</li>
|
||||||
|
<li>Preview file contents without extracting files</li>
|
||||||
|
<li xml:lang="ar">استعراض محتوى الملف دون استخراج الملفات منه</li>
|
||||||
|
<li xml:lang="bg">Преглеждане съдържанието на файла, без извличане на файловете</li>
|
||||||
|
<li xml:lang="ca">Vista prèvia del contingut de fitxers sense extreure'ls</li>
|
||||||
|
<li xml:lang="cs">Náhled obsahu souborů bez jejich rozbalení</li>
|
||||||
|
<li xml:lang="da">Forhåndsvis filindhold uden at udtrække filer</li>
|
||||||
|
<li xml:lang="de">Vorschau der Dateiinhalte ohne das Entpacken der Dateien</li>
|
||||||
|
<li xml:lang="en-GB">Preview file contents without extracting files</li>
|
||||||
|
<li xml:lang="es">Vista previa del contenido de archivos sin extraerlos</li>
|
||||||
|
<li xml:lang="et">Failide sisu näitamine ilma neid lahti pakkimata.</li>
|
||||||
|
<li xml:lang="fi">Tiedoston sisällön esikatselu purkamatta tiedostoa</li>
|
||||||
|
<li xml:lang="fr">Prévisualiser le contenu des fichiers sans les extraire</li>
|
||||||
|
<li xml:lang="hu">Fájltartalom előnézete a fájlok kibontása nélkül</li>
|
||||||
|
<li xml:lang="it">Anteprima dei file senza estrarre i file</li>
|
||||||
|
<li xml:lang="ko">압축 풀지 않고 파일 내용 미리 보기</li>
|
||||||
|
<li xml:lang="nb">Forhåndsvis innhold uten å pakke ut filer</li>
|
||||||
|
<li xml:lang="nds">Datein ahn Ruttrecken vörweg ankieken</li>
|
||||||
|
<li xml:lang="nl">Voorvertoning van inhoud van bestand zonder bestanden uit te pakken</li>
|
||||||
|
<li xml:lang="pl">Podejrzyj zawartość pliku bez jego wypakowywania</li>
|
||||||
|
<li xml:lang="pt">Antevisão do conteúdo dos ficheiros sem os extrair</li>
|
||||||
|
<li xml:lang="pt-BR">Visualização do conteúdo dos arquivos sem precisar extraí-los</li>
|
||||||
|
<li xml:lang="sk">Náhľad obsahu súboru bez rozbalenia súborov</li>
|
||||||
|
<li xml:lang="sl">Predoglejte vsebino datoteke brez razširjanja</li>
|
||||||
|
<li xml:lang="sr">Преглед садржаја фајлова без распакивања.</li>
|
||||||
|
<li xml:lang="sr-Latn">Pregled sadržaja fajlova bez raspakivanja.</li>
|
||||||
|
<li xml:lang="sr-ijekavian">Преглед садржаја фајлова без распакивања.</li>
|
||||||
|
<li xml:lang="sr-ijekavianlatin">Pregled sadržaja fajlova bez raspakivanja.</li>
|
||||||
|
<li xml:lang="sv">Förhandsgranska filinnehåll utan att packa upp filer</li>
|
||||||
|
<li xml:lang="tr">Dosyaları ayıklamadan dosya içeriği önizlemesi</li>
|
||||||
|
<li xml:lang="uk">Попередній перегляд вмісту файлів без розпаковування</li>
|
||||||
|
<li xml:lang="x-test">xxPreview file contents without extracting filesxx</li>
|
||||||
|
<li xml:lang="zh-CN">不解压就预览文件</li>
|
||||||
|
<li xml:lang="zh-TW">不需解壓縮即可預覽檔案內容</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<image width="834" height="651">http://kde.org/images/screenshots/ark.png</image>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
<url type="homepage">http://kde.org/applications/utilities/ark/</url>
|
||||||
|
<url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?format=guided&product=ark</url>
|
||||||
|
<url type="help">http://docs.kde.org/stable/en/kdeutils/ark/index.html</url>
|
||||||
|
<project_group>KDE</project_group>
|
||||||
|
<provides>
|
||||||
|
<binary>ark</binary>
|
||||||
|
</provides>
|
||||||
|
</component>
|
158
ark/app/ark.desktop.cmake
Executable file
|
@ -0,0 +1,158 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
MimeType=@SUPPORTED_ARK_MIMETYPES@
|
||||||
|
GenericName=Archiving Tool
|
||||||
|
GenericName[af]=Argiveer Program
|
||||||
|
GenericName[ar]=أداة أرشفة
|
||||||
|
GenericName[ast]=Ferramienta p'archivar
|
||||||
|
GenericName[bg]=Работа с архиви
|
||||||
|
GenericName[br]=Ostilh merañ an Dielloù
|
||||||
|
GenericName[bs]=Alatka za arhiviranje
|
||||||
|
GenericName[ca]=Eina d'arxivament
|
||||||
|
GenericName[ca@valencia]=Eina d'arxivament
|
||||||
|
GenericName[cs]=Archivační nástroj
|
||||||
|
GenericName[cy]=Erfyn Archifo
|
||||||
|
GenericName[da]=Arkiveringsværktøj
|
||||||
|
GenericName[de]=Archivprogramm
|
||||||
|
GenericName[el]=Εργαλείο αρχειοθέτησης
|
||||||
|
GenericName[en_GB]=Archiving Tool
|
||||||
|
GenericName[eo]=Arkivilo
|
||||||
|
GenericName[es]=Archivador
|
||||||
|
GenericName[et]=Arhiivide haldamise rakendus
|
||||||
|
GenericName[eu]=Artxibatzeko tresna
|
||||||
|
GenericName[fa]=ابزار بایگانی
|
||||||
|
GenericName[fi]=Pakkausohjelma
|
||||||
|
GenericName[fr]=Outil d'archivage
|
||||||
|
GenericName[ga]=Uirlis Chartlannaithe
|
||||||
|
GenericName[gl]=Utilidade de arquivo
|
||||||
|
GenericName[he]=כלי לניהול ארכיונים
|
||||||
|
GenericName[hne]=अभिलेखन औजार
|
||||||
|
GenericName[hr]=Alat za arhiviranje
|
||||||
|
GenericName[hu]=Fájltömörítő
|
||||||
|
GenericName[ia]=Instrumento per archivar
|
||||||
|
GenericName[id]=Perkakas Pengarsip
|
||||||
|
GenericName[is]=Vinna með safnskrár
|
||||||
|
GenericName[it]=Strumento di archiviazione
|
||||||
|
GenericName[ja]=アーカイブツール
|
||||||
|
GenericName[kk]=Архивтеу құралы
|
||||||
|
GenericName[km]=ឧបករណ៍ប័ណ្ណសារ
|
||||||
|
GenericName[ko]=압축 도구
|
||||||
|
GenericName[lt]=Archyvavimo priemonė
|
||||||
|
GenericName[lv]=Arhivēšanas rīks
|
||||||
|
GenericName[mk]=Алатка за архивирање
|
||||||
|
GenericName[mr]=संग्रह साधन
|
||||||
|
GenericName[ms]=Alatan Pengarkiban
|
||||||
|
GenericName[nb]=Arkiveringsverktøy
|
||||||
|
GenericName[nds]=Archievwarktüüch
|
||||||
|
GenericName[ne]=सङ्ग्रहण उपकरण
|
||||||
|
GenericName[nl]=Archiefgereedschap
|
||||||
|
GenericName[nn]=Arkiveringsverktøy
|
||||||
|
GenericName[pa]=ਅਕਾਇਵਿੰਗ ਟੂਲ
|
||||||
|
GenericName[pl]=Narzędzie do archiwizacji
|
||||||
|
GenericName[pt]=Ferramenta de Armazenamento
|
||||||
|
GenericName[pt_BR]=Ferramenta de Arquivamento
|
||||||
|
GenericName[ro]=Utilitar de arhivare
|
||||||
|
GenericName[ru]=Архиватор
|
||||||
|
GenericName[sk]=Archivačný nástroj
|
||||||
|
GenericName[sl]=Orodje za ravnanje z arhivi
|
||||||
|
GenericName[sq]=Mjeti Arkivues
|
||||||
|
GenericName[sr]=Алатка за архивирање
|
||||||
|
GenericName[sr@ijekavian]=Алатка за архивирање
|
||||||
|
GenericName[sr@ijekavianlatin]=Alatka za arhiviranje
|
||||||
|
GenericName[sr@latin]=Alatka za arhiviranje
|
||||||
|
GenericName[sv]=Arkiveringsverktyg
|
||||||
|
GenericName[ta]=காப்பக கருவி
|
||||||
|
GenericName[tg]=Асбобҳои Бойгонӣ
|
||||||
|
GenericName[th]=เครื่องมือจัดการแฟ้มจัดเก็บ
|
||||||
|
GenericName[tr]=Arşivleme Aracı
|
||||||
|
GenericName[ug]=ئارخىپ قورالى
|
||||||
|
GenericName[uk]=Засіб роботи з архівами
|
||||||
|
GenericName[uz]=Arxivlash vositasi
|
||||||
|
GenericName[uz@cyrillic]=Архивлаш воситаси
|
||||||
|
GenericName[vi]=Công Cụ Nén
|
||||||
|
GenericName[wa]=Usteye d' årtchivaedje
|
||||||
|
GenericName[xh]=Isixhobo Sokuphatha i Archive
|
||||||
|
GenericName[x-test]=xxArchiving Toolxx
|
||||||
|
GenericName[zh_CN]=压缩归档工具
|
||||||
|
GenericName[zh_TW]=壓縮工具
|
||||||
|
Name=Ark
|
||||||
|
Name[af]=Ark
|
||||||
|
Name[ar]=أرك
|
||||||
|
Name[ast]=Ark
|
||||||
|
Name[bg]=Ark
|
||||||
|
Name[br]=Ark
|
||||||
|
Name[bs]=Ark
|
||||||
|
Name[ca]=Ark
|
||||||
|
Name[ca@valencia]=Ark
|
||||||
|
Name[cs]=Ark
|
||||||
|
Name[cy]=Ark
|
||||||
|
Name[da]=Ark
|
||||||
|
Name[de]=Ark
|
||||||
|
Name[el]=Ark
|
||||||
|
Name[en_GB]=Ark
|
||||||
|
Name[eo]=Arko
|
||||||
|
Name[es]=Ark
|
||||||
|
Name[et]=Ark
|
||||||
|
Name[eu]=Ark
|
||||||
|
Name[fi]=Ark
|
||||||
|
Name[fr]=Ark
|
||||||
|
Name[ga]=Ark
|
||||||
|
Name[gl]=Ark
|
||||||
|
Name[he]=Ark
|
||||||
|
Name[hne]=आर्क
|
||||||
|
Name[hr]=Ark
|
||||||
|
Name[hu]=Ark
|
||||||
|
Name[ia]=Ark
|
||||||
|
Name[id]=Ark
|
||||||
|
Name[is]=Ark
|
||||||
|
Name[it]=Ark
|
||||||
|
Name[ja]=Ark
|
||||||
|
Name[kk]=Ark
|
||||||
|
Name[km]=Ark
|
||||||
|
Name[ko]=Ark
|
||||||
|
Name[lt]=Ark
|
||||||
|
Name[lv]=Ark
|
||||||
|
Name[mk]=Ark
|
||||||
|
Name[mr]=आर्क
|
||||||
|
Name[ms]=Ark
|
||||||
|
Name[nb]=Ark
|
||||||
|
Name[nds]=Ark
|
||||||
|
Name[ne]=आर्क
|
||||||
|
Name[nl]=Ark
|
||||||
|
Name[nn]=Ark
|
||||||
|
Name[pa]=ਆਕ
|
||||||
|
Name[pl]=Ark
|
||||||
|
Name[pt]=Ark
|
||||||
|
Name[pt_BR]=Ark
|
||||||
|
Name[ro]=Ark
|
||||||
|
Name[ru]=Ark
|
||||||
|
Name[sk]=Ark
|
||||||
|
Name[sl]=Ark
|
||||||
|
Name[sq]=Ark
|
||||||
|
Name[sr]=Арк
|
||||||
|
Name[sr@ijekavian]=Арк
|
||||||
|
Name[sr@ijekavianlatin]=Ark
|
||||||
|
Name[sr@latin]=Ark
|
||||||
|
Name[sv]=Ark
|
||||||
|
Name[ta]=ஆர்க்
|
||||||
|
Name[tg]=Ark
|
||||||
|
Name[th]=อาร์ก
|
||||||
|
Name[tr]=Ark
|
||||||
|
Name[ug]=Ark
|
||||||
|
Name[uk]=Ark
|
||||||
|
Name[uz]=Ark
|
||||||
|
Name[uz@cyrillic]=Ark
|
||||||
|
Name[vi]=Ark
|
||||||
|
Name[wa]=Ark
|
||||||
|
Name[xh]=Ark
|
||||||
|
Name[x-test]=xxArkxx
|
||||||
|
Name[zh_CN]=Ark
|
||||||
|
Name[zh_TW]=Ark
|
||||||
|
Exec=ark -caption %c %U
|
||||||
|
Icon=ark
|
||||||
|
X-DocPath=ark/index.html
|
||||||
|
Type=Application
|
||||||
|
Terminal=false
|
||||||
|
X-DBUS-StartupType=Unique
|
||||||
|
X-KDE-HasTempFileOption=true
|
||||||
|
Categories=Qt;KDE;Utility;Archiving;Compression;X-KDE-Utilities-File;
|
||||||
|
InitialPreference=3
|
351
ark/app/ark_addtoservicemenu.desktop
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Service
|
||||||
|
ServiceTypes=KonqPopupMenu/Plugin
|
||||||
|
MimeType=all/all;
|
||||||
|
Actions=compressHere;compressAsZip;compressAsRar;compressAsTar;compressTo;
|
||||||
|
X-KDE-Submenu=Compress
|
||||||
|
X-KDE-Submenu[ar]=اضغط
|
||||||
|
X-KDE-Submenu[ast]=Comprimir
|
||||||
|
X-KDE-Submenu[bg]=Компресиране
|
||||||
|
X-KDE-Submenu[bs]=Kompresuj
|
||||||
|
X-KDE-Submenu[ca]=Compressió
|
||||||
|
X-KDE-Submenu[ca@valencia]=Compressió
|
||||||
|
X-KDE-Submenu[cs]=Zkomprimovat
|
||||||
|
X-KDE-Submenu[da]=Komprimér
|
||||||
|
X-KDE-Submenu[de]=Komprimieren
|
||||||
|
X-KDE-Submenu[el]=Συμπίεση
|
||||||
|
X-KDE-Submenu[en_GB]=Compress
|
||||||
|
X-KDE-Submenu[es]=Comprimir
|
||||||
|
X-KDE-Submenu[et]=Paki
|
||||||
|
X-KDE-Submenu[eu]=Konprimatu
|
||||||
|
X-KDE-Submenu[fi]=Pakkaa
|
||||||
|
X-KDE-Submenu[fr]=Compresser
|
||||||
|
X-KDE-Submenu[ga]=Comhbhrúigh
|
||||||
|
X-KDE-Submenu[gl]=Comprimir
|
||||||
|
X-KDE-Submenu[hne]=संपीडित करव
|
||||||
|
X-KDE-Submenu[hr]=Zapakiraj
|
||||||
|
X-KDE-Submenu[hu]=Tömörítés
|
||||||
|
X-KDE-Submenu[ia]=Comprime
|
||||||
|
X-KDE-Submenu[id]=Kompres
|
||||||
|
X-KDE-Submenu[it]=Comprimi
|
||||||
|
X-KDE-Submenu[ja]=圧縮
|
||||||
|
X-KDE-Submenu[kk]=Сығу
|
||||||
|
X-KDE-Submenu[km]=បង្ហាប់
|
||||||
|
X-KDE-Submenu[ko]=압축하기
|
||||||
|
X-KDE-Submenu[lt]=Suspausti
|
||||||
|
X-KDE-Submenu[lv]=Saspiest
|
||||||
|
X-KDE-Submenu[mr]=संक्षिप्त करा
|
||||||
|
X-KDE-Submenu[nb]=Komprimer
|
||||||
|
X-KDE-Submenu[nds]=Komprimeren
|
||||||
|
X-KDE-Submenu[nl]=Comprimeren
|
||||||
|
X-KDE-Submenu[nn]=Komprimer
|
||||||
|
X-KDE-Submenu[pa]=ਕੰਪਰੈੱਸ
|
||||||
|
X-KDE-Submenu[pl]=Kompresuj
|
||||||
|
X-KDE-Submenu[pt]=Comprimir
|
||||||
|
X-KDE-Submenu[pt_BR]=Compactar
|
||||||
|
X-KDE-Submenu[ro]=Comprimă
|
||||||
|
X-KDE-Submenu[ru]=Упаковать
|
||||||
|
X-KDE-Submenu[sk]=Komprimovať
|
||||||
|
X-KDE-Submenu[sl]=Stisni
|
||||||
|
X-KDE-Submenu[sq]=Ngjish
|
||||||
|
X-KDE-Submenu[sr]=Компресуј
|
||||||
|
X-KDE-Submenu[sr@ijekavian]=Компресуј
|
||||||
|
X-KDE-Submenu[sr@ijekavianlatin]=Kompresuj
|
||||||
|
X-KDE-Submenu[sr@latin]=Kompresuj
|
||||||
|
X-KDE-Submenu[sv]=Komprimera
|
||||||
|
X-KDE-Submenu[th]=บีบข้อมูล
|
||||||
|
X-KDE-Submenu[tr]=Sıkıştır
|
||||||
|
X-KDE-Submenu[ug]=پرېس
|
||||||
|
X-KDE-Submenu[uk]=Стиснути
|
||||||
|
X-KDE-Submenu[wa]=Rastrinde
|
||||||
|
X-KDE-Submenu[x-test]=xxCompressxx
|
||||||
|
X-KDE-Submenu[zh_CN]=压缩
|
||||||
|
X-KDE-Submenu[zh_TW]=壓縮
|
||||||
|
X-KDE-StartupNotify=false
|
||||||
|
X-KDE-Priority=TopLevel
|
||||||
|
|
||||||
|
[Desktop Action compressHere]
|
||||||
|
Name=Here
|
||||||
|
Name[ar]=هنا
|
||||||
|
Name[ast]=Equí
|
||||||
|
Name[bg]=Тук
|
||||||
|
Name[bs]=ovdje
|
||||||
|
Name[ca]=Aquí
|
||||||
|
Name[ca@valencia]=Ací
|
||||||
|
Name[cs]=Sem
|
||||||
|
Name[da]=Her
|
||||||
|
Name[de]=Hier
|
||||||
|
Name[el]=Εδώ
|
||||||
|
Name[en_GB]=Here
|
||||||
|
Name[es]=Aquí
|
||||||
|
Name[et]=Siia
|
||||||
|
Name[eu]=Hemen
|
||||||
|
Name[fi]=Tähän
|
||||||
|
Name[fr]=Ici
|
||||||
|
Name[ga]=Anseo
|
||||||
|
Name[gl]=Aquí
|
||||||
|
Name[hr]=Ovdje
|
||||||
|
Name[hu]=Ide
|
||||||
|
Name[ia]=Hic
|
||||||
|
Name[id]=Di Sini
|
||||||
|
Name[is]=Hér
|
||||||
|
Name[it]=Qui
|
||||||
|
Name[ja]=ここに
|
||||||
|
Name[kk]=Осында
|
||||||
|
Name[km]=នៅទីនេះ
|
||||||
|
Name[ko]=여기
|
||||||
|
Name[lt]=Čia
|
||||||
|
Name[lv]=Šeit
|
||||||
|
Name[mr]=येथे
|
||||||
|
Name[nb]=Her
|
||||||
|
Name[nds]=Hier
|
||||||
|
Name[nl]=Hier
|
||||||
|
Name[nn]=Her
|
||||||
|
Name[pa]=ਇੱਥੇ
|
||||||
|
Name[pl]=Tutaj
|
||||||
|
Name[pt]=Aqui
|
||||||
|
Name[pt_BR]=Aqui
|
||||||
|
Name[ro]=Aici
|
||||||
|
Name[ru]=В эту папку
|
||||||
|
Name[sk]=Sem
|
||||||
|
Name[sl]=Sem
|
||||||
|
Name[sq]=Këtu
|
||||||
|
Name[sr]=овде
|
||||||
|
Name[sr@ijekavian]=овдје
|
||||||
|
Name[sr@ijekavianlatin]=ovdje
|
||||||
|
Name[sr@latin]=ovde
|
||||||
|
Name[sv]=Här
|
||||||
|
Name[th]=ไว้ที่นี่
|
||||||
|
Name[tr]=Buraya
|
||||||
|
Name[ug]=بۇ جاي
|
||||||
|
Name[uk]=Сюди
|
||||||
|
Name[wa]=Cial
|
||||||
|
Name[x-test]=xxHerexx
|
||||||
|
Name[zh_CN]=这里
|
||||||
|
Name[zh_TW]=這裡
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --changetofirstpath --add --autofilename tar.gz %F
|
||||||
|
|
||||||
|
[Desktop Action compressAsZip]
|
||||||
|
Name=As ZIP Archive
|
||||||
|
Name[ar]=ك أرشيف ZIP
|
||||||
|
Name[ast]=Como archivu comprimíu ZIP
|
||||||
|
Name[bg]=Като ZIP архив
|
||||||
|
Name[bs]=kao ZIP arhivu
|
||||||
|
Name[ca]=Com a arxiu ZIP
|
||||||
|
Name[ca@valencia]=Com a arxiu ZIP
|
||||||
|
Name[cs]=Jako archiv ZIP
|
||||||
|
Name[da]=Som ZIP-arkiv
|
||||||
|
Name[de]=Als ZIP-Archiv
|
||||||
|
Name[el]=Ως αρχειοθήκη ZIP
|
||||||
|
Name[en_GB]=As ZIP Archive
|
||||||
|
Name[es]=Como archivo comprimido ZIP
|
||||||
|
Name[et]=ZIP-arhiivina
|
||||||
|
Name[eu]=ZIP artxibo gisa
|
||||||
|
Name[fi]=ZIP-paketiksi
|
||||||
|
Name[fr]=Comme une archive « ZIP »
|
||||||
|
Name[ga]=Mar Chartlann ZIP
|
||||||
|
Name[gl]=Como arquivo ZIP
|
||||||
|
Name[hr]=Kao ZIP-arhiva
|
||||||
|
Name[hu]=ZIP archívumként
|
||||||
|
Name[ia]=Como archivo ZIP
|
||||||
|
Name[id]=Sebagai Arsip ZIP
|
||||||
|
Name[it]=Come archivio ZIP
|
||||||
|
Name[ja]=ZIP アーカイブに
|
||||||
|
Name[kk]=ZIP архиві қылып
|
||||||
|
Name[km]=ជាប័ណ្ណសារ ZIP
|
||||||
|
Name[ko]=ZIP 파일로
|
||||||
|
Name[lt]=ZIP archyvas
|
||||||
|
Name[lv]=Kā ZIP arhīvu
|
||||||
|
Name[mr]=ZIP संग्रह प्रमाणे
|
||||||
|
Name[nb]=Som ZIP-arkiv
|
||||||
|
Name[nds]=As Zip-Archiev
|
||||||
|
Name[nl]=Als ZIP-archief
|
||||||
|
Name[nn]=Som ZIP-arkiv
|
||||||
|
Name[pa]=ਜ਼ਿਪ ਅਕਾਇਵ ਵਾਂਗ
|
||||||
|
Name[pl]=Jako archiwum ZIP
|
||||||
|
Name[pt]=Como Pacote ZIP
|
||||||
|
Name[pt_BR]=Como arquivo ZIP
|
||||||
|
Name[ro]=Ca arhivă ZIP
|
||||||
|
Name[ru]=Как архив ZIP
|
||||||
|
Name[sk]=Do ZIP archívu
|
||||||
|
Name[sl]=Kot arhiv ZIP
|
||||||
|
Name[sq]=Si Arkiv ZIP
|
||||||
|
Name[sr]=као ЗИП архиву
|
||||||
|
Name[sr@ijekavian]=као ЗИП архиву
|
||||||
|
Name[sr@ijekavianlatin]=kao ZIP arhivu
|
||||||
|
Name[sr@latin]=kao ZIP arhivu
|
||||||
|
Name[sv]=Som ZIP-arkiv
|
||||||
|
Name[th]=เป็นแฟ้มจัดเก็บบีบอัดแบบ ZIP
|
||||||
|
Name[tr]=ZIP Arşivi Olarak
|
||||||
|
Name[ug]=ZIP ئارخىپى
|
||||||
|
Name[uk]=Як архів ZIP
|
||||||
|
Name[wa]=Come årtchive ZIP
|
||||||
|
Name[x-test]=xxAs ZIP Archivexx
|
||||||
|
Name[zh_CN]=为 ZIP 归档
|
||||||
|
Name[zh_TW]=成 ZIP 壓縮檔
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --changetofirstpath --add --autofilename zip %F
|
||||||
|
|
||||||
|
[Desktop Action compressAsRar]
|
||||||
|
Name=As RAR Archive
|
||||||
|
Name[ar]=كأرشيف RAR
|
||||||
|
Name[ast]=Como archivu comprimíu RAR
|
||||||
|
Name[bg]=Като RAR архив
|
||||||
|
Name[bs]=kao RAR arhivu
|
||||||
|
Name[ca]=Com a arxiu RAR
|
||||||
|
Name[ca@valencia]=Com a arxiu RAR
|
||||||
|
Name[cs]=Jako archiv RAR
|
||||||
|
Name[da]=Som RAR-arkiv
|
||||||
|
Name[de]=Als RAR-Archiv
|
||||||
|
Name[el]=Ως αρχειοθήκη RAR
|
||||||
|
Name[en_GB]=As RAR Archive
|
||||||
|
Name[es]=Como archivo comprimido RAR
|
||||||
|
Name[et]=RAR-arhiivina
|
||||||
|
Name[eu]=RAR artxibo gisa
|
||||||
|
Name[fi]=RAR-paketiksi
|
||||||
|
Name[fr]=Comme une archive « RAR »
|
||||||
|
Name[ga]=Mar Chartlann RAR
|
||||||
|
Name[gl]=Como arquivo RAR
|
||||||
|
Name[hr]=Kao RAR-arhiva
|
||||||
|
Name[hu]=RAR archívumként
|
||||||
|
Name[ia]=Como archivo RAR
|
||||||
|
Name[id]=Sebagai Arsip RAR
|
||||||
|
Name[it]=Come archivio RAR
|
||||||
|
Name[ja]=RAR アーカイブに
|
||||||
|
Name[kk]=RAR архиві қылып
|
||||||
|
Name[km]=ជាប័ណ្ណសារ RAR
|
||||||
|
Name[ko]=RAR 파일로
|
||||||
|
Name[lt]=RAR archyvas
|
||||||
|
Name[lv]=Kā RAR arhīvu
|
||||||
|
Name[mr]=RAR संग्रह प्रमाणे
|
||||||
|
Name[nb]=Som RAR-arkiv
|
||||||
|
Name[nds]=As RAR-Archiev
|
||||||
|
Name[nl]=Als RAR-archief
|
||||||
|
Name[nn]=Som RAR-arkiv
|
||||||
|
Name[pa]=RAR ਅਕਾਇਵ ਵਾਂਗ
|
||||||
|
Name[pl]=Jako archiwum RAR
|
||||||
|
Name[pt]=Como Pacote RAR
|
||||||
|
Name[pt_BR]=Como arquivo RAR
|
||||||
|
Name[ro]=Ca arhivă RAR
|
||||||
|
Name[ru]=Как архив RAR
|
||||||
|
Name[sk]=Do RAR archívu
|
||||||
|
Name[sl]=Kot arhiv RAR
|
||||||
|
Name[sq]=Si Arkiv RAR
|
||||||
|
Name[sr]=као РАР архиву
|
||||||
|
Name[sr@ijekavian]=као РАР архиву
|
||||||
|
Name[sr@ijekavianlatin]=kao RAR arhivu
|
||||||
|
Name[sr@latin]=kao RAR arhivu
|
||||||
|
Name[sv]=Som RAR-arkiv
|
||||||
|
Name[th]=เป็นแฟ้มจัดเก็บบีบอัดแบบ RAR
|
||||||
|
Name[tr]=RAR Arşivi Olarak
|
||||||
|
Name[ug]=RAR ئارخىپى
|
||||||
|
Name[uk]=Як архів RAR
|
||||||
|
Name[wa]=Come årtchive RAR
|
||||||
|
Name[x-test]=xxAs RAR Archivexx
|
||||||
|
Name[zh_CN]=为 RAR 归档
|
||||||
|
Name[zh_TW]=成 RAR 壓縮檔
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --changetofirstpath --add --autofilename rar %F
|
||||||
|
|
||||||
|
[Desktop Action compressAsTar]
|
||||||
|
Name=As TAR.GZ Archive
|
||||||
|
Name[ar]=كأرشيف TAR.GZ
|
||||||
|
Name[bg]=Като TAR.GZ архив
|
||||||
|
Name[ca]=Com a arxiu TAR.GZ
|
||||||
|
Name[cs]=Jako archiv TAR.GZ
|
||||||
|
Name[da]=Som TAR.GZ-arkiv
|
||||||
|
Name[de]=Als TAR.GZ-Archiv
|
||||||
|
Name[en_GB]=As TAR.GZ Archive
|
||||||
|
Name[es]=Como archivo comprimido TAR.GZ
|
||||||
|
Name[et]=TAR.GZ-arhiivina
|
||||||
|
Name[fi]=TAR.GZ-paketiksi
|
||||||
|
Name[fr]=Comme une archive « TAR.GZ »
|
||||||
|
Name[hu]=TAR.GZ archívumként
|
||||||
|
Name[ia]=Como archivo TAR.GZ
|
||||||
|
Name[it]=Come archivio TAR.GZ
|
||||||
|
Name[ja]=TAR.GZ アーカイブに
|
||||||
|
Name[ko]=TAR.GZ 파일로
|
||||||
|
Name[nb]=Som TAR.GZ-arkiv
|
||||||
|
Name[nds]=As TAR.GZ-Archiev
|
||||||
|
Name[nl]=Als TAR.GZ-archief
|
||||||
|
Name[pa]=TAR.GZ ਅਕਾਇਵ ਵਜੋਂ
|
||||||
|
Name[pl]=Jako archiwum TAR.GZ
|
||||||
|
Name[pt]=Como Pacote TAR.GZ
|
||||||
|
Name[pt_BR]=Como arquivo TAR.GZ
|
||||||
|
Name[ru]=Как архив TAR.GZ
|
||||||
|
Name[sk]=Ako TAR.GZ archív
|
||||||
|
Name[sl]=Kot arhiv TAR.GZ
|
||||||
|
Name[sr]=као таргз архиву
|
||||||
|
Name[sr@ijekavian]=као таргз архиву
|
||||||
|
Name[sr@ijekavianlatin]=kao targz arhivu
|
||||||
|
Name[sr@latin]=kao targz arhivu
|
||||||
|
Name[sv]=Som TAR.GZ-arkiv
|
||||||
|
Name[tr]=TAR.GZ Arşivi Olarak
|
||||||
|
Name[uk]=Як архів TAR.GZ
|
||||||
|
Name[x-test]=xxAs TAR.GZ Archivexx
|
||||||
|
Name[zh_CN]=为 TAR.GZ 归档
|
||||||
|
Name[zh_TW]=成 TAR.GZ 壓縮檔
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --changetofirstpath --add --autofilename tar.gz %F
|
||||||
|
|
||||||
|
[Desktop Action compressTo]
|
||||||
|
Name=Compress To...
|
||||||
|
Name[ar]=اضغط إلى...
|
||||||
|
Name[ast]=Comprimir en...
|
||||||
|
Name[bg]=Компресиране в...
|
||||||
|
Name[bs]=Kompresuj u...
|
||||||
|
Name[ca]=Comprimeix a...
|
||||||
|
Name[ca@valencia]=Comprimeix a...
|
||||||
|
Name[cs]=Zkomprimovat do...
|
||||||
|
Name[da]=Komprimér til...
|
||||||
|
Name[de]=Komprimieren nach ...
|
||||||
|
Name[el]=Συμπίεση σε...
|
||||||
|
Name[en_GB]=Compress To...
|
||||||
|
Name[es]=Comprimir en...
|
||||||
|
Name[et]=Paki asukohta...
|
||||||
|
Name[eu]=Konprimatu hona...
|
||||||
|
Name[fi]=Pakkaa…
|
||||||
|
Name[fr]=Compresser vers...
|
||||||
|
Name[ga]=Comhbhrúigh Go...
|
||||||
|
Name[gl]=Comprimir en...
|
||||||
|
Name[hr]=Zapakiraj u …
|
||||||
|
Name[hu]=Tömörítés ide…
|
||||||
|
Name[ia]=Comprime a...
|
||||||
|
Name[id]=Kompres ke...
|
||||||
|
Name[it]=Comprimi in...
|
||||||
|
Name[ja]=圧縮...
|
||||||
|
Name[kk]=Мыныған архивтеу,,,
|
||||||
|
Name[km]=បង្ហាប់ទៅជា...
|
||||||
|
Name[ko]=다음으로 압축하기...
|
||||||
|
Name[lt]=Suspausti į...
|
||||||
|
Name[lv]=Saspiest uz...
|
||||||
|
Name[mr]=यावर संक्षिप्त करा...
|
||||||
|
Name[nb]=Komprimer til …
|
||||||
|
Name[nds]=Komprimeren as...
|
||||||
|
Name[nl]=Comprimeren naar...
|
||||||
|
Name[nn]=Komprimer til …
|
||||||
|
Name[pa]=...ਵਜੋਂ ਕੰਪਰੈੱਸ ਕਰੋ
|
||||||
|
Name[pl]=Kompresuj do...
|
||||||
|
Name[pt]=Comprimir Para...
|
||||||
|
Name[pt_BR]=Compactar para...
|
||||||
|
Name[ro]=Comprimă în...
|
||||||
|
Name[ru]=Упаковать в архив...
|
||||||
|
Name[sk]=Komprimovať do...
|
||||||
|
Name[sl]=Stisni v ...
|
||||||
|
Name[sq]=Ngjishe Tek...
|
||||||
|
Name[sr]=другде...
|
||||||
|
Name[sr@ijekavian]=другдје...
|
||||||
|
Name[sr@ijekavianlatin]=drugdje...
|
||||||
|
Name[sr@latin]=drugde...
|
||||||
|
Name[sv]=Komprimera till...
|
||||||
|
Name[th]=บีบข้อมูลไปยัง...
|
||||||
|
Name[tr]=Farklı Sıkıştır...
|
||||||
|
Name[ug]=… غا پرېسلاش
|
||||||
|
Name[uk]=Стиснути до...
|
||||||
|
Name[wa]=Rastrinde eyet rlomer...
|
||||||
|
Name[x-test]=xxCompress To...xx
|
||||||
|
Name[zh_CN]=压缩到...
|
||||||
|
Name[zh_TW]=壓縮為...
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --add --changetofirstpath --dialog %F
|
61
ark/app/ark_dndextract.desktop.cmake
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Service
|
||||||
|
X-KDE-ServiceTypes=KonqDndPopupMenu/Plugin
|
||||||
|
X-KDE-Library=libextracthere
|
||||||
|
Name=Ark Extract Here
|
||||||
|
Name[ar]=أرك استخرج هنا
|
||||||
|
Name[ast]=Estrayer equí con Ark
|
||||||
|
Name[bg]=Извличане тук
|
||||||
|
Name[bs]=Raspakuj Arkom ovde
|
||||||
|
Name[ca]=Extracció de l'Ark aquí
|
||||||
|
Name[ca@valencia]=Extracció de l'Ark ací
|
||||||
|
Name[cs]=Rozbalit Arkem sem
|
||||||
|
Name[da]=Pak ud med Ark her
|
||||||
|
Name[de]=Ark – Hierher auspacken
|
||||||
|
Name[el]=Εξαγωγή Ark εδώ
|
||||||
|
Name[en_GB]=Ark Extract Here
|
||||||
|
Name[es]=Extraer aquí con Ark
|
||||||
|
Name[et]=Paki siia lahti
|
||||||
|
Name[eu]=Ark: atera hemen
|
||||||
|
Name[fi]=Ark – Pura tähän
|
||||||
|
Name[fr]=Extraire un fichier « Ark » ici
|
||||||
|
Name[ga]=Bain an chartlann Ark amach agus cuir é anseo
|
||||||
|
Name[gl]=Extraer aquí con Ark
|
||||||
|
Name[hr]=Ovdje Ark-otpakiraj
|
||||||
|
Name[hu]=Kibontás ide
|
||||||
|
Name[ia]=Ark Extrahe hic
|
||||||
|
Name[id]=Ark Ekstrak di Sini
|
||||||
|
Name[it]=Ark Estrai qui
|
||||||
|
Name[ja]=Ark ここに展開
|
||||||
|
Name[kk]=Мынаған тарқату
|
||||||
|
Name[km]=ស្រង់ចេញ Ark នៅទីនេះ
|
||||||
|
Name[ko]=Ark 여기에 풀기
|
||||||
|
Name[lt]=Čia išpakuoti archyvą
|
||||||
|
Name[lv]=Ark atspiest šeit
|
||||||
|
Name[mr]=येथे आर्क पुर्ववत करा
|
||||||
|
Name[nb]=Pakk ut arkivet her med Ark
|
||||||
|
Name[nds]=Hier mit Ark utpacken
|
||||||
|
Name[nl]=Ark: hier uitpakken
|
||||||
|
Name[nn]=Pakk ut med Ark her
|
||||||
|
Name[pa]=ਅਕਾਇਵ ਇੱਥੇ ਖੋਲ੍ਹੋ
|
||||||
|
Name[pl]=Rozpakuj tutaj
|
||||||
|
Name[pt]=Extrair para Aqui
|
||||||
|
Name[pt_BR]=Extrair com o Ark aqui
|
||||||
|
Name[ro]=Ark extrage aici
|
||||||
|
Name[ru]=Распаковать в эту папку
|
||||||
|
Name[sk]=Ark - rozbaliť sem
|
||||||
|
Name[sl]=Razširi sem z Arkom
|
||||||
|
Name[sq]=Ark Ekstrakton Këtu
|
||||||
|
Name[sr]=Распакуј Арком овде
|
||||||
|
Name[sr@ijekavian]=Распакуј Арком овдје
|
||||||
|
Name[sr@ijekavianlatin]=Raspakuj Arkom ovdje
|
||||||
|
Name[sr@latin]=Raspakuj Arkom ovde
|
||||||
|
Name[sv]=Packa upp arkiv här
|
||||||
|
Name[th]=อาร์ก คลายแฟ้มไว้ที่นี่
|
||||||
|
Name[tr]=Ark Arşivi Buraya Çıkart
|
||||||
|
Name[uk]=Видобути архів сюди з Ark
|
||||||
|
Name[wa]=Saetchî foû avou Ark cial
|
||||||
|
Name[x-test]=xxArk Extract Herexx
|
||||||
|
Name[zh_CN]=Ark 在此解压缩
|
||||||
|
Name[zh_TW]=在此解壓縮
|
||||||
|
MimeType=@SUPPORTED_ARK_MIMETYPES@
|
238
ark/app/ark_servicemenu.desktop.cmake
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Service
|
||||||
|
ServiceTypes=KonqPopupMenu/Plugin
|
||||||
|
MimeType=@SUPPORTED_ARK_MIMETYPES@
|
||||||
|
Actions=arkAutoExtractHere;arkExtractTo;arkExtractHere;
|
||||||
|
X-KDE-Priority=TopLevel
|
||||||
|
X-KDE-StartupNotify=false
|
||||||
|
#StartupNotify=false
|
||||||
|
X-KDE-Submenu=Extract
|
||||||
|
X-KDE-Submenu[ar]=استخرِج
|
||||||
|
X-KDE-Submenu[bg]=Извличане
|
||||||
|
X-KDE-Submenu[bs]=Raspakivanje
|
||||||
|
X-KDE-Submenu[ca]=Extreu
|
||||||
|
X-KDE-Submenu[ca@valencia]=Extrau
|
||||||
|
X-KDE-Submenu[cs]=Rozbalit
|
||||||
|
X-KDE-Submenu[da]=Pak ud
|
||||||
|
X-KDE-Submenu[de]=Entpacken
|
||||||
|
X-KDE-Submenu[el]=Εξαγωγή
|
||||||
|
X-KDE-Submenu[en_GB]=Extract
|
||||||
|
X-KDE-Submenu[es]=Extraer
|
||||||
|
X-KDE-Submenu[et]=Lahtipakkimine
|
||||||
|
X-KDE-Submenu[eu]=Atera
|
||||||
|
X-KDE-Submenu[fi]=Pura
|
||||||
|
X-KDE-Submenu[fr]=Extraire
|
||||||
|
X-KDE-Submenu[ga]=Bain amach
|
||||||
|
X-KDE-Submenu[gl]=Extraer
|
||||||
|
X-KDE-Submenu[hr]=Otpakiraj
|
||||||
|
X-KDE-Submenu[hu]=Kibontás
|
||||||
|
X-KDE-Submenu[ia]=Extrahe
|
||||||
|
X-KDE-Submenu[it]=Estrai
|
||||||
|
X-KDE-Submenu[ja]=展開
|
||||||
|
X-KDE-Submenu[kk]=Тарқату
|
||||||
|
X-KDE-Submenu[km]=ស្រង់ចេញ
|
||||||
|
X-KDE-Submenu[ko]=압축 풀기
|
||||||
|
X-KDE-Submenu[lt]=Išpakuoti
|
||||||
|
X-KDE-Submenu[mr]=पुर्ववत करा
|
||||||
|
X-KDE-Submenu[nb]=Pakk ut
|
||||||
|
X-KDE-Submenu[nds]=Utpacken
|
||||||
|
X-KDE-Submenu[nl]=Uitpakken
|
||||||
|
X-KDE-Submenu[pa]=ਇੱਥੇ ਖਿਲਾਰੋ
|
||||||
|
X-KDE-Submenu[pl]=Rozpakuj
|
||||||
|
X-KDE-Submenu[pt]=Extrair
|
||||||
|
X-KDE-Submenu[pt_BR]=Extrair
|
||||||
|
X-KDE-Submenu[ro]=Extrage
|
||||||
|
X-KDE-Submenu[ru]=Распаковать
|
||||||
|
X-KDE-Submenu[sk]=Rozbaliť
|
||||||
|
X-KDE-Submenu[sl]=Razširi
|
||||||
|
X-KDE-Submenu[sr]=Распакуј
|
||||||
|
X-KDE-Submenu[sr@ijekavian]=Распакуј
|
||||||
|
X-KDE-Submenu[sr@ijekavianlatin]=Raspakuj
|
||||||
|
X-KDE-Submenu[sr@latin]=Raspakuj
|
||||||
|
X-KDE-Submenu[sv]=Packa upp
|
||||||
|
X-KDE-Submenu[tr]=Çıkart
|
||||||
|
X-KDE-Submenu[ug]=ئايرىش
|
||||||
|
X-KDE-Submenu[uk]=Видобути
|
||||||
|
X-KDE-Submenu[x-test]=xxExtractxx
|
||||||
|
X-KDE-Submenu[zh_CN]=解压缩
|
||||||
|
X-KDE-Submenu[zh_TW]=解開
|
||||||
|
|
||||||
|
[Desktop Action arkExtractHere]
|
||||||
|
Name=Extract Archive Here
|
||||||
|
Name[ar]=فك الأرشيف هنا
|
||||||
|
Name[ast]=Estrayer archivu comprimíu equí
|
||||||
|
Name[bg]=Извличане тук
|
||||||
|
Name[bs]=Raspakuj arhivu ovde
|
||||||
|
Name[ca]=Extreu l'arxiu aquí
|
||||||
|
Name[ca@valencia]=Extrau l'arxiu ací
|
||||||
|
Name[cs]=Rozbalit archiv sem
|
||||||
|
Name[da]=Udpak arkiv her
|
||||||
|
Name[de]=Archiv hierher auspacken
|
||||||
|
Name[el]=Εξαγωγή αρχειοθήκης εδώ
|
||||||
|
Name[en_GB]=Extract Archive Here
|
||||||
|
Name[es]=Extraer archivo comprimido aquí
|
||||||
|
Name[et]=Paki arhiiv siia lahti
|
||||||
|
Name[eu]=Atera artxiboa hemen
|
||||||
|
Name[fi]=Pura paketti tähän
|
||||||
|
Name[fr]=Extraire l'archive ici
|
||||||
|
Name[ga]=Bain an chartlann amach agus cuir é anseo
|
||||||
|
Name[gl]=Extraer o arquivo aquí
|
||||||
|
Name[hr]=Ovdje otpakiraj arhivu
|
||||||
|
Name[hu]=Kibontás ide
|
||||||
|
Name[ia]=Extrahe archivo hic
|
||||||
|
Name[id]=Ekstrak Arsip di Sini
|
||||||
|
Name[it]=Estrai l'archivio qui
|
||||||
|
Name[ja]=アーカイブをここに展開
|
||||||
|
Name[kk]=Архивті мынаған тарқату
|
||||||
|
Name[km]=ស្រង់ចេញប័ណ្ណសារនៅទីនេះ
|
||||||
|
Name[ko]=여기에 압축 풀기
|
||||||
|
Name[lt]=Čia išpakuoti archyvą
|
||||||
|
Name[lv]=Atspiest arhīvu šeit
|
||||||
|
Name[mr]=येथे संग्रह पुर्ववत करा
|
||||||
|
Name[nb]=Pakk ut arkivet her
|
||||||
|
Name[nds]=Archiev hier utpacken
|
||||||
|
Name[nl]=Archief hier uitpakken
|
||||||
|
Name[nn]=Pakk ut arkivet her
|
||||||
|
Name[pa]=ਅਕਾਇਵ ਇੱਥੇ ਖੋਲ੍ਹੋ
|
||||||
|
Name[pl]=Rozpakuj archiwum tutaj
|
||||||
|
Name[pt]=Extrair o Pacote para Aqui
|
||||||
|
Name[pt_BR]=Extrair arquivo aqui
|
||||||
|
Name[ro]=Extrage arhiva aici
|
||||||
|
Name[ru]=В эту папку
|
||||||
|
Name[sk]=Rozbaliť archív sem
|
||||||
|
Name[sl]=Razširi arhiv sem
|
||||||
|
Name[sq]=Ekstrakto Arkivin Këtu
|
||||||
|
Name[sr]=Распакуј архиву овде
|
||||||
|
Name[sr@ijekavian]=Распакуј архиву овдје
|
||||||
|
Name[sr@ijekavianlatin]=Raspakuj arhivu ovdje
|
||||||
|
Name[sr@latin]=Raspakuj arhivu ovde
|
||||||
|
Name[sv]=Packa upp arkiv här
|
||||||
|
Name[th]=คลายแฟ้มจัดเก็บไว้ที่นี่
|
||||||
|
Name[tr]=Arşivi Buraya Çıkart
|
||||||
|
Name[uk]=Видобути архів сюди
|
||||||
|
Name[wa]=Saetchî l' årtchive foû cial
|
||||||
|
Name[x-test]=xxExtract Archive Herexx
|
||||||
|
Name[zh_CN]=在此解压缩归档
|
||||||
|
Name[zh_TW]=在此解壓縮
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --batch --autodestination %F
|
||||||
|
|
||||||
|
[Desktop Action arkExtractTo]
|
||||||
|
Name=Extract Archive To...
|
||||||
|
Name[ar]=فك الأرشيف إلى...
|
||||||
|
Name[ast]=Estrayer archivu comprimíu en...
|
||||||
|
Name[bg]=Извличане в...
|
||||||
|
Name[bs]=Raspakuj arhivu u...
|
||||||
|
Name[ca]=Extreu l'arxiu a...
|
||||||
|
Name[ca@valencia]=Extrau l'arxiu a...
|
||||||
|
Name[cs]=Rozbalit archiv do...
|
||||||
|
Name[da]=Udpak arkiv til...
|
||||||
|
Name[de]=Archiv auspacken nach ...
|
||||||
|
Name[el]=Εξαγωγή αρχειοθήκης σε...
|
||||||
|
Name[en_GB]=Extract Archive To...
|
||||||
|
Name[es]=Extraer archivo comprimido en...
|
||||||
|
Name[et]=Paki arhiiv lahti...
|
||||||
|
Name[eu]=Atera artxiboa hona...
|
||||||
|
Name[fi]=Pura paketti…
|
||||||
|
Name[fr]=Extraire l'archive vers...
|
||||||
|
Name[ga]=Bain an chartlann amach go...
|
||||||
|
Name[gl]=Extraer o arquivo en...
|
||||||
|
Name[hr]=Otpakiraj arhivu u …
|
||||||
|
Name[hu]=Kibontás ide…
|
||||||
|
Name[ia]=Extrahe archivo in...
|
||||||
|
Name[id]=Ekstrak Arsip ke...
|
||||||
|
Name[it]=Estrai l'archivio in...
|
||||||
|
Name[ja]=アーカイブを展開...
|
||||||
|
Name[kk]=Мынаған тарқату...
|
||||||
|
Name[km]=ស្រង់ចេញប័ណ្ណសារទៅ...
|
||||||
|
Name[ko]=다음 경로에 압축 풀기...
|
||||||
|
Name[lt]=Išpakuoti archyvą į...
|
||||||
|
Name[lv]=Atspiest arhīvu uz...
|
||||||
|
Name[mr]=यावर संग्रह पुर्ववत करा...
|
||||||
|
Name[nb]=Pakk ut arkivet til …
|
||||||
|
Name[nds]=Archiev utpacken as...
|
||||||
|
Name[nl]=Archief uitpakken naar...
|
||||||
|
Name[nn]=Pakk ut arkivet til …
|
||||||
|
Name[pa]=...ਵਜੋਂ ਅਕਾਇਵ ਐਕਸਟਰੈਕਟ
|
||||||
|
Name[pl]=Rozpakuj archiwum do...
|
||||||
|
Name[pt]=Extrair o Pacote Para...
|
||||||
|
Name[pt_BR]=Extrair arquivo para...
|
||||||
|
Name[ro]=Extrage arhiva în...
|
||||||
|
Name[ru]=Указать путь...
|
||||||
|
Name[sk]=Rozbaliť archív do...
|
||||||
|
Name[sl]=Razširi arhiv v ...
|
||||||
|
Name[sq]=Ekstrakto Arkivin Tek...
|
||||||
|
Name[sr]=Распакуј архиву у...
|
||||||
|
Name[sr@ijekavian]=Распакуј архиву у...
|
||||||
|
Name[sr@ijekavianlatin]=Raspakuj arhivu u...
|
||||||
|
Name[sr@latin]=Raspakuj arhivu u...
|
||||||
|
Name[sv]=Packa upp arkiv i...
|
||||||
|
Name[th]=คลายแฟ้มจัดเก็บไปยัง...
|
||||||
|
Name[tr]=Arşivi Şuraya Çıkart...
|
||||||
|
Name[uk]=Видобути архів до...
|
||||||
|
Name[wa]=Saetchî l' årtchive foû eyet l' rilomer...
|
||||||
|
Name[x-test]=xxExtract Archive To...xx
|
||||||
|
Name[zh_CN]=解压缩归档到...
|
||||||
|
Name[zh_TW]=解壓縮到...
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --batch --autodestination --dialog %F
|
||||||
|
|
||||||
|
[Desktop Action arkAutoExtractHere]
|
||||||
|
Name=Extract Archive Here, Autodetect Subfolder
|
||||||
|
Name[ar]=فك الأرشيف هنا ، تعرف تلقائي للمجلدات الفرعية
|
||||||
|
Name[ast]=Estrayer archivu comprimíu equí, autodeteutar subcarpeta
|
||||||
|
Name[bg]=Извличане тук, автоматична подпапка
|
||||||
|
Name[bs]=Raspakuj arhivu ovdje, pogodi poddirektorij
|
||||||
|
Name[ca]=Extreu l'arxiu aquí, detecta automàticament la subcarpeta
|
||||||
|
Name[ca@valencia]=Extrau l'arxiu ací, detecta automàticament la subcarpeta
|
||||||
|
Name[cs]=Rozbalit archiv sem, automaticky detekovat podsložku
|
||||||
|
Name[da]=Udpak arkiv her og find automatisk undermappe
|
||||||
|
Name[de]=Archiv hierher auspacken, Unterordner selbständig ermitteln
|
||||||
|
Name[el]=Εξαγωγή αρχειοθήκης εδώ, αυτόματη επιλογή υποφακέλου
|
||||||
|
Name[en_GB]=Extract Archive Here, Autodetect Subfolder
|
||||||
|
Name[es]=Extraer archivo comprimido aquí, autodetectar subcarpeta
|
||||||
|
Name[et]=Paki arhiiv siia lahti, tuvasta automaatselt alamkataloog
|
||||||
|
Name[eu]=Atera artxiboa hona, automatikoki detektatu azpikarpeta
|
||||||
|
Name[fi]=Pura paketti tähän, tunnista alikansio automaattisesti
|
||||||
|
Name[fr]=Extraire l'archive ici, auto-détecter les sous-dossiers
|
||||||
|
Name[ga]=Bain an chartlann amach agus cuir é anseo, braith fofhillteán go huathoibríoch
|
||||||
|
Name[gl]=Extraer o arquivo aquí, detectar o subcartafol
|
||||||
|
Name[hr]=Ovdje otpakiraj arhivu i automatski prepoznaj podmapu
|
||||||
|
Name[hu]=Kibontás ide (automatikus almappalétrehozás)
|
||||||
|
Name[ia]=Extrahe archivo hic, auto-releva subdossier
|
||||||
|
Name[id]=Ekstrak Arsip di Sini, Deteksi Otomatis Subfolder
|
||||||
|
Name[it]=Estrai l'archivio qui, autorileva la sottocartella
|
||||||
|
Name[ja]=アーカイブをここに展開、サブフォルダを自動検出
|
||||||
|
Name[kk]=Мынаған, ішкі қапшығына тарқату
|
||||||
|
Name[km]=ស្រង់ចេញប័ណ្ណសារនៅទីនេះ រកថតរងឃើញដោយស្វ័យប្រវត្តិ
|
||||||
|
Name[ko]=하위 폴더를 감지해서 여기에 압축 풀기
|
||||||
|
Name[lt]=Išpakuoti archyvą čia, automatiškai rasti poaplankius
|
||||||
|
Name[lv]=Atspiest arhīvu šeit, automātiska apakšmape
|
||||||
|
Name[mr]=येथे संग्रह पुर्ववत करा, उपसंचयीका स्वंयंशोध
|
||||||
|
Name[nb]=Pakk ut arkivet her, finn undermapper automatisk
|
||||||
|
Name[nds]=Archiev hier utpacken, Ünnerorner autom. opdecken
|
||||||
|
Name[nl]=Archief hier uitpakken, submap autodetecteren
|
||||||
|
Name[nn]=Pakk ut arkivet her / til undermappe
|
||||||
|
Name[pa]=ਅਕਾਇਵ ਇੱਥੇ ਖੋਲ੍ਹੋ, ਸਬ-ਫੋਲਡਰ ਆਪੇ ਖੋਜੋ
|
||||||
|
Name[pl]=Rozpakuj archiwum tutaj, wykryj podkatalogi
|
||||||
|
Name[pt]=Extrair o Pacote Aqui com Detecção da Sub-Pasta
|
||||||
|
Name[pt_BR]=Extrair aqui detectando subpasta
|
||||||
|
Name[ro]=Extrage arhiva aici, autodetectează subdosarul
|
||||||
|
Name[ru]=Во вложенную папку
|
||||||
|
Name[sk]=Rozbaliť archív sem, automaticky určiť podpriečinok
|
||||||
|
Name[sl]=Razširi arhiv sem, samodejno zaznaj podmapo
|
||||||
|
Name[sq]=Ekstrakto Arkivin Këtu, Vetëdallo Nëndosjen
|
||||||
|
Name[sr]=Распакуј архиву овде, погоди потфасциклу
|
||||||
|
Name[sr@ijekavian]=Распакуј архиву овдје, погоди потфасциклу
|
||||||
|
Name[sr@ijekavianlatin]=Raspakuj arhivu ovdje, pogodi potfasciklu
|
||||||
|
Name[sr@latin]=Raspakuj arhivu ovde, pogodi potfasciklu
|
||||||
|
Name[sv]=Packa upp arkiv här, detektera underkatalog automatiskt
|
||||||
|
Name[th]=คลายแฟ้มจัดเก็บไว้ที่นี่, และตรวจสอบโฟลเดอร์ย่อยอัตโนมัติ
|
||||||
|
Name[tr]=Arşivi Buraya Çıkart, Alt Dizinleri Otomatik Belirle
|
||||||
|
Name[uk]=Видобути архів сюди, автоматично визначити підтеку
|
||||||
|
Name[wa]=Saetchî l' årtchive foû cial, deteccion otomatike do ridant efant
|
||||||
|
Name[x-test]=xxExtract Archive Here, Autodetect Subfolderxx
|
||||||
|
Name[zh_CN]=在此解压缩归档,自动探测子文件夹
|
||||||
|
Name[zh_TW]=在此解壓縮,自動偵測子資料夾
|
||||||
|
Icon=ark
|
||||||
|
Exec=ark --batch --autodestination --autosubfolder %F
|
17
ark/app/arkui.rc
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE kpartgui>
|
||||||
|
<kpartgui name="ark" version="12">
|
||||||
|
<MenuBar>
|
||||||
|
<Menu name="file">
|
||||||
|
<DefineGroup name="file_save" append="save_merge"/>
|
||||||
|
</Menu>
|
||||||
|
<Merge/>
|
||||||
|
<Menu name="settings">
|
||||||
|
<DefineGroup name="settings_show" append="show_merge"/>
|
||||||
|
</Menu>
|
||||||
|
</MenuBar>
|
||||||
|
<ToolBar noMerge="1" name="mainToolBar">
|
||||||
|
<text>Main Toolbar</text>
|
||||||
|
<Action name="file_new"/>
|
||||||
|
<Action name="file_open"/>
|
||||||
|
</ToolBar>
|
||||||
|
</kpartgui>
|
292
ark/app/batchextract.cpp
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009-2010 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "batchextract.h"
|
||||||
|
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "kerfuffle/extractiondialog.h"
|
||||||
|
#include "kerfuffle/jobs.h"
|
||||||
|
#include "kerfuffle/queries.h"
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KGlobal>
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KRun>
|
||||||
|
#include <KIO/RenameDialog>
|
||||||
|
#include <kwidgetjobtracker.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
|
||||||
|
BatchExtract::BatchExtract()
|
||||||
|
: KCompositeJob(0),
|
||||||
|
m_autoSubfolder(false),
|
||||||
|
m_preservePaths(true),
|
||||||
|
m_openDestinationAfterExtraction(false)
|
||||||
|
{
|
||||||
|
setCapabilities(KJob::Killable);
|
||||||
|
|
||||||
|
connect(this, SIGNAL(result(KJob*)), SLOT(showFailedFiles()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchExtract::~BatchExtract()
|
||||||
|
{
|
||||||
|
if (!m_inputs.isEmpty()) {
|
||||||
|
KIO::getJobTracker()->unregisterJob(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::addExtraction(Kerfuffle::Archive* archive)
|
||||||
|
{
|
||||||
|
QString destination = destinationFolder();
|
||||||
|
|
||||||
|
if ((autoSubfolder()) && (!archive->isSingleFolderArchive())) {
|
||||||
|
const QDir d(destination);
|
||||||
|
QString subfolderName = archive->subfolderName();
|
||||||
|
|
||||||
|
if (d.exists(subfolderName)) {
|
||||||
|
subfolderName = KIO::RenameDialog::suggestName(destination, subfolderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.mkdir(subfolderName);
|
||||||
|
|
||||||
|
destination += QLatin1Char( '/' ) + subfolderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
options[QLatin1String( "PreservePaths" )] = preservePaths();
|
||||||
|
|
||||||
|
Kerfuffle::ExtractJob *job = archive->copyFiles(QVariantList(), destination, options);
|
||||||
|
|
||||||
|
kDebug() << QString(QLatin1String( "Registering job from archive %1, to %2, preservePaths %3" )).arg(archive->fileName()).arg(destination).arg(preservePaths());
|
||||||
|
|
||||||
|
addSubjob(job);
|
||||||
|
|
||||||
|
m_fileNames[job] = qMakePair(archive->fileName(), destination);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(percent(KJob*,ulong)),
|
||||||
|
this, SLOT(forwardProgress(KJob*,ulong)));
|
||||||
|
connect(job, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
this, SLOT(slotUserQuery(Kerfuffle::Query*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::slotUserQuery(Kerfuffle::Query *query)
|
||||||
|
{
|
||||||
|
query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatchExtract::autoSubfolder() const
|
||||||
|
{
|
||||||
|
return m_autoSubfolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::setAutoSubfolder(bool value)
|
||||||
|
{
|
||||||
|
m_autoSubfolder = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::start()
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, this, SLOT(slotStartJob()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::slotStartJob()
|
||||||
|
{
|
||||||
|
// If none of the archives could be loaded, there is no subjob to run
|
||||||
|
if (m_inputs.isEmpty()) {
|
||||||
|
emitResult();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(Kerfuffle::Archive *archive, m_inputs) {
|
||||||
|
addExtraction(archive);
|
||||||
|
}
|
||||||
|
|
||||||
|
KIO::getJobTracker()->registerJob(this);
|
||||||
|
|
||||||
|
emit description(this,
|
||||||
|
i18n("Extracting file..."),
|
||||||
|
qMakePair(i18n("Source archive"), m_fileNames.value(subjobs().at(0)).first),
|
||||||
|
qMakePair(i18n("Destination"), m_fileNames.value(subjobs().at(0)).second)
|
||||||
|
);
|
||||||
|
|
||||||
|
m_initialJobCount = subjobs().size();
|
||||||
|
|
||||||
|
kDebug() << "Starting first job";
|
||||||
|
|
||||||
|
subjobs().at(0)->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::showFailedFiles()
|
||||||
|
{
|
||||||
|
if (!m_failedFiles.isEmpty()) {
|
||||||
|
KMessageBox::informationList(0, i18n("The following files could not be extracted:"), m_failedFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::slotResult(KJob *job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
// TODO: The user must be informed about which file caused the error, and that the other files
|
||||||
|
// in the queue will not be extracted.
|
||||||
|
if (job->error()) {
|
||||||
|
kDebug() << "There was en error, " << job->errorText();
|
||||||
|
|
||||||
|
setErrorText(job->errorText());
|
||||||
|
setError(job->error());
|
||||||
|
|
||||||
|
removeSubjob(job);
|
||||||
|
|
||||||
|
KMessageBox::error(NULL, job->errorText().isEmpty() ?
|
||||||
|
i18n("There was an error during extraction.") : job->errorText()
|
||||||
|
);
|
||||||
|
|
||||||
|
emitResult();
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
removeSubjob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasSubjobs()) {
|
||||||
|
if (openDestinationAfterExtraction()) {
|
||||||
|
KUrl destination(destinationFolder());
|
||||||
|
destination.cleanPath();
|
||||||
|
KRun::runUrl(destination, QLatin1String( "inode/directory" ), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Finished, emitting the result";
|
||||||
|
emitResult();
|
||||||
|
} else {
|
||||||
|
kDebug() << "Starting the next job";
|
||||||
|
emit description(this,
|
||||||
|
i18n("Extracting file..."),
|
||||||
|
qMakePair(i18n("Source archive"), m_fileNames.value(subjobs().at(0)).first),
|
||||||
|
qMakePair(i18n("Destination"), m_fileNames.value(subjobs().at(0)).second)
|
||||||
|
);
|
||||||
|
subjobs().at(0)->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::forwardProgress(KJob *job, unsigned long percent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(job)
|
||||||
|
int jobPart = 100 / m_initialJobCount;
|
||||||
|
setPercent(jobPart *(m_initialJobCount - subjobs().size()) + percent / m_initialJobCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatchExtract::addInput(const KUrl& url)
|
||||||
|
{
|
||||||
|
Kerfuffle::Archive *archive = Kerfuffle::Archive::create(url.pathOrUrl(), this);
|
||||||
|
|
||||||
|
if ((archive == NULL) || (!QFileInfo(url.pathOrUrl()).exists())) {
|
||||||
|
m_failedFiles.append(url.fileName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inputs.append(archive);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatchExtract::openDestinationAfterExtraction() const
|
||||||
|
{
|
||||||
|
return m_openDestinationAfterExtraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatchExtract::preservePaths() const
|
||||||
|
{
|
||||||
|
return m_preservePaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BatchExtract::destinationFolder() const
|
||||||
|
{
|
||||||
|
if (m_destinationFolder.isEmpty()) {
|
||||||
|
return QDir::currentPath();
|
||||||
|
} else {
|
||||||
|
return m_destinationFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::setDestinationFolder(const QString& folder)
|
||||||
|
{
|
||||||
|
if (QFileInfo(folder).isDir()) {
|
||||||
|
m_destinationFolder = folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::setOpenDestinationAfterExtraction(bool value)
|
||||||
|
{
|
||||||
|
m_openDestinationAfterExtraction = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchExtract::setPreservePaths(bool value)
|
||||||
|
{
|
||||||
|
m_preservePaths = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BatchExtract::showExtractDialog()
|
||||||
|
{
|
||||||
|
QWeakPointer<Kerfuffle::ExtractionDialog> dialog =
|
||||||
|
new Kerfuffle::ExtractionDialog;
|
||||||
|
|
||||||
|
if (m_inputs.size() > 1) {
|
||||||
|
dialog.data()->batchModeOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.data()->setAutoSubfolder(autoSubfolder());
|
||||||
|
dialog.data()->setCurrentUrl(destinationFolder());
|
||||||
|
dialog.data()->setPreservePaths(preservePaths());
|
||||||
|
|
||||||
|
if (m_inputs.size() == 1) {
|
||||||
|
if (m_inputs.at(0)->isSingleFolderArchive()) {
|
||||||
|
dialog.data()->setSingleFolderArchive(true);
|
||||||
|
}
|
||||||
|
dialog.data()->setSubfolder(m_inputs.at(0)->subfolderName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dialog.data()->exec()) {
|
||||||
|
delete dialog.data();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAutoSubfolder(dialog.data()->autoSubfolders());
|
||||||
|
setDestinationFolder(dialog.data()->destinationDirectory().pathOrUrl());
|
||||||
|
setOpenDestinationAfterExtraction(dialog.data()->openDestinationAfterExtraction());
|
||||||
|
setPreservePaths(dialog.data()->preservePaths());
|
||||||
|
|
||||||
|
delete dialog.data();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <batchextract.moc>
|
234
ark/app/batchextract.h
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009-2010 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BATCHEXTRACT_H
|
||||||
|
#define BATCHEXTRACT_H
|
||||||
|
|
||||||
|
#include <kcompositejob.h>
|
||||||
|
#include <KUrl>
|
||||||
|
|
||||||
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QPair>
|
||||||
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class Archive;
|
||||||
|
class Query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class schedules the extraction of all given compressed archives.
|
||||||
|
*
|
||||||
|
* Like AddToArchive, this class does not need the GUI to be active, and
|
||||||
|
* provides the functionality available from the --batch command-line option.
|
||||||
|
*
|
||||||
|
* @author Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*/
|
||||||
|
class BatchExtract : public KCompositeJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a new BatchExtract object.
|
||||||
|
*/
|
||||||
|
BatchExtract();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a BatchExtract object.
|
||||||
|
*/
|
||||||
|
virtual ~BatchExtract();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ExtractJob for the given @p archive and puts it on the queue.
|
||||||
|
*
|
||||||
|
* If necessary, the destination directory for the archive is created.
|
||||||
|
*
|
||||||
|
* @param archive The archive that will be extracted.
|
||||||
|
*
|
||||||
|
* @see setAutoSubfolder
|
||||||
|
*/
|
||||||
|
void addExtraction(Kerfuffle::Archive* archive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper that calls slotStartJob() when the event loop has started.
|
||||||
|
*/
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to automatically create a folder inside the destination
|
||||||
|
* directory if the archive has more than one directory or file
|
||||||
|
* at top level.
|
||||||
|
*
|
||||||
|
* @return @c true Create the subdirectory automatically.
|
||||||
|
* @return @c false Do not create the subdirectory automatically.
|
||||||
|
*/
|
||||||
|
bool autoSubfolder() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether a folder should be created when necessary so
|
||||||
|
* the archive is extracted to it.
|
||||||
|
*
|
||||||
|
* If set to @c true, when the archive does not consist of a
|
||||||
|
* single folder with the other files and directories inside,
|
||||||
|
* a directory will be automatically created inside the destination
|
||||||
|
* directory and the archive will be extracted there.
|
||||||
|
*
|
||||||
|
* @param value Whether to create this directory automatically
|
||||||
|
* when needed.
|
||||||
|
*/
|
||||||
|
void setAutoSubfolder(bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a file to the list of files that will be extracted.
|
||||||
|
*
|
||||||
|
* @param url The file that will be added to the list.
|
||||||
|
*
|
||||||
|
* @return @c true The file exists and a suitable plugin
|
||||||
|
* could be found for it.
|
||||||
|
* @return @c false The file does not exist or a suitable
|
||||||
|
* plugin could not be found.
|
||||||
|
*/
|
||||||
|
bool addInput(const KUrl& url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the extract options dialog before extracting the files.
|
||||||
|
*
|
||||||
|
* @return @c true The user has set some options and clicked OK.
|
||||||
|
* @return @c false The user has canceled extraction.
|
||||||
|
*/
|
||||||
|
bool showExtractDialog();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the destination directory where the archives
|
||||||
|
* will be extracted to.
|
||||||
|
*
|
||||||
|
* @return The destination directory. If no directory has been manually
|
||||||
|
* set with setDestinationFolder, QDir::currentPath() will be
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
QString destinationFolder() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the directory the archives will be extracted to.
|
||||||
|
*
|
||||||
|
* If @c setSubfolder has been used, the final destination
|
||||||
|
* directory will be the concatenation of both.
|
||||||
|
*
|
||||||
|
* If @p folder does not exist, the current destination
|
||||||
|
* folder will not change.
|
||||||
|
*
|
||||||
|
* @param folder The directory that will be used.
|
||||||
|
*/
|
||||||
|
void setDestinationFolder(const QString& folder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the destination folder should
|
||||||
|
* be open after all archives are extracted.
|
||||||
|
*
|
||||||
|
* @return @c true Open the destination folder.
|
||||||
|
* @return @c false Do not open the destination folder.
|
||||||
|
*/
|
||||||
|
bool openDestinationAfterExtraction() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to open the destination folder after
|
||||||
|
* all archives are extracted.
|
||||||
|
*
|
||||||
|
* @param value Whether to open the destination.
|
||||||
|
*/
|
||||||
|
void setOpenDestinationAfterExtraction(bool value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether all files should be extracted to the same directory,
|
||||||
|
* even if they're in different directories in the archive.
|
||||||
|
*
|
||||||
|
* This is also known as "flat" extraction.
|
||||||
|
*
|
||||||
|
* @return @c true Paths should be preserved.
|
||||||
|
* @return @c false Paths should be ignored.
|
||||||
|
*/
|
||||||
|
bool preservePaths() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether paths should be preserved during extraction.
|
||||||
|
*
|
||||||
|
* When it is set to false, all files are extracted to a single
|
||||||
|
* directory, regardless of their hierarchy in the archive.
|
||||||
|
*
|
||||||
|
* @param value Whether to preserve paths.
|
||||||
|
*/
|
||||||
|
void setPreservePaths(bool value);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* Updates the percentage of the job that has been completed.
|
||||||
|
*/
|
||||||
|
void forwardProgress(KJob *job, unsigned long percent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dialog with a list of all the files that could not
|
||||||
|
* be successfully extracted.
|
||||||
|
*/
|
||||||
|
void showFailedFiles();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows an error message if the current job hasn't finished
|
||||||
|
* successfully, and advances to the next extraction job if
|
||||||
|
* there are more.
|
||||||
|
*/
|
||||||
|
void slotResult(KJob *job);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a query dialog, which may happen when a file already exists.
|
||||||
|
*/
|
||||||
|
void slotUserQuery(Kerfuffle::Query *query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the real work for start() and extracts all scheduled files.
|
||||||
|
*
|
||||||
|
* Each extraction job is started after the last one finishes.
|
||||||
|
* The jobs are executed in the order they were added via addInput().
|
||||||
|
*/
|
||||||
|
void slotStartJob();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_initialJobCount;
|
||||||
|
QMap<KJob*, QPair<QString, QString> > m_fileNames;
|
||||||
|
bool m_autoSubfolder;
|
||||||
|
|
||||||
|
QList<Kerfuffle::Archive*> m_inputs;
|
||||||
|
QString m_destinationFolder;
|
||||||
|
QStringList m_failedFiles;
|
||||||
|
bool m_preservePaths;
|
||||||
|
bool m_openDestinationAfterExtraction;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BATCHEXTRACT_H
|
82
ark/app/extractHereDndPlugin.cpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Harald Hvaal <haraldhv (at@at) stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 "extractHereDndPlugin.h"
|
||||||
|
#include "batchextract.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
#include <KAction>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
#include <KPluginLoader>
|
||||||
|
#include <KLocale>
|
||||||
|
#include <kfileitemlistproperties.h>
|
||||||
|
|
||||||
|
K_PLUGIN_FACTORY(ExtractHerePluginFactory,
|
||||||
|
registerPlugin<ExtractHereDndPlugin>();
|
||||||
|
)
|
||||||
|
K_EXPORT_PLUGIN(ExtractHerePluginFactory("stupidname", "ark"))
|
||||||
|
|
||||||
|
void ExtractHereDndPlugin::slotTriggered()
|
||||||
|
{
|
||||||
|
kDebug() << "Preparing job";
|
||||||
|
BatchExtract *batchJob = new BatchExtract();
|
||||||
|
|
||||||
|
batchJob->setAutoSubfolder(true);
|
||||||
|
batchJob->setDestinationFolder(m_dest.pathOrUrl());
|
||||||
|
batchJob->setPreservePaths(true);
|
||||||
|
foreach(const KUrl& url, m_urls) {
|
||||||
|
batchJob->addInput(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
batchJob->start();
|
||||||
|
kDebug() << "Started job";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractHereDndPlugin::ExtractHereDndPlugin(QObject* parent, const QVariantList&)
|
||||||
|
: KonqDndPopupMenuPlugin(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractHereDndPlugin::setup(const KFileItemListProperties& popupMenuInfo,
|
||||||
|
KUrl destination,
|
||||||
|
QList<QAction*>& userActions)
|
||||||
|
{
|
||||||
|
const QString extractHereMessage = i18nc("@action:inmenu Context menu shown when an archive is being drag'n'dropped", "Extract here");
|
||||||
|
|
||||||
|
if (!Kerfuffle::supportedMimeTypes().contains(popupMenuInfo.mimeType())) {
|
||||||
|
kDebug() << popupMenuInfo.mimeType() << "is not a supported mimetype";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Plugin executed";
|
||||||
|
|
||||||
|
KAction *action = new KAction(KIcon(QLatin1String("archive-extract")),
|
||||||
|
extractHereMessage, NULL);
|
||||||
|
connect(action, SIGNAL(triggered()), this, SLOT(slotTriggered()));
|
||||||
|
|
||||||
|
userActions.append(action);
|
||||||
|
m_dest = destination;
|
||||||
|
m_urls = popupMenuInfo.urlList();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "extractHereDndPlugin.moc"
|
46
ark/app/extractHereDndPlugin.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Harald Hvaal <haraldhv (at@at) stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 EXTRACTHEREDNDPLUGIN_H
|
||||||
|
#define EXTRACTHEREDNDPLUGIN_H
|
||||||
|
|
||||||
|
#include <kurl.h>
|
||||||
|
#include <konq_dndpopupmenuplugin.h>
|
||||||
|
|
||||||
|
class ExtractHereDndPlugin : public KonqDndPopupMenuPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotTriggered();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ExtractHereDndPlugin(QObject* parent, const QVariantList&);
|
||||||
|
|
||||||
|
virtual void setup(const KFileItemListProperties& popupMenuInfo,
|
||||||
|
KUrl destination,
|
||||||
|
QList<QAction*>& userActions);
|
||||||
|
private:
|
||||||
|
KUrl m_dest;
|
||||||
|
QList<KUrl> m_urls;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* EXTRACTHEREDNDPLUGIN_H */
|
1
ark/app/icons/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
kde4_install_icons(${ICON_INSTALL_DIR})
|
BIN
ark/app/icons/hi128-apps-ark.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
ark/app/icons/hi16-apps-ark.png
Normal file
After Width: | Height: | Size: 528 B |
BIN
ark/app/icons/hi22-apps-ark.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
ark/app/icons/hi32-apps-ark.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
ark/app/icons/hi48-apps-ark.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
ark/app/icons/hi64-apps-ark.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
ark/app/icons/hisc-apps-ark.svgz
Normal file
210
ark/app/main.cpp
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 "mainwindow.h"
|
||||||
|
#include "batchextract.h"
|
||||||
|
#include "kerfuffle/addtoarchive.h"
|
||||||
|
|
||||||
|
#include <KAboutData>
|
||||||
|
#include <KApplication>
|
||||||
|
#include <KCmdLineArgs>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KLocale>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
using Kerfuffle::AddToArchive;
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
KAboutData aboutData("ark", 0, ki18n("Ark"),
|
||||||
|
"2.19", ki18n("KDE Archiving tool"),
|
||||||
|
KAboutData::License_GPL,
|
||||||
|
ki18n("(c) 1997-2011, The Various Ark Developers"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"http://utils.kde.org/projects/ark"
|
||||||
|
);
|
||||||
|
|
||||||
|
aboutData.addAuthor(ki18n("Raphael Kubo da Costa"),
|
||||||
|
ki18n("Maintainer"),
|
||||||
|
"rakuco@FreeBSD.org");
|
||||||
|
aboutData.addAuthor(ki18n("Harald Hvaal"),
|
||||||
|
ki18n("Former Maintainer"),
|
||||||
|
"haraldhv@stud.ntnu.no");
|
||||||
|
aboutData.addAuthor(ki18n("Henrique Pinto"),
|
||||||
|
ki18n("Former Maintainer"),
|
||||||
|
"henrique.pinto@kdemail.net");
|
||||||
|
aboutData.addAuthor(ki18n("Helio Chissini de Castro"),
|
||||||
|
ki18n("Former maintainer"),
|
||||||
|
"helio@kde.org");
|
||||||
|
aboutData.addAuthor(ki18n("Georg Robbers"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"Georg.Robbers@urz.uni-hd.de");
|
||||||
|
aboutData.addAuthor(ki18n("Roberto Selbach Teixeira"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"maragato@kde.org");
|
||||||
|
aboutData.addAuthor(ki18n("Francois-Xavier Duranceau"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"duranceau@kde.org");
|
||||||
|
aboutData.addAuthor(ki18n("Emily Ezust (Corel Corporation)"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"emilye@corel.com");
|
||||||
|
aboutData.addAuthor(ki18n("Michael Jarrett (Corel Corporation)"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"michaelj@corel.com");
|
||||||
|
aboutData.addAuthor(ki18n("Robert Palmbos"),
|
||||||
|
KLocalizedString(),
|
||||||
|
"palm9744@kettering.edu");
|
||||||
|
|
||||||
|
aboutData.addCredit(ki18n("Bryce Corkins"),
|
||||||
|
ki18n("Icons"),
|
||||||
|
"dbryce@attglobal.net");
|
||||||
|
aboutData.addCredit(ki18n("Liam Smit"),
|
||||||
|
ki18n("Ideas, help with the icons"),
|
||||||
|
"smitty@absamail.co.za");
|
||||||
|
aboutData.addCredit(ki18n("Andrew Smith"),
|
||||||
|
ki18n("bkisofs code"),
|
||||||
|
QByteArray(),
|
||||||
|
"http://littlesvr.ca/misc/contactandrew.php");
|
||||||
|
aboutData.setProgramIconName(QLatin1String("ark"));
|
||||||
|
|
||||||
|
KCmdLineArgs::init(argc, argv, &aboutData);
|
||||||
|
KCmdLineOptions option;
|
||||||
|
option.add("+[url]", ki18n("URL of an archive to be opened"));
|
||||||
|
option.add("d").add("dialog", ki18n("Show a dialog for specifying the options for the operation (extract/add)"));
|
||||||
|
option.add("o").add("destination <directory>", ki18n("Destination folder to extract to. Defaults to current path if not specified."));
|
||||||
|
option.add(":", ki18n("Options for adding files"));
|
||||||
|
option.add("c").add("add", ki18n("Query the user for an archive filename and add specified files to it. Quit when finished."));
|
||||||
|
option.add("t").add("add-to <filename>", ki18n("Add the specified files to 'filename'. Create archive if it does not exist. Quit when finished."));
|
||||||
|
option.add("p").add("changetofirstpath", ki18n("Change the current dir to the first entry and add all other entries relative to this one."));
|
||||||
|
option.add("f").add("autofilename <suffix>", ki18n("Automatically choose a filename, with the selected suffix (for example rar, tar.gz, zip or any other supported types)"));
|
||||||
|
option.add(":", ki18n("Options for batch extraction:"));
|
||||||
|
option.add("b").add("batch", ki18n("Use the batch interface instead of the usual dialog. This option is implied if more than one url is specified."));
|
||||||
|
option.add("e").add("autodestination", ki18n("The destination argument will be set to the path of the first file supplied."));
|
||||||
|
option.add("a").add("autosubfolder", ki18n("Archive contents will be read, and if detected to not be a single folder archive, a subfolder with the name of the archive will be created."));
|
||||||
|
KCmdLineArgs::addCmdLineOptions(option);
|
||||||
|
KCmdLineArgs::addTempFileOption();
|
||||||
|
|
||||||
|
KApplication application;
|
||||||
|
application.setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
|
//session restoring
|
||||||
|
if (application.isSessionRestored()) {
|
||||||
|
MainWindow* window = NULL;
|
||||||
|
|
||||||
|
if (KMainWindow::canBeRestored(1)) {
|
||||||
|
window = new MainWindow;
|
||||||
|
window->restore(1);
|
||||||
|
if (!window->loadPart()) {
|
||||||
|
delete window;
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else { //new ark window (no restored session)
|
||||||
|
// open any given URLs
|
||||||
|
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
|
||||||
|
|
||||||
|
if (args->isSet("add") || args->isSet("add-to")) {
|
||||||
|
AddToArchive *addToArchiveJob = new AddToArchive;
|
||||||
|
application.connect(addToArchiveJob, SIGNAL(result(KJob*)), SLOT(quit()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
if (args->isSet("changetofirstpath")) {
|
||||||
|
addToArchiveJob->setChangeToFirstPath(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("add-to")) {
|
||||||
|
addToArchiveJob->setFilename(args->getOption("add-to"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("autofilename")) {
|
||||||
|
addToArchiveJob->setAutoFilenameSuffix(args->getOption("autofilename"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < args->count(); ++i) {
|
||||||
|
//TODO: use the returned value here?
|
||||||
|
addToArchiveJob->addInput(args->url(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("dialog")) {
|
||||||
|
if (!addToArchiveJob->showAddDialog()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addToArchiveJob->start();
|
||||||
|
} else if (args->isSet("batch")) {
|
||||||
|
BatchExtract *batchJob = new BatchExtract;
|
||||||
|
application.connect(batchJob, SIGNAL(result(KJob*)), SLOT(quit()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
for (int i = 0; i < args->count(); ++i) {
|
||||||
|
batchJob->addInput(args->url(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("autosubfolder")) {
|
||||||
|
kDebug() << "Setting autosubfolder";
|
||||||
|
batchJob->setAutoSubfolder(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("autodestination")) {
|
||||||
|
QString autopath = QFileInfo(args->url(0).path()).path();
|
||||||
|
kDebug() << "By autodestination, setting path to " << autopath;
|
||||||
|
batchJob->setDestinationFolder(autopath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("destination")) {
|
||||||
|
kDebug() << "Setting destination to " << args->getOption("destination");
|
||||||
|
batchJob->setDestinationFolder(args->getOption("destination"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->isSet("dialog")) {
|
||||||
|
if (!batchJob->showExtractDialog()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
batchJob->start();
|
||||||
|
} else {
|
||||||
|
MainWindow *window = new MainWindow;
|
||||||
|
if (!window->loadPart()) { // if loading the part fails
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args->count()) {
|
||||||
|
kDebug() << "trying to open" << args->url(0);
|
||||||
|
|
||||||
|
if (args->isSet("dialog")) {
|
||||||
|
window->setShowExtractDialog(true);
|
||||||
|
}
|
||||||
|
window->openUrl(args->url(0));
|
||||||
|
}
|
||||||
|
window->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Entering application loop";
|
||||||
|
return application.exec();
|
||||||
|
}
|
259
ark/app/mainwindow.cpp
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2003: Georg Robbers <Georg.Robbers@urz.uni-hd.de>
|
||||||
|
* Copyright (C) 2003: Helio Chissini de Castro <helio@conectiva.com>
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 "mainwindow.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "part/interface.h"
|
||||||
|
|
||||||
|
#include <KPluginLoader>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KApplication>
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KActionCollection>
|
||||||
|
#include <KStandardAction>
|
||||||
|
#include <KFileDialog>
|
||||||
|
#include <KRecentFilesAction>
|
||||||
|
#include <KGlobal>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KEditToolBar>
|
||||||
|
#include <KShortcutsDialog>
|
||||||
|
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QDragMoveEvent>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
|
||||||
|
static bool isValidArchiveDrag(const QMimeData *data)
|
||||||
|
{
|
||||||
|
return ((data->hasUrls()) && (data->urls().count() == 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *)
|
||||||
|
: KParts::MainWindow()
|
||||||
|
{
|
||||||
|
setXMLFile(QLatin1String( "arkui.rc" ));
|
||||||
|
|
||||||
|
setupActions();
|
||||||
|
statusBar();
|
||||||
|
|
||||||
|
if (!initialGeometrySet()) {
|
||||||
|
resize(640, 480);
|
||||||
|
}
|
||||||
|
setAutoSaveSettings(QLatin1String( "MainWindow" ));
|
||||||
|
|
||||||
|
setAcceptDrops(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
if (m_recentFilesAction) {
|
||||||
|
m_recentFilesAction->saveEntries(KGlobal::config()->group("Recent Files"));
|
||||||
|
}
|
||||||
|
delete m_part;
|
||||||
|
m_part = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::dragEnterEvent(QDragEnterEvent * event)
|
||||||
|
{
|
||||||
|
kDebug() << event;
|
||||||
|
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
if (iface->isBusy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event->source() == NULL) &&
|
||||||
|
(isValidArchiveDrag(event->mimeData()))) {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::dropEvent(QDropEvent * event)
|
||||||
|
{
|
||||||
|
kDebug() << event;
|
||||||
|
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
if (iface->isBusy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event->source() == NULL) &&
|
||||||
|
(isValidArchiveDrag(event->mimeData()))) {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: if this call provokes a message box the drag will still be going
|
||||||
|
//while the box is onscreen. looks buggy, do something about it
|
||||||
|
openUrl(event->mimeData()->urls().at(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::dragMoveEvent(QDragMoveEvent * event)
|
||||||
|
{
|
||||||
|
kDebug() << event;
|
||||||
|
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
if (iface->isBusy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((event->source() == NULL) &&
|
||||||
|
(isValidArchiveDrag(event->mimeData()))) {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::loadPart()
|
||||||
|
{
|
||||||
|
KPluginLoader loader(QLatin1String( "arkpart" ));
|
||||||
|
KPluginFactory *factory = loader.factory();
|
||||||
|
if (factory) {
|
||||||
|
m_part = static_cast<KParts::ReadWritePart*>(factory->create<KParts::ReadWritePart>(this));
|
||||||
|
}
|
||||||
|
if (!factory || !m_part) {
|
||||||
|
KMessageBox::error(this, i18n("Unable to find Ark's KPart component, please check your installation."));
|
||||||
|
kWarning() << "Error loading Ark KPart: " << loader.errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_part->setObjectName( QLatin1String("ArkPart" ));
|
||||||
|
setCentralWidget(m_part->widget());
|
||||||
|
createGUI(m_part);
|
||||||
|
|
||||||
|
connect(m_part, SIGNAL(busy()), this, SLOT(updateActions()));
|
||||||
|
connect(m_part, SIGNAL(ready()), this, SLOT(updateActions()));
|
||||||
|
connect(m_part, SIGNAL(quit()), this, SLOT(quit()));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setupActions()
|
||||||
|
{
|
||||||
|
m_newAction = KStandardAction::openNew(this, SLOT(newArchive()), actionCollection());
|
||||||
|
m_openAction = KStandardAction::open(this, SLOT(openArchive()), actionCollection());
|
||||||
|
KStandardAction::quit(this, SLOT(quit()), actionCollection());
|
||||||
|
|
||||||
|
m_recentFilesAction = KStandardAction::openRecent(this, SLOT(openUrl(KUrl)), actionCollection());
|
||||||
|
m_recentFilesAction->setToolBarMode(KRecentFilesAction::MenuMode);
|
||||||
|
m_recentFilesAction->setToolButtonPopupMode(QToolButton::DelayedPopup);
|
||||||
|
m_recentFilesAction->setIconText(i18nc("action, to open an archive", "Open"));
|
||||||
|
m_recentFilesAction->setStatusTip(i18n("Click to open an archive, click and hold to open a recently-opened archive"));
|
||||||
|
m_recentFilesAction->setToolTip(i18n("Open an archive"));
|
||||||
|
m_recentFilesAction->loadEntries(KGlobal::config()->group("Recent Files"));
|
||||||
|
connect(m_recentFilesAction, SIGNAL(triggered()),
|
||||||
|
this, SLOT(openArchive()));
|
||||||
|
|
||||||
|
createStandardStatusBarAction();
|
||||||
|
|
||||||
|
KStandardAction::configureToolbars(this, SLOT(editToolbars()), actionCollection());
|
||||||
|
KStandardAction::keyBindings(this, SLOT(editKeyBindings()), actionCollection());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateActions()
|
||||||
|
{
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
m_newAction->setEnabled(!iface->isBusy());
|
||||||
|
m_openAction->setEnabled(!iface->isBusy());
|
||||||
|
m_recentFilesAction->setEnabled(!iface->isBusy());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editKeyBindings()
|
||||||
|
{
|
||||||
|
KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this);
|
||||||
|
dlg.addCollection(actionCollection());
|
||||||
|
dlg.addCollection(m_part->actionCollection());
|
||||||
|
|
||||||
|
dlg.configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editToolbars()
|
||||||
|
{
|
||||||
|
saveMainWindowSettings(KGlobal::config()->group(QLatin1String("MainWindow")));
|
||||||
|
|
||||||
|
QWeakPointer<KEditToolBar> dlg = new KEditToolBar(factory(), this);
|
||||||
|
dlg.data()->exec();
|
||||||
|
|
||||||
|
createGUI(m_part);
|
||||||
|
|
||||||
|
applyMainWindowSettings(KGlobal::config()->group(QLatin1String("MainWindow")));
|
||||||
|
|
||||||
|
delete dlg.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::openArchive()
|
||||||
|
{
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
Q_ASSERT(iface);
|
||||||
|
const KUrl url = KFileDialog::getOpenUrl(KUrl("kfiledialog:///ArkOpenDir"),
|
||||||
|
Kerfuffle::supportedMimeTypes().join( QLatin1String( " " )),
|
||||||
|
this);
|
||||||
|
openUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::openUrl(const KUrl& url)
|
||||||
|
{
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
m_part->setArguments(m_openArgs);
|
||||||
|
|
||||||
|
if (m_part->openUrl(url)) {
|
||||||
|
m_recentFilesAction->addUrl(url);
|
||||||
|
} else {
|
||||||
|
m_recentFilesAction->removeUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setShowExtractDialog(bool option)
|
||||||
|
{
|
||||||
|
if (option) {
|
||||||
|
m_openArgs.metaData()[QLatin1String( "showExtractDialog" )] = QLatin1String( "true" );
|
||||||
|
} else {
|
||||||
|
m_openArgs.metaData().remove(QLatin1String( "showExtractDialog" ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::quit()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::newArchive()
|
||||||
|
{
|
||||||
|
Interface *iface = qobject_cast<Interface*>(m_part);
|
||||||
|
Q_ASSERT(iface);
|
||||||
|
|
||||||
|
const QStringList mimeTypes = Kerfuffle::supportedWriteMimeTypes();
|
||||||
|
|
||||||
|
kDebug() << "Supported mimetypes are" << mimeTypes.join( QLatin1String( " " ));
|
||||||
|
|
||||||
|
const KUrl saveFileUrl =
|
||||||
|
KFileDialog::getSaveUrl(KUrl("kfiledialog:///ArkNewDir"),
|
||||||
|
mimeTypes.join(QLatin1String(" ")));
|
||||||
|
|
||||||
|
m_openArgs.metaData()[QLatin1String( "createNewArchive" )] = QLatin1String( "true" );
|
||||||
|
|
||||||
|
openUrl(saveFileUrl);
|
||||||
|
|
||||||
|
m_openArgs.metaData().remove(QLatin1String( "showExtractDialog" ));
|
||||||
|
m_openArgs.metaData().remove(QLatin1String( "createNewArchive" ));
|
||||||
|
}
|
66
ark/app/mainwindow.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <KParts/MainWindow>
|
||||||
|
#include <KParts/ReadWritePart>
|
||||||
|
#include <KUrl>
|
||||||
|
|
||||||
|
class KRecentFilesAction;
|
||||||
|
|
||||||
|
class MainWindow: public KParts::MainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
bool loadPart();
|
||||||
|
|
||||||
|
void dragEnterEvent(class QDragEnterEvent * event);
|
||||||
|
void dropEvent(class QDropEvent * event);
|
||||||
|
void dragMoveEvent(class QDragMoveEvent * event);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void openUrl(const KUrl& url);
|
||||||
|
void setShowExtractDialog(bool);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateActions();
|
||||||
|
void newArchive();
|
||||||
|
void openArchive();
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
void editKeyBindings();
|
||||||
|
void editToolbars();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupActions();
|
||||||
|
|
||||||
|
KParts::ReadWritePart *m_part;
|
||||||
|
KRecentFilesAction *m_recentFilesAction;
|
||||||
|
QAction *m_openAction;
|
||||||
|
QAction *m_newAction;
|
||||||
|
KParts::OpenUrlArguments m_openArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
22
ark/cmake/modules/COPYING-CMAKE-SCRIPTS
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
46
ark/cmake/modules/FindLibArchive.cmake
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# - Try to find libarchive
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# LIBARCHIVE_FOUND - system has libarchive
|
||||||
|
# LIBARCHIVE_INCLUDE_DIR - the libarchive include directory
|
||||||
|
# LIBARCHIVE_LIBRARY - Link this to use libarchive
|
||||||
|
# HAVE_LIBARCHIVE_GZIP_SUPPORT - whether libarchive has been compiled with gzip support
|
||||||
|
# HAVE_LIBARCHIVE_LZMA_SUPPORT - whether libarchive has been compiled with lzma support
|
||||||
|
# HAVE_LIBARCHIVE_XZ_SUPPORT - whether libarchive has been compiled with xz support
|
||||||
|
# HAVE_LIBARCHIVE_RPM_SUPPORT - whether libarchive has been compiled with rpm support
|
||||||
|
# HAVE_LIBARCHIVE_CAB_SUPPORT - whether libarchive has been compiled with cab support
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006, Pino Toscano, <toscano.pino@tiscali.it>
|
||||||
|
#
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
|
||||||
|
if (LIBARCHIVE_LIBRARY AND LIBARCHIVE_INCLUDE_DIR)
|
||||||
|
# in cache already
|
||||||
|
set(LIBARCHIVE_FOUND TRUE)
|
||||||
|
else (LIBARCHIVE_LIBRARY AND LIBARCHIVE_INCLUDE_DIR)
|
||||||
|
find_path(LIBARCHIVE_INCLUDE_DIR archive.h
|
||||||
|
${GNUWIN32_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(LIBARCHIVE_LIBRARY NAMES archive libarchive archive2 libarchive2
|
||||||
|
PATHS
|
||||||
|
${GNUWIN32_DIR}/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if (LIBARCHIVE_LIBRARY)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_write_set_compression_gzip "" HAVE_LIBARCHIVE_GZIP_SUPPORT)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_write_set_compression_lzma "" HAVE_LIBARCHIVE_LZMA_SUPPORT)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_write_set_compression_xz "" HAVE_LIBARCHIVE_XZ_SUPPORT)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_read_support_compression_rpm "" HAVE_LIBARCHIVE_RPM_SUPPORT)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_read_disk_entry_from_file "" HAVE_LIBARCHIVE_READ_DISK_API)
|
||||||
|
check_library_exists(${LIBARCHIVE_LIBRARY} archive_read_support_format_cab "" HAVE_LIBARCHIVE_CAB_SUPPORT)
|
||||||
|
endif (LIBARCHIVE_LIBRARY)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(LibArchive DEFAULT_MSG LIBARCHIVE_INCLUDE_DIR LIBARCHIVE_LIBRARY HAVE_LIBARCHIVE_GZIP_SUPPORT)
|
||||||
|
|
||||||
|
mark_as_advanced(LIBARCHIVE_INCLUDE_DIR LIBARCHIVE_LIBRARY HAVE_LIBARCHIVE_GZIP_SUPPORT HAVE_LIBARCHIVE_LZMA_SUPPORT HAVE_LIBARCHIVE_RPM_SUPPORT HAVE_LIBARCHIVE_CAB_SUPPORT)
|
||||||
|
endif (LIBARCHIVE_LIBRARY AND LIBARCHIVE_INCLUDE_DIR)
|
2
ark/config.h.cmake
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#cmakedefine HAVE_LIBARCHIVE_LZMA_SUPPORT ${HAVE_LIBARCHIVE_LZMA_SUPPORT}
|
||||||
|
#cmakedefine HAVE_LIBARCHIVE_XZ_SUPPORT ${HAVE_LIBARCHIVE_XZ_SUPPORT}
|
5
ark/doc/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
########### install files ###############
|
||||||
|
#
|
||||||
|
kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR ark)
|
||||||
|
kde4_create_manpage(man-ark.1.docbook 1 INSTALL_DESTINATION ${MAN_INSTALL_DIR})
|
||||||
|
|
BIN
ark/doc/ark-mainwindow.png
Normal file
After Width: | Height: | Size: 53 KiB |
336
ark/doc/index.docbook
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
|
||||||
|
<!ENTITY kappname "&ark;">
|
||||||
|
<!ENTITY package "kdeutils">
|
||||||
|
<!ENTITY % addindex "IGNORE">
|
||||||
|
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
|
||||||
|
]>
|
||||||
|
|
||||||
|
<book id="ark" lang="&language;">
|
||||||
|
|
||||||
|
<bookinfo>
|
||||||
|
<title>The &ark; Handbook</title>
|
||||||
|
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
&Matt.Johnston; &Matt.Johnston.mail;
|
||||||
|
</author>
|
||||||
|
|
||||||
|
<!-- TRANS:ROLES_OF_TRANSLATORS -->
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2000</year>
|
||||||
|
<holder>&Matt.Johnston;</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
<year>2004</year>
|
||||||
|
<holder>Henrique Pinto</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
|
||||||
|
<legalnotice>&FDLNotice;</legalnotice>
|
||||||
|
|
||||||
|
<date>2013-06-21</date>
|
||||||
|
<releaseinfo>2.19 &kde; (4.11)</releaseinfo>
|
||||||
|
|
||||||
|
<abstract>
|
||||||
|
<para>&ark; is an archive manager for &kde;.</para></abstract>
|
||||||
|
|
||||||
|
<keywordset>
|
||||||
|
<keyword>KDE</keyword>
|
||||||
|
<keyword>gzip</keyword>
|
||||||
|
<keyword>gunzip</keyword>
|
||||||
|
<keyword>tar</keyword>
|
||||||
|
<keyword>archive</keyword>
|
||||||
|
<keyword>zip</keyword>
|
||||||
|
<keyword>compression</keyword>
|
||||||
|
<keyword>7z</keyword>
|
||||||
|
<keyword>kdeutils</keyword>
|
||||||
|
<keyword>ark</keyword>
|
||||||
|
</keywordset>
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<chapter id="introduction">
|
||||||
|
<title>Introduction</title>
|
||||||
|
|
||||||
|
<para>&ark; is a program for viewing, extracting, creating and modifying
|
||||||
|
archives.
|
||||||
|
&ark; can handle various archive formats such as
|
||||||
|
<command>tar</command>, <command>gzip</command>,
|
||||||
|
<command>bzip2</command>, <command>zip</command>, <command>rar</command>,
|
||||||
|
<command>7zip</command>, <command>xz</command>, <command>rpm</command>,
|
||||||
|
<command>cab</command> and <command>deb</command> (support for certain archive formats depend on
|
||||||
|
the appropriate command-line programs being installed).</para>
|
||||||
|
|
||||||
|
<screenshot>
|
||||||
|
<screeninfo>&ark;'s main window</screeninfo>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="ark-mainwindow.png" format="PNG"/>
|
||||||
|
</imageobject>
|
||||||
|
<textobject>
|
||||||
|
<phrase>&ark;'s main window</phrase>
|
||||||
|
</textobject>
|
||||||
|
</mediaobject>
|
||||||
|
</screenshot>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="using-ark">
|
||||||
|
<title>Using &ark;</title>
|
||||||
|
|
||||||
|
<sect1 id="ark-open">
|
||||||
|
<title>Opening Archives</title>
|
||||||
|
|
||||||
|
<para>To open an archive in &ark;, choose
|
||||||
|
<guimenuitem>Open...</guimenuitem> (<keycombo
|
||||||
|
action="simul">&Ctrl;<keycap>O</keycap></keycombo>) from the <guimenu>File</guimenu>
|
||||||
|
menu. You can also open archive files by dragging and dropping from
|
||||||
|
&konqueror; or &dolphin;. Archive files should be associated with &ark;, so you can
|
||||||
|
also <mousebutton>right</mousebutton> click a file in &konqueror; or &dolphin; and
|
||||||
|
select <guimenuitem>Open with &ark;</guimenuitem> to open it or select an extract action for this file.</para>
|
||||||
|
|
||||||
|
<para>If you have enabled the information panel in the <guimenu>Settings</guimenu> menu
|
||||||
|
additional information about the selected folders or files in the archive is displayed.</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="ark-work-files">
|
||||||
|
<title>Working with Files</title>
|
||||||
|
|
||||||
|
<para>Once an archive has been opened, you can perform various
|
||||||
|
operations on the files inside the archive. By
|
||||||
|
selecting a file and using the <guimenu>Action</guimenu>
|
||||||
|
menu, you can choose what you want to do:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Add File...</guimenuitem> will add files from your disk to the archive.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Add Folder...</guimenuitem> will add folders from your disk to the archive.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Delete</guimenuitem> (<keycap>Del</keycap>) will remove the currently
|
||||||
|
selected file(s) from the archive.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Extract...</guimenuitem> (<keycombo
|
||||||
|
action="simul">&Ctrl;<keycap>E</keycap></keycombo>) opens a submenu with previously accessed folders,
|
||||||
|
and you can select to quick extract into any of them.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Preview</guimenuitem> will open the file in the associated viewer for that file type.</para>
|
||||||
|
<!-- File Associations Embedding first item in Service Preference Order for a file type-->
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
<sect1 id="ark-extract">
|
||||||
|
<title>Extracting Archives and Removing Files</title>
|
||||||
|
|
||||||
|
<para>Once an archive has been opened in &ark;, it can be extracted. To
|
||||||
|
quick extract files from an archive, you can select
|
||||||
|
<guisubmenu>Extract</guisubmenu> from the
|
||||||
|
<guimenu>Action</guimenu> menu. This opens a submenu with previously accessed folders,
|
||||||
|
and you can select to quick extract into any of them. Clicking on the check mark at
|
||||||
|
the right side of the <guibutton>Extract</guibutton> button in the toolbar performes the same action.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To open the <guilabel>Extract</guilabel> dialog click the <guibutton>Extract</guibutton>
|
||||||
|
button in the toolbar or use the shortcut <keycombo action="simul">&Ctrl;
|
||||||
|
<keycap>E</keycap></keycombo>.
|
||||||
|
|
||||||
|
This dialog allows you to select where you will extract files to. The default
|
||||||
|
location is the folder the archive is in.</para>
|
||||||
|
<para>You can specify to extract the files into a subfolder. The default name of this
|
||||||
|
subfolder is the first part of the archive name, but you can edit it to your needs.
|
||||||
|
If you want to preserve paths when extracting, select this option.
|
||||||
|
You may also choose to open the destination folder
|
||||||
|
in &konqueror; or &dolphin; or close &ark; once the extraction is complete.</para>
|
||||||
|
|
||||||
|
<para>If a file in the archive list is highlighted, you can
|
||||||
|
also select which files to extract:</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Selected files only</guimenuitem> extracts only the files
|
||||||
|
which have been selected.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>All files</guimenuitem> extracts the entire contents of the
|
||||||
|
archive.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>To extract a single file from an archive, click on the filename and drag it to the
|
||||||
|
target folder
|
||||||
|
</para>
|
||||||
|
<!--FIXME extract several files by drag + drop? - only in basyskom branch-->
|
||||||
|
<para>Extracting files from an archive does not change the archive and its contents.
|
||||||
|
Use <menuchoice><guimenu>Action</guimenu><guimenuitem>Delete</guimenuitem></menuchoice>
|
||||||
|
(<keysym>Del</keysym>) for this task.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="ark-create">
|
||||||
|
<title>Creating Archives and Adding Files</title>
|
||||||
|
|
||||||
|
<para>To create a new archive in &ark;, choose
|
||||||
|
<guimenuitem>New</guimenuitem> from the <guimenu>File</guimenu>
|
||||||
|
menu.</para>
|
||||||
|
|
||||||
|
<para>You can then type the name of the archive, with the appropriate
|
||||||
|
extension (<literal role="extension">tar.gz</literal>, <literal
|
||||||
|
role="extension">zip</literal>, <literal role="extension">bz2</literal>
|
||||||
|
&etc;) or select a supported format in the <guilabel>Filter</guilabel> combo box
|
||||||
|
and check the <guilabel>Automatically select filename extension</guilabel> option.
|
||||||
|
To add files to the archive, choose <guimenuitem>Add
|
||||||
|
File...</guimenuitem> from the <guimenu>Action</guimenu> menu. If you
|
||||||
|
want to add an entire folder to an archive, choose <guimenuitem>Add
|
||||||
|
Folder...</guimenuitem> from the <guimenu>Action</guimenu> menu.</para>
|
||||||
|
|
||||||
|
<para>An alternative way to add files to the archive is to drag one or more files
|
||||||
|
from &konqueror;, &dolphin; or the desktop into the main &ark; window, and it will
|
||||||
|
be added to the current archive.</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="ark-in_filemanager">
|
||||||
|
<title>Using &ark; in the Filemanager</title>
|
||||||
|
|
||||||
|
<para>Clicking with the &RMB; on an archive in a filemanager like &dolphin; or &konqueror;
|
||||||
|
displays a context menu with an item <guimenuitem>Open with Ark</guimenuitem>.
|
||||||
|
The menu has these additional items to extract an archive using &ark;:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Extract Archive Here, Autodetect Subfolder</guimenuitem> creates a
|
||||||
|
subfolder in the folder with the archive and extracts the folders and files into it.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Extract Archive To...</guimenuitem> works like in &ark;.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Extract Archive Here</guimenuitem> extracts the content of the archive into same folder.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
&dolphin;'s or &konqueror;'s context menu for a selection displays these actions in the
|
||||||
|
<guimenu>Compress</guimenu> submenu:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Here</guimenuitem> creates a Tar archive (gzip-compressed) in the current folder
|
||||||
|
with the extension <filename class="extension">.tar.gz</filename>.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>As ZIP Archive</guimenuitem>, <guimenuitem>As RAR Archive</guimenuitem>
|
||||||
|
or <guimenuitem>As ZIP/TAR Archive</guimenuitem> creates these archive types in the current folder.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para><guimenuitem>Compress To...</guimenuitem> opens a dialog where you can select folder, name and archive type.</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="batchmode">
|
||||||
|
<title>Advanced Batch Mode</title>
|
||||||
|
<para>&ark; has an advanced batch mode to manage archives without launching a &GUI; interface.
|
||||||
|
This mode allows you to extract or create archives and add files to them.</para>
|
||||||
|
|
||||||
|
<para>The batch mode is documented in <ulink url="man:/ark">&ark;'s man page</ulink>.
|
||||||
|
</para>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="credits">
|
||||||
|
|
||||||
|
<title>Credits and License</title>
|
||||||
|
|
||||||
|
<para>&ark; is Copyright © 1997-2008, The Various &ark; Developers</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<title>Authors:</title>
|
||||||
|
<listitem><para>Raphael Kubo da Costa
|
||||||
|
<email>rakuco@FreeBSD.org</email></para></listitem>
|
||||||
|
<listitem><para>Harald Hvaal
|
||||||
|
<email>haraldhv@stud.ntnu.no</email></para></listitem>
|
||||||
|
<listitem><para>Helio Chissini de Castro
|
||||||
|
<email>helio@conectiva.com.br</email></para></listitem>
|
||||||
|
<listitem><para>Georg Robbers
|
||||||
|
<email>Georg.Robbers@urz.uni-hd.de</email></para></listitem>
|
||||||
|
<listitem><para>Henrique Pinto
|
||||||
|
<email>henrique.pinto@kdemail.net</email></para></listitem>
|
||||||
|
<listitem><para>Roberto Selbach Teixeira
|
||||||
|
<email>maragato@kde.org</email></para></listitem>
|
||||||
|
<listitem><para>Robert Palmbos
|
||||||
|
<email>palm9744@kettering.edu</email></para></listitem>
|
||||||
|
<listitem><para>Francois-Xavier Duranceau
|
||||||
|
<email>duranceau@kde.org</email></para></listitem>
|
||||||
|
<listitem><para>Corel Corporation (author: Emily Ezust)
|
||||||
|
<email>emilye@corel.com</email></para></listitem>
|
||||||
|
<listitem><para>Corel Corporation (author: Michael Jarrett)
|
||||||
|
<email>michaelj@corel.com</email></para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>Documentation Copyright © 2000 &Matt.Johnston;
|
||||||
|
&Matt.Johnston.mail;</para>
|
||||||
|
|
||||||
|
<para>Documentation updated for &kde; 3.3 by Henrique Pinto
|
||||||
|
<email>henrique.pinto@kdemail.net</email>.</para>
|
||||||
|
|
||||||
|
<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
|
||||||
|
&underFDL;
|
||||||
|
&underGPL;
|
||||||
|
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<appendix id="installation">
|
||||||
|
<title>Installation</title>
|
||||||
|
|
||||||
|
<sect1 id="getting-ark">
|
||||||
|
<title>How to obtain &ark;</title>
|
||||||
|
|
||||||
|
&install.intro.documentation;
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="requirements">
|
||||||
|
<title>Requirements</title>
|
||||||
|
|
||||||
|
<para>In order to successfully use &ark;, you need &kde;
|
||||||
|
4. &GNU; <command>tar</command> and a recent
|
||||||
|
<command>gzip</command> are also needed if you want &ark; to handle tar archives. To handle other
|
||||||
|
file formats, you need the appropriate command line programs, such as <command>bzip2</command>,
|
||||||
|
<command>zip</command>, <command>unzip</command>, <command>ar</command>, <command>rar</command>,
|
||||||
|
<command>7zip</command>, <command>xz</command>, <command>rpm</command>,
|
||||||
|
<command>cab</command> and <command>deb</command>.</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="compilation">
|
||||||
|
<title>Compilation and Installation</title>
|
||||||
|
|
||||||
|
&install.compile.documentation;
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
</appendix>
|
||||||
|
|
||||||
|
&documentation.index;
|
||||||
|
</book>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Local Variables:
|
||||||
|
mode: sgml
|
||||||
|
sgml-minimize-attributes: nil
|
||||||
|
sgml-general-insert-case: lower
|
||||||
|
End:
|
||||||
|
-->
|
||||||
|
|
208
ark/doc/man-ark.1.docbook
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
|
||||||
|
<!ENTITY kappname "&ark;">
|
||||||
|
<!ENTITY % English "INCLUDE">
|
||||||
|
]>
|
||||||
|
|
||||||
|
<refentry lang="&language;">
|
||||||
|
<refentryinfo>
|
||||||
|
<title>&kde; User's Manual</title>
|
||||||
|
<author><firstname>Lauri</firstname><surname>Watts</surname> <contrib>Initial version of &ark; man page.</contrib></author>
|
||||||
|
|
||||||
|
<author><firstname>Raphael</firstname><surname>Kubo da Costa</surname> <contrib>Update &ark; man page.</contrib></author>
|
||||||
|
|
||||||
|
<date>2013-08-23</date>
|
||||||
|
<releaseinfo>2.19 (&kde; 4.11)</releaseinfo>
|
||||||
|
<productname>K Desktop Environment</productname>
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle><command>ark</command></refentrytitle>
|
||||||
|
<manvolnum>1</manvolnum>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname><command>ark</command></refname>
|
||||||
|
<refpurpose>&kde; archiving tool</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>ark</command>
|
||||||
|
<group choice="opt"><option>-b</option></group>
|
||||||
|
<group choice="opt"><option>-a</option></group>
|
||||||
|
<group choice="opt"><option>-e</option></group>
|
||||||
|
<group choice="opt"><option>-c</option></group>
|
||||||
|
<group choice="opt"><option>-f</option> <replaceable>
|
||||||
|
suffix</replaceable></group>
|
||||||
|
<group choice="opt"><option>-p</option></group>
|
||||||
|
<group choice="opt"><option>-t</option> <replaceable>
|
||||||
|
file</replaceable></group>
|
||||||
|
<group choice="opt"><option>-d</option></group>
|
||||||
|
<group choice="opt"><option>-o</option> <replaceable>
|
||||||
|
directory</replaceable></group>
|
||||||
|
<arg choice="opt">&kde; Generic Options</arg>
|
||||||
|
<arg choice="opt">&Qt; Generic Options</arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
<para>&ark; is a program for managing various compressed file formats
|
||||||
|
within &kde;. Archives can be viewed, extracted, created
|
||||||
|
and modified with &ark;. The program can handle various
|
||||||
|
formats such as <application>tar</application>,
|
||||||
|
<application>gzip</application>, <application>bzip2</application>,
|
||||||
|
<application>zip</application>, <application>rar</application>
|
||||||
|
(when the appropriate libraries or command-line programs are
|
||||||
|
installed).</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Operation modes</title>
|
||||||
|
<para>&ark; can be used either as a stand-alone &GUI; program as well as a
|
||||||
|
command-line program in order to perform some specific tasks.</para>
|
||||||
|
<para>If invoked without the -b (--batch) or -c (--add) options, &ark; is started
|
||||||
|
as a normal &GUI; program.</para>
|
||||||
|
<para>When the -b (--batch) option is used, &ark; can be used to extract the
|
||||||
|
contents of one or more files directly from the command-line, without
|
||||||
|
launching its &GUI;.</para>
|
||||||
|
<para>When the -c (--add) option is used, &ark; prompts for files that should
|
||||||
|
be added to a new archive or to an existing archive.</para>
|
||||||
|
<para></para>
|
||||||
|
<para></para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Options</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-d, --dialog</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Show a dialog for specifying the options for a batch or add operation.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-o, --destination
|
||||||
|
<replaceable>directory</replaceable></option></term>
|
||||||
|
<listitem><para>Default the extraction directory to <replaceable>directory</replaceable>.
|
||||||
|
If not passed, the current path is used.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>Options for adding files</title>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-c, --add</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Query the user for an archive filename and add specified files to it.
|
||||||
|
Quit when finished.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-t, --add-to <replaceable>filename</replaceable></option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Add the specified files to <replaceable>filename</replaceable>. Create archive
|
||||||
|
if it does not exist. Quit when finished.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-p, --changetofirstpath</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Change the current directory to the first entry and add all other entries relative
|
||||||
|
to this one.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-f, --autofilename <replaceable>suffix</replaceable></option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Automatically choose a filename, with the selected <replaceable>suffix</replaceable>
|
||||||
|
(for example rar, tar.gz, zip or any other supported types).</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>Options for batch extraction</title>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-b, --batch</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Use the batch interface instead of the usual dialog. This option is implied
|
||||||
|
if more than one url is specified.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-e, --autodestination</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>The destination argument will be set to the path of the first file
|
||||||
|
supplied.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-a, --autosubfolder</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Archive contents will be read, and if detected to not be a single folder archive,
|
||||||
|
a subfolder by the name of the archive will be created.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Examples</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><userinput><command>ark</command> <option>--batch</option>
|
||||||
|
<replaceable>archive.tar.bz2</replaceable></userinput></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Will extract <replaceable>archive.tar.bz2</replaceable> into the current directory
|
||||||
|
without showing any &GUI;.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><userinput><command>ark</command> <option>-b</option> <option>-d</option>
|
||||||
|
<replaceable>archive.tar.bz2</replaceable> <replaceable>archive2.zip</replaceable></userinput></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Will first show an extraction options dialog and then extract both
|
||||||
|
<replaceable>archive.tar.bz2</replaceable> and <replaceable>archive2.zip</replaceable>
|
||||||
|
into the directory chosen in the dialog.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><userinput><command>ark</command> <option>--add-to</option>
|
||||||
|
<replaceable>my-archive.zip</replaceable> <replaceable>photo1.jpg</replaceable>
|
||||||
|
<replaceable>text.txt</replaceable></userinput></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Will create <replaceable>my-archive.zip</replaceable> if does not exist and
|
||||||
|
then add <replaceable>photo1.jpg</replaceable> and <replaceable>text.txt</replaceable> to it.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Authors</title>
|
||||||
|
<para>&ark; is currently maintained by &Harald.Hvaal; &Harald.Hvaal.mail;
|
||||||
|
and &Raphael.Kubo.da.Costa; &Raphael.Kubo.da.Costa.mail;.</para>
|
||||||
|
<para>This man page was first written by &Lauri.Watts;
|
||||||
|
&Lauri.Watts.mail; in 2005 for &kde; 3.4, and was later updated in 2009 by
|
||||||
|
&Raphael.Kubo.da.Costa; &Raphael.Kubo.da.Costa.mail;.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry>
|
50
ark/kerfuffle/CMakeLists.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
macro_optional_find_package(QJSON)
|
||||||
|
macro_log_feature(QJSON_FOUND "qjson" "A library for processing and serializing JSON files" "http://qjson.sourceforge.net" FALSE "" "Required for compiling Ark's unit tests")
|
||||||
|
|
||||||
|
########### next target ###############
|
||||||
|
|
||||||
|
set(kerfuffle_SRCS
|
||||||
|
archive.cpp
|
||||||
|
archiveinterface.cpp
|
||||||
|
jobs.cpp
|
||||||
|
extractiondialog.cpp
|
||||||
|
adddialog.cpp
|
||||||
|
queries.cpp
|
||||||
|
addtoarchive.cpp
|
||||||
|
cliinterface.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
kde4_add_kcfg_files(kerfuffle_SRCS settings.kcfgc)
|
||||||
|
|
||||||
|
kde4_add_ui_files(kerfuffle_SRCS extractiondialog.ui adddialog.ui )
|
||||||
|
|
||||||
|
kde4_add_library(kerfuffle SHARED ${kerfuffle_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(kerfuffle ${KDE4_KFILE_LIBS} ${KDE4_KPARTS_LIBS})
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(kerfuffle ${KDE4_KPTY_LIBS})
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|
||||||
|
set_target_properties(kerfuffle PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION})
|
||||||
|
|
||||||
|
install(TARGETS kerfuffle ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||||
|
|
||||||
|
install(FILES kerfufflePlugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR})
|
||||||
|
install(FILES ark.kcfg DESTINATION ${KCFG_INSTALL_DIR})
|
||||||
|
|
||||||
|
if (QJSON_FOUND)
|
||||||
|
# This is a hack to make QJSON work with both 0.7.1 (the latest stable)
|
||||||
|
# and the current master (b440550), which uses a different casing for
|
||||||
|
# the CMake variables.
|
||||||
|
# It should be removed when QJSON master becomes sane and reverts the
|
||||||
|
# casing again.
|
||||||
|
if (QJSON_LIBRARIES AND QJSON_INCLUDE_DIR)
|
||||||
|
set(KERFUFFLE_QJSON_LIBRARIES "${QJSON_LIBRARIES}")
|
||||||
|
set(KERFUFFLE_QJSON_INCLUDE_DIR "${QJSON_INCLUDE_DIR}")
|
||||||
|
else (QJSON_LIBRARIES AND QJSON_INCLUDE_DIR)
|
||||||
|
set(KERFUFFLE_QJSON_LIBRARIES "${qjson_LIBRARIES}")
|
||||||
|
set(KERFUFFLE_QJSON_INCLUDE_DIR "${qjson_INCLUDE_DIR}")
|
||||||
|
endif (QJSON_LIBRARIES AND QJSON_INCLUDE_DIR)
|
||||||
|
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif (QJSON_FOUND)
|
135
ark/kerfuffle/adddialog.cpp
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009,2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "adddialog.h"
|
||||||
|
#include "ui_adddialog.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KFilePlacesModel>
|
||||||
|
#include <KGlobal>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class AddDialogUI: public QWidget, public Ui::AddDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddDialogUI(QWidget *parent = 0)
|
||||||
|
: QWidget(parent) {
|
||||||
|
setupUi(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AddDialog::AddDialog(const QStringList& itemsToAdd,
|
||||||
|
const KUrl & startDir,
|
||||||
|
const QString & filter,
|
||||||
|
QWidget * parent,
|
||||||
|
QWidget * widget
|
||||||
|
)
|
||||||
|
: KFileDialog(startDir, filter, parent, widget)
|
||||||
|
{
|
||||||
|
setOperationMode(KFileDialog::Saving);
|
||||||
|
setMode(KFile::File | KFile::LocalOnly);
|
||||||
|
setConfirmOverwrite(true);
|
||||||
|
setCaption(i18n("Compress to Archive"));
|
||||||
|
|
||||||
|
loadConfiguration();
|
||||||
|
|
||||||
|
connect(this, SIGNAL(okClicked()), SLOT(updateDefaultMimeType()));
|
||||||
|
|
||||||
|
m_ui = new AddDialogUI(this);
|
||||||
|
mainWidget()->layout()->addWidget(m_ui);
|
||||||
|
|
||||||
|
setupIconList(itemsToAdd);
|
||||||
|
|
||||||
|
// Set up a default name if there's only one file to compress
|
||||||
|
if (itemsToAdd.size() == 1) {
|
||||||
|
const QFileInfo fileInfo(itemsToAdd.first());
|
||||||
|
const QString fileName =
|
||||||
|
fileInfo.isDir() ? fileInfo.dir().dirName() : fileInfo.baseName();
|
||||||
|
|
||||||
|
// #272914: Add an extension when it is present, otherwise KFileDialog
|
||||||
|
// will not automatically add it as baseFileName is a file which
|
||||||
|
// already exists.
|
||||||
|
setSelection(fileName + currentFilterMimeType()->mainExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
//These extra options will be implemented in a 4.2+ version of
|
||||||
|
//ark
|
||||||
|
m_ui->groupExtraOptions->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddDialog::loadConfiguration()
|
||||||
|
{
|
||||||
|
m_config = KConfigGroup(KGlobal::config()->group("AddDialog"));
|
||||||
|
|
||||||
|
const QString defaultMimeType = QLatin1String( "application/x-compressed-tar" );
|
||||||
|
const QStringList writeMimeTypes = Kerfuffle::supportedWriteMimeTypes();
|
||||||
|
const QString lastMimeType = m_config.readEntry("LastMimeType", defaultMimeType);
|
||||||
|
|
||||||
|
if (writeMimeTypes.contains(lastMimeType)) {
|
||||||
|
setMimeFilter(writeMimeTypes, lastMimeType);
|
||||||
|
} else {
|
||||||
|
setMimeFilter(writeMimeTypes, defaultMimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddDialog::setupIconList(const QStringList& itemsToAdd)
|
||||||
|
{
|
||||||
|
QStandardItemModel* listModel = new QStandardItemModel(this);
|
||||||
|
QStringList sortedList(itemsToAdd);
|
||||||
|
|
||||||
|
sortedList.sort();
|
||||||
|
|
||||||
|
Q_FOREACH(const QString& urlString, sortedList) {
|
||||||
|
KUrl url(urlString);
|
||||||
|
|
||||||
|
QStandardItem* item = new QStandardItem;
|
||||||
|
item->setText(url.fileName());
|
||||||
|
|
||||||
|
QString iconName = KMimeType::iconNameForUrl(url);
|
||||||
|
item->setIcon(KIcon(iconName));
|
||||||
|
|
||||||
|
item->setData(QVariant(url), KFilePlacesModel::UrlRole);
|
||||||
|
|
||||||
|
listModel->appendRow(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ui->compressList->setModel(listModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddDialog::updateDefaultMimeType()
|
||||||
|
{
|
||||||
|
m_config.writeEntry("LastMimeType", currentMimeFilter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "adddialog.moc"
|
63
ark/kerfuffle/adddialog.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ADDDIALOG_H
|
||||||
|
#define ADDDIALOG_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KFileDialog>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class KERFUFFLE_EXPORT AddDialog : public KFileDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddDialog(const QStringList & itemsToAdd,
|
||||||
|
const KUrl & startDir,
|
||||||
|
const QString & filter,
|
||||||
|
QWidget * parent,
|
||||||
|
QWidget * widget = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class AddDialogUI *m_ui;
|
||||||
|
KConfigGroup m_config;
|
||||||
|
|
||||||
|
void loadConfiguration();
|
||||||
|
void setupIconList(const QStringList& itemsToAdd);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateDefaultMimeType();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
113
ark/kerfuffle/adddialog.ui
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
<ui version="4.0" >
|
||||||
|
<class>AddDialog</class>
|
||||||
|
<widget class="QWidget" name="AddDialog" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>565</width>
|
||||||
|
<height>113</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupCompressFiles" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title" >
|
||||||
|
<string>Files/Folders to Compress</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" >
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="compressList" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape" >
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow" >
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth" >
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers" >
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode" >
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize" >
|
||||||
|
<size>
|
||||||
|
<width>32</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="textElideMode" >
|
||||||
|
<enum>Qt::ElideMiddle</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollMode" >
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="resizeMode" >
|
||||||
|
<enum>QListView::Adjust</enum>
|
||||||
|
</property>
|
||||||
|
<property name="viewMode" >
|
||||||
|
<enum>QListView::IconMode</enum>
|
||||||
|
</property>
|
||||||
|
<property name="uniformItemSizes" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupExtraOptions" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title" >
|
||||||
|
<string>Extra Compression Options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Easter egg for the developers:
|
||||||
|
This is where future versions will have extra compression options for the various compression interfaces.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
213
ark/kerfuffle/addtoarchive.cpp
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "addtoarchive.h"
|
||||||
|
#include "adddialog.h"
|
||||||
|
#include "archive.h"
|
||||||
|
#include "jobs.h"
|
||||||
|
|
||||||
|
#include <KConfig>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kjobtrackerinterface.h>
|
||||||
|
#include <kmessagebox.h>
|
||||||
|
#include <klocale.h>
|
||||||
|
#include <kio/job.h>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
AddToArchive::AddToArchive(QObject *parent)
|
||||||
|
: KJob(parent), m_changeToFirstPath(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AddToArchive::~AddToArchive()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::setAutoFilenameSuffix(const QString& suffix)
|
||||||
|
{
|
||||||
|
m_autoFilenameSuffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::setChangeToFirstPath(bool value)
|
||||||
|
{
|
||||||
|
m_changeToFirstPath = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::setFilename(const KUrl& path)
|
||||||
|
{
|
||||||
|
m_filename = path.pathOrUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::setMimeType(const QString & mimeType)
|
||||||
|
{
|
||||||
|
m_mimeType = mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddToArchive::showAddDialog(void)
|
||||||
|
{
|
||||||
|
QWeakPointer<Kerfuffle::AddDialog> dialog = new Kerfuffle::AddDialog(
|
||||||
|
m_inputs, // itemsToAdd
|
||||||
|
KUrl(m_firstPath), // startDir
|
||||||
|
QLatin1String( "" ), // filter
|
||||||
|
NULL, // parent
|
||||||
|
NULL); // widget
|
||||||
|
|
||||||
|
bool ret = dialog.data()->exec();
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
kDebug() << "Returned URL:" << dialog.data()->selectedUrl();
|
||||||
|
kDebug() << "Returned mime:" << dialog.data()->currentMimeFilter();
|
||||||
|
setFilename(dialog.data()->selectedUrl());
|
||||||
|
setMimeType(dialog.data()->currentMimeFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete dialog.data();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddToArchive::addInput(const KUrl& url)
|
||||||
|
{
|
||||||
|
m_inputs << url.pathOrUrl(
|
||||||
|
QFileInfo(url.pathOrUrl()).isDir() ?
|
||||||
|
KUrl::AddTrailingSlash :
|
||||||
|
KUrl::RemoveTrailingSlash
|
||||||
|
);
|
||||||
|
|
||||||
|
if (m_firstPath.isEmpty()) {
|
||||||
|
QString firstEntry = url.pathOrUrl(KUrl::RemoveTrailingSlash);
|
||||||
|
m_firstPath = QFileInfo(firstEntry).dir().absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::start()
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, this, SLOT(slotStartJob()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: If this class should ever be called outside main.cpp,
|
||||||
|
// the returns should be preceded by emitResult().
|
||||||
|
void AddToArchive::slotStartJob(void)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
Kerfuffle::CompressionOptions options;
|
||||||
|
|
||||||
|
if (!m_inputs.size()) {
|
||||||
|
KMessageBox::error(NULL, i18n("No input files were given."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::Archive *archive;
|
||||||
|
if (!m_filename.isEmpty()) {
|
||||||
|
archive = Kerfuffle::Archive::create(m_filename, m_mimeType, this);
|
||||||
|
kDebug() << "Set filename to " << m_filename;
|
||||||
|
} else {
|
||||||
|
if (m_autoFilenameSuffix.isEmpty()) {
|
||||||
|
KMessageBox::error(NULL, i18n("You need to either supply a filename for the archive or a suffix (such as rar, tar.gz) with the <command>--autofilename</command> argument."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_firstPath.isEmpty()) {
|
||||||
|
kDebug() << "Weird, this should not happen. no firstpath defined. aborting";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString base = QFileInfo(m_inputs.first()).absoluteFilePath();
|
||||||
|
if (base.endsWith(QLatin1Char('/'))) {
|
||||||
|
base.chop(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString finalName = base + QLatin1Char( '.' ) + m_autoFilenameSuffix;
|
||||||
|
|
||||||
|
//if file already exists, append a number to the base until it doesn't
|
||||||
|
//exist
|
||||||
|
int appendNumber = 0;
|
||||||
|
while (QFileInfo(finalName).exists()) {
|
||||||
|
++appendNumber;
|
||||||
|
finalName = base + QLatin1Char( '_' ) + QString::number(appendNumber) + QLatin1Char( '.' ) + m_autoFilenameSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Autoset filename to "<< finalName;
|
||||||
|
archive = Kerfuffle::Archive::create(finalName, m_mimeType, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (archive == NULL) {
|
||||||
|
KMessageBox::error(NULL, i18n("Failed to create the new archive. Permissions might not be sufficient."));
|
||||||
|
return;
|
||||||
|
} else if (archive->isReadOnly()) {
|
||||||
|
KMessageBox::error(NULL, i18n("It is not possible to create archives of this type."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_changeToFirstPath) {
|
||||||
|
if (m_firstPath.isEmpty()) {
|
||||||
|
kDebug() << "Weird, this should not happen. no firstpath defined. aborting";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDir stripDir(m_firstPath);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_inputs.size(); ++i) {
|
||||||
|
m_inputs[i] = stripDir.absoluteFilePath(m_inputs.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
options[QLatin1String( "GlobalWorkDir" )] = stripDir.path();
|
||||||
|
kDebug() << "Setting GlobalWorkDir to " << stripDir.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::AddJob *job =
|
||||||
|
archive->addFiles(m_inputs, options);
|
||||||
|
|
||||||
|
KIO::getJobTracker()->registerJob(job);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotFinished(KJob*)));
|
||||||
|
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddToArchive::slotFinished(KJob *job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
if (job->error()) {
|
||||||
|
KMessageBox::error(NULL, job->errorText());
|
||||||
|
}
|
||||||
|
|
||||||
|
emitResult();
|
||||||
|
}
|
||||||
|
}
|
85
ark/kerfuffle/addtoarchive.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ADDTOARCHIVE_H
|
||||||
|
#define ADDTOARCHIVE_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <KJob>
|
||||||
|
#include <KUrl>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compresses all input files into an archive.
|
||||||
|
*
|
||||||
|
* This is a job class that creates a compressed archive
|
||||||
|
* with all the given input files.
|
||||||
|
*
|
||||||
|
* It provides the functionality for the --add command-line
|
||||||
|
* option, and does not need the GUI to be running.
|
||||||
|
*
|
||||||
|
* @author Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*/
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class KERFUFFLE_EXPORT AddToArchive : public KJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddToArchive(QObject *parent = 0);
|
||||||
|
~AddToArchive();
|
||||||
|
|
||||||
|
bool showAddDialog();
|
||||||
|
void setPreservePaths(bool value);
|
||||||
|
void setChangeToFirstPath(bool value);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool addInput(const KUrl& url);
|
||||||
|
void setAutoFilenameSuffix(const QString& suffix);
|
||||||
|
void setFilename(const KUrl& path);
|
||||||
|
void setMimeType(const QString & mimeType);
|
||||||
|
void start();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotFinished(KJob*);
|
||||||
|
void slotStartJob();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_filename;
|
||||||
|
QString m_strippedPath;
|
||||||
|
QString m_autoFilenameSuffix;
|
||||||
|
QString m_firstPath;
|
||||||
|
QString m_mimeType;
|
||||||
|
QStringList m_inputs;
|
||||||
|
bool m_changeToFirstPath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ADDTOARCHIVE_H
|
||||||
|
|
333
ark/kerfuffle/archive.cpp
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2009-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "archive.h"
|
||||||
|
#include "archiveinterface.h"
|
||||||
|
#include "jobs.h"
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KPluginLoader>
|
||||||
|
#include <KMimeType>
|
||||||
|
#include <KMimeTypeTrader>
|
||||||
|
#include <KServiceTypeTrader>
|
||||||
|
|
||||||
|
static bool comparePlugins(const KService::Ptr &p1, const KService::Ptr &p2)
|
||||||
|
{
|
||||||
|
return (p1->property(QLatin1String( "X-KDE-Priority" )).toInt()) > (p2->property(QLatin1String( "X-KDE-Priority" )).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString determineMimeType(const QString& filename)
|
||||||
|
{
|
||||||
|
if (!QFile::exists(filename)) {
|
||||||
|
return KMimeType::findByPath(filename)->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filename);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const qint64 maxSize = 0x100000; // 1MB
|
||||||
|
const qint64 bufferSize = qMin(maxSize, file.size());
|
||||||
|
const QByteArray buffer = file.read(bufferSize);
|
||||||
|
|
||||||
|
return KMimeType::findByNameAndContent(filename, buffer)->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
static KService::List findPluginOffers(const QString& filename, const QString& fixedMimeType)
|
||||||
|
{
|
||||||
|
KService::List offers;
|
||||||
|
|
||||||
|
const QString mimeType = fixedMimeType.isEmpty() ? determineMimeType(filename) : fixedMimeType;
|
||||||
|
|
||||||
|
if (!mimeType.isEmpty()) {
|
||||||
|
offers = KMimeTypeTrader::self()->query(mimeType, QLatin1String( "Kerfuffle/Plugin" ), QLatin1String( "(exist Library)" ));
|
||||||
|
qSort(offers.begin(), offers.end(), comparePlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
return offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
Archive *Archive::create(const QString &fileName, QObject *parent)
|
||||||
|
{
|
||||||
|
return create(fileName, QString(), parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive *Archive::create(const QString &fileName, const QString &fixedMimeType, QObject *parent)
|
||||||
|
{
|
||||||
|
qRegisterMetaType<ArchiveEntry>("ArchiveEntry");
|
||||||
|
|
||||||
|
const KService::List offers = findPluginOffers(fileName, fixedMimeType);
|
||||||
|
|
||||||
|
if (offers.isEmpty()) {
|
||||||
|
kDebug() << "Could not find a plugin to handle" << fileName;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString pluginName = offers.first()->library();
|
||||||
|
kDebug() << "Loading plugin" << pluginName;
|
||||||
|
|
||||||
|
KPluginFactory * const factory = KPluginLoader(pluginName).factory();
|
||||||
|
if (!factory) {
|
||||||
|
kDebug() << "Invalid plugin factory for" << pluginName;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList args;
|
||||||
|
args.append(QVariant(QFileInfo(fileName).absoluteFilePath()));
|
||||||
|
|
||||||
|
ReadOnlyArchiveInterface * const iface = factory->create<ReadOnlyArchiveInterface>(0, args);
|
||||||
|
if (!iface) {
|
||||||
|
kDebug() << "Could not create plugin instance" << pluginName << "for" << fileName;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Archive(iface, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive::Archive(ReadOnlyArchiveInterface *archiveInterface, QObject *parent)
|
||||||
|
: QObject(parent),
|
||||||
|
m_iface(archiveInterface),
|
||||||
|
m_hasBeenListed(false),
|
||||||
|
m_isPasswordProtected(false),
|
||||||
|
m_isSingleFolderArchive(false)
|
||||||
|
{
|
||||||
|
Q_ASSERT(archiveInterface);
|
||||||
|
archiveInterface->setParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Archive::~Archive()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Archive::isReadOnly() const
|
||||||
|
{
|
||||||
|
return m_iface->isReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob* Archive::open()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob* Archive::create()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListJob* Archive::list()
|
||||||
|
{
|
||||||
|
ListJob *job = new ListJob(m_iface, this);
|
||||||
|
job->setAutoDelete(false);
|
||||||
|
|
||||||
|
//if this job has not been listed before, we grab the opportunity to
|
||||||
|
//collect some information about the archive
|
||||||
|
if (!m_hasBeenListed) {
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(onListFinished(KJob*)));
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteJob* Archive::deleteFiles(const QList<QVariant> & files)
|
||||||
|
{
|
||||||
|
if (m_iface->isReadOnly()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DeleteJob *newJob = new DeleteJob(files, static_cast<ReadWriteArchiveInterface*>(m_iface), this);
|
||||||
|
|
||||||
|
return newJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddJob* Archive::addFiles(const QStringList & files, const CompressionOptions& options)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_iface->isReadOnly());
|
||||||
|
AddJob *newJob = new AddJob(files, options, static_cast<ReadWriteArchiveInterface*>(m_iface), this);
|
||||||
|
connect(newJob, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(onAddFinished(KJob*)));
|
||||||
|
return newJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob* Archive::copyFiles(const QList<QVariant> & files, const QString & destinationDir, ExtractionOptions options)
|
||||||
|
{
|
||||||
|
ExtractionOptions newOptions = options;
|
||||||
|
if (isPasswordProtected()) {
|
||||||
|
newOptions[QLatin1String( "PasswordProtectedHint" )] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob *newJob = new ExtractJob(files, destinationDir, newOptions, m_iface, this);
|
||||||
|
return newJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Archive::fileName() const
|
||||||
|
{
|
||||||
|
return m_iface->filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Archive::onAddFinished(KJob* job)
|
||||||
|
{
|
||||||
|
//if the archive was previously a single folder archive and an add job
|
||||||
|
//has successfully finished, then it is no longer a single folder
|
||||||
|
//archive (for the current implementation, which does not allow adding
|
||||||
|
//folders/files other places than the root.
|
||||||
|
//TODO: handle the case of creating a new file and singlefolderarchive
|
||||||
|
//then.
|
||||||
|
if (m_isSingleFolderArchive && !job->error()) {
|
||||||
|
m_isSingleFolderArchive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Archive::onListFinished(KJob* job)
|
||||||
|
{
|
||||||
|
ListJob *ljob = qobject_cast<ListJob*>(job);
|
||||||
|
m_extractedFilesSize = ljob->extractedFilesSize();
|
||||||
|
m_isSingleFolderArchive = ljob->isSingleFolderArchive();
|
||||||
|
m_isPasswordProtected = ljob->isPasswordProtected();
|
||||||
|
m_subfolderName = ljob->subfolderName();
|
||||||
|
if (m_subfolderName.isEmpty()) {
|
||||||
|
QFileInfo fi(fileName());
|
||||||
|
QString base = fi.completeBaseName();
|
||||||
|
|
||||||
|
//special case for tar.gz/bzip2 files
|
||||||
|
if (base.right(4).toUpper() == QLatin1String(".TAR")) {
|
||||||
|
base.chop(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_subfolderName = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hasBeenListed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Archive::listIfNotListed()
|
||||||
|
{
|
||||||
|
if (!m_hasBeenListed) {
|
||||||
|
KJob *job = list();
|
||||||
|
|
||||||
|
connect(job, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
SLOT(onUserQuery(Kerfuffle::Query*)));
|
||||||
|
|
||||||
|
QEventLoop loop(this);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
&loop, SLOT(quit()));
|
||||||
|
job->start();
|
||||||
|
loop.exec(); // krazy:exclude=crashy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Archive::onUserQuery(Query* query)
|
||||||
|
{
|
||||||
|
query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Archive::isSingleFolderArchive()
|
||||||
|
{
|
||||||
|
listIfNotListed();
|
||||||
|
return m_isSingleFolderArchive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Archive::isPasswordProtected()
|
||||||
|
{
|
||||||
|
listIfNotListed();
|
||||||
|
return m_isPasswordProtected;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Archive::subfolderName()
|
||||||
|
{
|
||||||
|
listIfNotListed();
|
||||||
|
return m_subfolderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Archive::setPassword(const QString &password)
|
||||||
|
{
|
||||||
|
m_iface->setPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList supportedMimeTypes()
|
||||||
|
{
|
||||||
|
const QLatin1String constraint("(exist Library)");
|
||||||
|
const QLatin1String basePartService("Kerfuffle/Plugin");
|
||||||
|
|
||||||
|
const KService::List offers = KServiceTypeTrader::self()->query(basePartService, constraint);
|
||||||
|
KService::List::ConstIterator it = offers.constBegin();
|
||||||
|
KService::List::ConstIterator itEnd = offers.constEnd();
|
||||||
|
|
||||||
|
QStringList supported;
|
||||||
|
|
||||||
|
for (; it != itEnd; ++it) {
|
||||||
|
KService::Ptr service = *it;
|
||||||
|
QStringList mimeTypes = service->serviceTypes();
|
||||||
|
|
||||||
|
foreach (const QString& mimeType, mimeTypes) {
|
||||||
|
if (mimeType != basePartService && !supported.contains(mimeType)) {
|
||||||
|
supported.append(mimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Returning" << supported;
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList supportedWriteMimeTypes()
|
||||||
|
{
|
||||||
|
const QLatin1String constraint("(exist Library) and ([X-KDE-Kerfuffle-ReadWrite] == true)");
|
||||||
|
const QLatin1String basePartService("Kerfuffle/Plugin");
|
||||||
|
|
||||||
|
const KService::List offers = KServiceTypeTrader::self()->query(basePartService, constraint);
|
||||||
|
KService::List::ConstIterator it = offers.constBegin();
|
||||||
|
KService::List::ConstIterator itEnd = offers.constEnd();
|
||||||
|
|
||||||
|
QStringList supported;
|
||||||
|
|
||||||
|
for (; it != itEnd; ++it) {
|
||||||
|
KService::Ptr service = *it;
|
||||||
|
QStringList mimeTypes = service->serviceTypes();
|
||||||
|
|
||||||
|
foreach (const QString& mimeType, mimeTypes) {
|
||||||
|
if (mimeType != basePartService && !supported.contains(mimeType)) {
|
||||||
|
supported.append(mimeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Returning" << supported;
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kerfuffle
|
149
ark/kerfuffle/archive.h
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARCHIVE_H
|
||||||
|
#define ARCHIVE_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
class KJob;
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class ListJob;
|
||||||
|
class ExtractJob;
|
||||||
|
class DeleteJob;
|
||||||
|
class AddJob;
|
||||||
|
class Query;
|
||||||
|
class ReadOnlyArchiveInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meta data related to one entry in a compressed archive.
|
||||||
|
*
|
||||||
|
* When creating a plugin, information about every single entry in
|
||||||
|
* an archive is contained in an ArchiveEntry, and metadata
|
||||||
|
* is set with the entries in this enum.
|
||||||
|
*
|
||||||
|
* Please notice that not all archive formats support all the properties
|
||||||
|
* below, so set those that are available.
|
||||||
|
*/
|
||||||
|
enum EntryMetaDataType {
|
||||||
|
FileName = 0, /**< The entry's file name */
|
||||||
|
InternalID, /**< The entry's ID for Ark's internal manipulation */
|
||||||
|
Permissions, /**< The entry's permissions */
|
||||||
|
Owner, /**< The user the entry belongs to */
|
||||||
|
Group, /**< The user group the entry belongs to */
|
||||||
|
Size, /**< The entry's original size */
|
||||||
|
CompressedSize, /**< The compressed size for the entry */
|
||||||
|
Link, /**< The entry is a symbolic link */
|
||||||
|
Ratio, /**< The compression ratio for the entry */
|
||||||
|
CRC, /**< The entry's CRC */
|
||||||
|
Method, /**< The compression method used on the entry */
|
||||||
|
Version, /**< The archiver version needed to extract the entry */
|
||||||
|
Timestamp, /**< The timestamp for the current entry */
|
||||||
|
IsDirectory, /**< The entry is a directory */
|
||||||
|
Comment,
|
||||||
|
IsPasswordProtected, /**< The entry is password-protected */
|
||||||
|
Custom = 1048576
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QHash<int, QVariant> ArchiveEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
These are the extra options for doing the compression. Naming convention
|
||||||
|
is CamelCase with either Global, or the compression type (such as Zip,
|
||||||
|
Rar, etc), followed by the property name used
|
||||||
|
*/
|
||||||
|
typedef QHash<QString, QVariant> CompressionOptions;
|
||||||
|
typedef QHash<QString, QVariant> ExtractionOptions;
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT Archive : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Archive *create(const QString &fileName, QObject *parent = 0);
|
||||||
|
static Archive *create(const QString &fileName, const QString &fixedMimeType, QObject *parent = 0);
|
||||||
|
~Archive();
|
||||||
|
|
||||||
|
QString fileName() const;
|
||||||
|
bool isReadOnly() const;
|
||||||
|
|
||||||
|
KJob* open();
|
||||||
|
KJob* create();
|
||||||
|
ListJob* list();
|
||||||
|
DeleteJob* deleteFiles(const QList<QVariant> & files);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compression options that should be handled by all interfaces:
|
||||||
|
*
|
||||||
|
* GlobalWorkDir - Change to this dir before adding the new files.
|
||||||
|
* The path names should then be added relative to this directory.
|
||||||
|
*
|
||||||
|
* TODO: find a way to actually add files to specific locations in
|
||||||
|
* the archive
|
||||||
|
* (not supported yet) GlobalPathInArchive - a path relative to the
|
||||||
|
* archive root where the files will be added under
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
AddJob* addFiles(const QStringList & files, const CompressionOptions& options = CompressionOptions());
|
||||||
|
|
||||||
|
ExtractJob* copyFiles(const QList<QVariant> & files, const QString & destinationDir, ExtractionOptions options = ExtractionOptions());
|
||||||
|
|
||||||
|
bool isSingleFolderArchive();
|
||||||
|
QString subfolderName();
|
||||||
|
bool isPasswordProtected();
|
||||||
|
|
||||||
|
void setPassword(const QString &password);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onListFinished(KJob*);
|
||||||
|
void onAddFinished(KJob*);
|
||||||
|
void onUserQuery(Kerfuffle::Query*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Archive(ReadOnlyArchiveInterface *archiveInterface, QObject *parent = 0);
|
||||||
|
|
||||||
|
void listIfNotListed();
|
||||||
|
ReadOnlyArchiveInterface *m_iface;
|
||||||
|
bool m_hasBeenListed;
|
||||||
|
bool m_isPasswordProtected;
|
||||||
|
bool m_isSingleFolderArchive;
|
||||||
|
QString m_subfolderName;
|
||||||
|
qlonglong m_extractedFilesSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
KERFUFFLE_EXPORT QStringList supportedMimeTypes();
|
||||||
|
KERFUFFLE_EXPORT QStringList supportedWriteMimeTypes();
|
||||||
|
} // namespace Kerfuffle
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ARCHIVE_H
|
122
ark/kerfuffle/archiveinterface.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "archiveinterface.h"
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kfileitem.h>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
ReadOnlyArchiveInterface::ReadOnlyArchiveInterface(QObject *parent, const QVariantList & args)
|
||||||
|
: QObject(parent), m_waitForFinishedSignal(false)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
m_filename = args.first().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyArchiveInterface::~ReadOnlyArchiveInterface()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ReadOnlyArchiveInterface::filename() const
|
||||||
|
{
|
||||||
|
return m_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::isReadOnly() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::open()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadOnlyArchiveInterface::setPassword(const QString &password)
|
||||||
|
{
|
||||||
|
m_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ReadOnlyArchiveInterface::password() const
|
||||||
|
{
|
||||||
|
return m_password;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::doKill()
|
||||||
|
{
|
||||||
|
//default implementation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::doSuspend()
|
||||||
|
{
|
||||||
|
//default implementation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::doResume()
|
||||||
|
{
|
||||||
|
//default implementation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriteArchiveInterface::ReadWriteArchiveInterface(QObject *parent, const QVariantList & args)
|
||||||
|
: ReadOnlyArchiveInterface(parent, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadWriteArchiveInterface::~ReadWriteArchiveInterface()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadOnlyArchiveInterface::waitForFinishedSignal()
|
||||||
|
{
|
||||||
|
return m_waitForFinishedSignal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadOnlyArchiveInterface::setWaitForFinishedSignal(bool value)
|
||||||
|
{
|
||||||
|
m_waitForFinishedSignal = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWriteArchiveInterface::isReadOnly() const
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(filename());
|
||||||
|
if (fileInfo.exists()) {
|
||||||
|
return ! fileInfo.isWritable();
|
||||||
|
} else {
|
||||||
|
return !fileInfo.dir().exists(); // TODO: Should also check if we can create a file in that directory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kerfuffle
|
||||||
|
|
||||||
|
#include "archiveinterface.moc"
|
138
ark/kerfuffle/archiveinterface.h
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARCHIVEINTERFACE_H
|
||||||
|
#define ARCHIVEINTERFACE_H
|
||||||
|
|
||||||
|
#include "archive.h"
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QString>
|
||||||
|
#include <QVariantList>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class Query;
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT ReadOnlyArchiveInterface: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ReadOnlyArchiveInterface(QObject *parent, const QVariantList & args);
|
||||||
|
virtual ~ReadOnlyArchiveInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the filename of the archive currently being handled.
|
||||||
|
*/
|
||||||
|
QString filename() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the file can only be read.
|
||||||
|
*
|
||||||
|
* @return @c true The file cannot be written.
|
||||||
|
* @return @c false The file can be read and written.
|
||||||
|
*/
|
||||||
|
virtual bool isReadOnly() const;
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List archive contents.
|
||||||
|
* This runs the process of reading archive contents.
|
||||||
|
* When subclassing, you can block as long as you need, the function runs
|
||||||
|
* in its own thread.
|
||||||
|
* @returns whether the listing succeeded.
|
||||||
|
* @note If returning false, make sure to emit the error() signal beforewards to notify
|
||||||
|
* the user of the error condition.
|
||||||
|
*/
|
||||||
|
virtual bool list() = 0;
|
||||||
|
void setPassword(const QString &password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract files from archive.
|
||||||
|
* Globally recognized extraction options:
|
||||||
|
* @li PreservePaths - preserve file paths (extract flat if false)
|
||||||
|
* @li RootNode - node in the archive which will correspond to the @arg destinationDirectory
|
||||||
|
* When subclassing, you can block as long as you need, the function runs
|
||||||
|
* in its own thread.
|
||||||
|
* @returns whether the listing succeeded.
|
||||||
|
* @note If returning false, make sure to emit the error() signal beforewards to notify
|
||||||
|
* the user of the error condition.
|
||||||
|
*/
|
||||||
|
virtual bool copyFiles(const QList<QVariant> & files, const QString & destinationDirectory, ExtractionOptions options) = 0;
|
||||||
|
|
||||||
|
bool waitForFinishedSignal();
|
||||||
|
|
||||||
|
virtual bool doKill();
|
||||||
|
virtual bool doSuspend();
|
||||||
|
virtual bool doResume();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void error(const QString &message, const QString &details = QString());
|
||||||
|
void entry(const ArchiveEntry &archiveEntry);
|
||||||
|
void entryRemoved(const QString &path);
|
||||||
|
void progress(double progress);
|
||||||
|
void info(const QString &info);
|
||||||
|
void finished(bool result);
|
||||||
|
void userQuery(Query *query);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString password() const;
|
||||||
|
/**
|
||||||
|
* Setting this option to true will not exit the thread with the
|
||||||
|
* exit of the various functions, but rather when finished(bool) is
|
||||||
|
* called. Doing this one can use the event loop easily while doing
|
||||||
|
* the operation.
|
||||||
|
*/
|
||||||
|
void setWaitForFinishedSignal(bool value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_filename;
|
||||||
|
QString m_password;
|
||||||
|
bool m_waitForFinishedSignal;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT ReadWriteArchiveInterface: public ReadOnlyArchiveInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ReadWriteArchiveInterface(QObject *parent, const QVariantList & args);
|
||||||
|
virtual ~ReadWriteArchiveInterface();
|
||||||
|
|
||||||
|
virtual bool isReadOnly() const;
|
||||||
|
|
||||||
|
//see archive.h for a list of what the compressionoptions might
|
||||||
|
//contain
|
||||||
|
virtual bool addFiles(const QStringList & files, const CompressionOptions& options) = 0;
|
||||||
|
virtual bool deleteFiles(const QList<QVariant> & files) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kerfuffle
|
||||||
|
|
||||||
|
#endif // ARCHIVEINTERFACE_H
|
25
ark/kerfuffle/ark.kcfg
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||||
|
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||||
|
<kcfgfile name="arkrc"/>
|
||||||
|
<group name="Extraction">
|
||||||
|
<entry name="openDestinationFolderAfterExtraction" type="Bool">
|
||||||
|
<label>Open destination folder after extraction</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
<entry name="closeAfterExtraction" type="Bool">
|
||||||
|
<label>Close Ark after extraction</label>
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
<entry name="preservePaths" type="Bool">
|
||||||
|
<label>Preserve paths when extracting</label>
|
||||||
|
<default>true</default>
|
||||||
|
</entry>
|
||||||
|
</group>
|
||||||
|
<group name="MainWindow">
|
||||||
|
<entry name="splitterSizes" type="IntList" />
|
||||||
|
<entry name="splitterSizesWithBothWidgets" type="IntList" />
|
||||||
|
</group>
|
||||||
|
</kcfg>
|
751
ark/kerfuffle/cliinterface.cpp
Normal file
|
@ -0,0 +1,751 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cliinterface.h"
|
||||||
|
#include "queries.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# include <KProcess>
|
||||||
|
#else
|
||||||
|
# include <KPtyDevice>
|
||||||
|
# include <KPtyProcess>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <KStandardDirs>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KLocale>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
CliInterface::CliInterface(QObject *parent, const QVariantList & args)
|
||||||
|
: ReadWriteArchiveInterface(parent, args),
|
||||||
|
m_process(0),
|
||||||
|
m_listEmptyLines(false),
|
||||||
|
m_abortingOperation(false)
|
||||||
|
{
|
||||||
|
//because this interface uses the event loop
|
||||||
|
setWaitForFinishedSignal(true);
|
||||||
|
|
||||||
|
if (QMetaType::type("QProcess::ExitStatus") == 0) {
|
||||||
|
qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::cacheParameterList()
|
||||||
|
{
|
||||||
|
m_param = parameterList();
|
||||||
|
Q_ASSERT(m_param.contains(ExtractProgram));
|
||||||
|
Q_ASSERT(m_param.contains(ListProgram));
|
||||||
|
Q_ASSERT(m_param.contains(PreservePathSwitch));
|
||||||
|
Q_ASSERT(m_param.contains(FileExistsExpression));
|
||||||
|
Q_ASSERT(m_param.contains(FileExistsInput));
|
||||||
|
}
|
||||||
|
|
||||||
|
CliInterface::~CliInterface()
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_process);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::setListEmptyLines(bool emptyLines)
|
||||||
|
{
|
||||||
|
m_listEmptyLines = emptyLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::list()
|
||||||
|
{
|
||||||
|
cacheParameterList();
|
||||||
|
m_operationMode = List;
|
||||||
|
|
||||||
|
QStringList args = m_param.value(ListArgs).toStringList();
|
||||||
|
substituteListVariables(args);
|
||||||
|
|
||||||
|
if (!runProcess(m_param.value(ListProgram).toStringList(), args)) {
|
||||||
|
failOperation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::copyFiles(const QList<QVariant> & files, const QString & destinationDirectory, ExtractionOptions options)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
cacheParameterList();
|
||||||
|
|
||||||
|
m_operationMode = Copy;
|
||||||
|
|
||||||
|
//start preparing the argument list
|
||||||
|
QStringList args = m_param.value(ExtractArgs).toStringList();
|
||||||
|
|
||||||
|
//now replace the various elements in the list
|
||||||
|
for (int i = 0; i < args.size(); ++i) {
|
||||||
|
QString argument = args.at(i);
|
||||||
|
kDebug() << "Processing argument " << argument;
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$Archive" )) {
|
||||||
|
args[i] = filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$PreservePathSwitch" )) {
|
||||||
|
QStringList replacementFlags = m_param.value(PreservePathSwitch).toStringList();
|
||||||
|
Q_ASSERT(replacementFlags.size() == 2);
|
||||||
|
|
||||||
|
bool preservePaths = options.value(QLatin1String( "PreservePaths" )).toBool();
|
||||||
|
QString theReplacement;
|
||||||
|
if (preservePaths) {
|
||||||
|
theReplacement = replacementFlags.at(0);
|
||||||
|
} else {
|
||||||
|
theReplacement = replacementFlags.at(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theReplacement.isEmpty()) {
|
||||||
|
args.removeAt(i);
|
||||||
|
--i; //decrement to compensate for the variable we removed
|
||||||
|
} else {
|
||||||
|
//but in this case we don't have to decrement, we just
|
||||||
|
//replace it
|
||||||
|
args[i] = theReplacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$PasswordSwitch" )) {
|
||||||
|
//if the PasswordSwitch argument has been added, we at least
|
||||||
|
//assume that the format of the switch has been added as well
|
||||||
|
Q_ASSERT(m_param.contains(PasswordSwitch));
|
||||||
|
|
||||||
|
//we will decrement i afterwards
|
||||||
|
args.removeAt(i);
|
||||||
|
|
||||||
|
//if we get a hint about this being a password protected archive, ask about
|
||||||
|
//the password in advance.
|
||||||
|
if ((options.value(QLatin1String("PasswordProtectedHint")).toBool()) &&
|
||||||
|
(password().isEmpty())) {
|
||||||
|
kDebug() << "Password hint enabled, querying user";
|
||||||
|
|
||||||
|
Kerfuffle::PasswordNeededQuery query(filename());
|
||||||
|
emit userQuery(&query);
|
||||||
|
query.waitForResponse();
|
||||||
|
|
||||||
|
if (query.responseCancelled()) {
|
||||||
|
failOperation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setPassword(query.password());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString pass = password();
|
||||||
|
|
||||||
|
if (!pass.isEmpty()) {
|
||||||
|
QStringList theSwitch = m_param.value(PasswordSwitch).toStringList();
|
||||||
|
for (int j = 0; j < theSwitch.size(); ++j) {
|
||||||
|
//get the argument part
|
||||||
|
QString newArg = theSwitch.at(j);
|
||||||
|
|
||||||
|
//substitute the $Path
|
||||||
|
newArg.replace(QLatin1String( "$Password" ), pass);
|
||||||
|
|
||||||
|
//put it in the arg list
|
||||||
|
args.insert(i + j, newArg);
|
||||||
|
++i;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--i; //decrement to compensate for the variable we replaced
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$RootNodeSwitch" )) {
|
||||||
|
//if the RootNodeSwitch argument has been added, we at least
|
||||||
|
//assume that the format of the switch has been added as well
|
||||||
|
Q_ASSERT(m_param.contains(RootNodeSwitch));
|
||||||
|
|
||||||
|
//we will decrement i afterwards
|
||||||
|
args.removeAt(i);
|
||||||
|
|
||||||
|
QString rootNode;
|
||||||
|
if (options.contains(QLatin1String( "RootNode" ))) {
|
||||||
|
rootNode = options.value(QLatin1String( "RootNode" )).toString();
|
||||||
|
kDebug() << "Set root node " << rootNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rootNode.isEmpty()) {
|
||||||
|
QStringList theSwitch = m_param.value(RootNodeSwitch).toStringList();
|
||||||
|
for (int j = 0; j < theSwitch.size(); ++j) {
|
||||||
|
//get the argument part
|
||||||
|
QString newArg = theSwitch.at(j);
|
||||||
|
|
||||||
|
//substitute the $Path
|
||||||
|
newArg.replace(QLatin1String( "$Path" ), rootNode);
|
||||||
|
|
||||||
|
//put it in the arg list
|
||||||
|
args.insert(i + j, newArg);
|
||||||
|
++i;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--i; //decrement to compensate for the variable we replaced
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$Files" )) {
|
||||||
|
args.removeAt(i);
|
||||||
|
for (int j = 0; j < files.count(); ++j) {
|
||||||
|
args.insert(i + j, escapeFileName(files.at(j).toString()));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Setting current dir to " << destinationDirectory;
|
||||||
|
QDir::setCurrent(destinationDirectory);
|
||||||
|
|
||||||
|
if (!runProcess(m_param.value(ExtractProgram).toStringList(), args)) {
|
||||||
|
failOperation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::addFiles(const QStringList & files, const CompressionOptions& options)
|
||||||
|
{
|
||||||
|
cacheParameterList();
|
||||||
|
|
||||||
|
m_operationMode = Add;
|
||||||
|
|
||||||
|
const QString globalWorkDir = options.value(QLatin1String( "GlobalWorkDir" )).toString();
|
||||||
|
const QDir workDir = globalWorkDir.isEmpty() ? QDir::current() : QDir(globalWorkDir);
|
||||||
|
if (!globalWorkDir.isEmpty()) {
|
||||||
|
kDebug() << "GlobalWorkDir is set, changing dir to " << globalWorkDir;
|
||||||
|
QDir::setCurrent(globalWorkDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
//start preparing the argument list
|
||||||
|
QStringList args = m_param.value(AddArgs).toStringList();
|
||||||
|
|
||||||
|
//now replace the various elements in the list
|
||||||
|
for (int i = 0; i < args.size(); ++i) {
|
||||||
|
const QString argument = args.at(i);
|
||||||
|
kDebug() << "Processing argument " << argument;
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$Archive" )) {
|
||||||
|
args[i] = filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$Files" )) {
|
||||||
|
args.removeAt(i);
|
||||||
|
for (int j = 0; j < files.count(); ++j) {
|
||||||
|
// #191821: workDir must be used instead of QDir::current()
|
||||||
|
// so that symlinks aren't resolved automatically
|
||||||
|
// TODO: this kind of call should be moved upwards in the
|
||||||
|
// class hierarchy to avoid code duplication
|
||||||
|
const QString relativeName =
|
||||||
|
workDir.relativeFilePath(files.at(j));
|
||||||
|
|
||||||
|
args.insert(i + j, relativeName);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!runProcess(m_param.value(AddProgram).toStringList(), args)) {
|
||||||
|
failOperation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::deleteFiles(const QList<QVariant> & files)
|
||||||
|
{
|
||||||
|
cacheParameterList();
|
||||||
|
m_operationMode = Delete;
|
||||||
|
|
||||||
|
//start preparing the argument list
|
||||||
|
QStringList args = m_param.value(DeleteArgs).toStringList();
|
||||||
|
|
||||||
|
//now replace the various elements in the list
|
||||||
|
for (int i = 0; i < args.size(); ++i) {
|
||||||
|
QString argument = args.at(i);
|
||||||
|
kDebug() << "Processing argument " << argument;
|
||||||
|
|
||||||
|
if (argument == QLatin1String( "$Archive" )) {
|
||||||
|
args[i] = filename();
|
||||||
|
} else if (argument == QLatin1String( "$Files" )) {
|
||||||
|
args.removeAt(i);
|
||||||
|
for (int j = 0; j < files.count(); ++j) {
|
||||||
|
args.insert(i + j, escapeFileName(files.at(j).toString()));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_removedFiles = files;
|
||||||
|
|
||||||
|
if (!runProcess(m_param.value(DeleteProgram).toStringList(), args)) {
|
||||||
|
failOperation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::runProcess(const QStringList& programNames, const QStringList& arguments)
|
||||||
|
{
|
||||||
|
QString programPath;
|
||||||
|
for (int i = 0; i < programNames.count(); i++) {
|
||||||
|
programPath = KStandardDirs::findExe(programNames.at(i));
|
||||||
|
if (!programPath.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (programPath.isEmpty()) {
|
||||||
|
const QString names = programNames.join(QLatin1String(", "));
|
||||||
|
emit error(i18ncp("@info", "Failed to locate program <filename>%2</filename> on disk.",
|
||||||
|
"Failed to locate programs <filename>%2</filename> on disk.", programNames.count(), names));
|
||||||
|
emit finished(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Executing" << programPath << arguments;
|
||||||
|
|
||||||
|
if (m_process) {
|
||||||
|
m_process->waitForFinished();
|
||||||
|
delete m_process;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
m_process = new KProcess;
|
||||||
|
#else
|
||||||
|
m_process = new KPtyProcess;
|
||||||
|
m_process->setPtyChannels(KPtyProcess::StdinChannel);
|
||||||
|
QEventLoop loop;
|
||||||
|
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit()), Qt::DirectConnection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_process->setOutputChannelMode(KProcess::MergedChannels);
|
||||||
|
m_process->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered | QIODevice::Text);
|
||||||
|
m_process->setProgram(programPath, arguments);
|
||||||
|
|
||||||
|
connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(readStdout()), Qt::DirectConnection);
|
||||||
|
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(processFinished(int,QProcess::ExitStatus)), Qt::DirectConnection);
|
||||||
|
|
||||||
|
m_stdOutData.clear();
|
||||||
|
|
||||||
|
m_process->start();
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
bool ret = m_process->waitForFinished(-1);
|
||||||
|
#else
|
||||||
|
bool ret = (loop.exec(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents) == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Q_ASSERT(!m_process);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
kDebug() << exitCode << exitStatus;
|
||||||
|
|
||||||
|
//if the m_process pointer is gone, then there is nothing to worry
|
||||||
|
//about here
|
||||||
|
if (!m_process) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_operationMode == Delete) {
|
||||||
|
foreach(const QVariant& v, m_removedFiles) {
|
||||||
|
emit entryRemoved(v.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle all the remaining data in the process
|
||||||
|
readStdout(true);
|
||||||
|
|
||||||
|
delete m_process;
|
||||||
|
m_process = 0;
|
||||||
|
|
||||||
|
emit progress(1.0);
|
||||||
|
|
||||||
|
if (m_operationMode == Add) {
|
||||||
|
list();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//and we're finished
|
||||||
|
emit finished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::failOperation()
|
||||||
|
{
|
||||||
|
// TODO: Would be good to unit test #304764/#304178.
|
||||||
|
kDebug();
|
||||||
|
doKill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::readStdout(bool handleAll)
|
||||||
|
{
|
||||||
|
//when hacking this function, please remember the following:
|
||||||
|
//- standard output comes in unpredictable chunks, this is why
|
||||||
|
//you can never know if the last part of the output is a complete line or not
|
||||||
|
//- console applications are not really consistent about what
|
||||||
|
//characters they send out (newline, backspace, carriage return,
|
||||||
|
//etc), so keep in mind that this function is supposed to handle
|
||||||
|
//all those special cases and be the lowest common denominator
|
||||||
|
|
||||||
|
if (m_abortingOperation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Q_ASSERT(m_process);
|
||||||
|
|
||||||
|
if (!m_process->bytesAvailable()) {
|
||||||
|
//if process has no more data, we can just bail out
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the process is still not finished (m_process is appearantly not
|
||||||
|
//set to NULL if here), then the operation should definitely not be in
|
||||||
|
//the main thread as this would freeze everything. assert this.
|
||||||
|
Q_ASSERT(QThread::currentThread() != QApplication::instance()->thread());
|
||||||
|
|
||||||
|
QByteArray dd = m_process->readAllStandardOutput();
|
||||||
|
m_stdOutData += dd;
|
||||||
|
|
||||||
|
QList<QByteArray> lines = m_stdOutData.split('\n');
|
||||||
|
|
||||||
|
//The reason for this check is that archivers often do not end
|
||||||
|
//queries (such as file exists, wrong password) on a new line, but
|
||||||
|
//freeze waiting for input. So we check for errors on the last line in
|
||||||
|
//all cases.
|
||||||
|
// TODO: QLatin1String() might not be the best choice here.
|
||||||
|
// The call to handleLine() at the end of the method uses
|
||||||
|
// QString::fromLocal8Bit(), for example.
|
||||||
|
// TODO: The same check methods are called in handleLine(), this
|
||||||
|
// is suboptimal.
|
||||||
|
bool foundErrorMessage =
|
||||||
|
(checkForErrorMessage(QLatin1String( lines.last() ), WrongPasswordPatterns) ||
|
||||||
|
checkForErrorMessage(QLatin1String( lines.last() ), ExtractionFailedPatterns) ||
|
||||||
|
checkForPasswordPromptMessage(QLatin1String(lines.last())) ||
|
||||||
|
checkForFileExistsMessage(QLatin1String( lines.last() )));
|
||||||
|
|
||||||
|
if (foundErrorMessage) {
|
||||||
|
handleAll = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is complex, here's an explanation:
|
||||||
|
//if there is no newline, then there is no guaranteed full line to
|
||||||
|
//handle in the output. The exception is that it is supposed to handle
|
||||||
|
//all the data, OR if there's been an error message found in the
|
||||||
|
//partial data.
|
||||||
|
if (lines.size() == 1 && !handleAll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleAll) {
|
||||||
|
m_stdOutData.clear();
|
||||||
|
} else {
|
||||||
|
//because the last line might be incomplete we leave it for now
|
||||||
|
//note, this last line may be an empty string if the stdoutdata ends
|
||||||
|
//with a newline
|
||||||
|
m_stdOutData = lines.takeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QByteArray& line, lines) {
|
||||||
|
if (!line.isEmpty() || (m_listEmptyLines && m_operationMode == List)) {
|
||||||
|
handleLine(QString::fromLocal8Bit(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::handleLine(const QString& line)
|
||||||
|
{
|
||||||
|
// TODO: This should be implemented by each plugin; the way progress is
|
||||||
|
// shown by each CLI application is subject to a lot of variation.
|
||||||
|
if ((m_operationMode == Copy || m_operationMode == Add) && m_param.contains(CaptureProgress) && m_param.value(CaptureProgress).toBool()) {
|
||||||
|
//read the percentage
|
||||||
|
int pos = line.indexOf(QLatin1Char( '%' ));
|
||||||
|
if (pos != -1 && pos > 1) {
|
||||||
|
int percentage = line.mid(pos - 2, 2).toInt();
|
||||||
|
emit progress(float(percentage) / 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_operationMode == Copy) {
|
||||||
|
if (checkForPasswordPromptMessage(line)) {
|
||||||
|
kDebug() << "Found a password prompt";
|
||||||
|
|
||||||
|
Kerfuffle::PasswordNeededQuery query(filename());
|
||||||
|
emit userQuery(&query);
|
||||||
|
query.waitForResponse();
|
||||||
|
|
||||||
|
if (query.responseCancelled()) {
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPassword(query.password());
|
||||||
|
|
||||||
|
const QString response(password() + QLatin1Char('\n'));
|
||||||
|
writeToProcess(response.toLocal8Bit());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkForErrorMessage(line, WrongPasswordPatterns)) {
|
||||||
|
kDebug() << "Wrong password!";
|
||||||
|
emit error(i18n("Incorrect password."));
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkForErrorMessage(line, ExtractionFailedPatterns)) {
|
||||||
|
kDebug() << "Error in extraction!!";
|
||||||
|
emit error(i18n("Extraction failed because of an unexpected error."));
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleFileExistsMessage(line)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_operationMode == List) {
|
||||||
|
if (checkForPasswordPromptMessage(line)) {
|
||||||
|
kDebug() << "Found a password prompt";
|
||||||
|
|
||||||
|
Kerfuffle::PasswordNeededQuery query(filename());
|
||||||
|
emit userQuery(&query);
|
||||||
|
query.waitForResponse();
|
||||||
|
|
||||||
|
if (query.responseCancelled()) {
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPassword(query.password());
|
||||||
|
|
||||||
|
const QString response(password() + QLatin1Char('\n'));
|
||||||
|
writeToProcess(response.toLocal8Bit());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkForErrorMessage(line, WrongPasswordPatterns)) {
|
||||||
|
kDebug() << "Wrong password!";
|
||||||
|
emit error(i18n("Incorrect password."));
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkForErrorMessage(line, ExtractionFailedPatterns)) {
|
||||||
|
kDebug() << "Error in extraction!!";
|
||||||
|
emit error(i18n("Extraction failed because of an unexpected error."));
|
||||||
|
failOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleFileExistsMessage(line)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readListLine(line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::checkForPasswordPromptMessage(const QString& line)
|
||||||
|
{
|
||||||
|
const QString passwordPromptPattern(m_param.value(PasswordPromptPattern).toString());
|
||||||
|
|
||||||
|
if (passwordPromptPattern.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_passwordPromptPattern.isEmpty()) {
|
||||||
|
m_passwordPromptPattern.setPattern(m_param.value(PasswordPromptPattern).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_passwordPromptPattern.indexIn(line) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::checkForFileExistsMessage(const QString& line)
|
||||||
|
{
|
||||||
|
if (m_existsPattern.isEmpty()) {
|
||||||
|
m_existsPattern.setPattern(m_param.value(FileExistsExpression).toString());
|
||||||
|
}
|
||||||
|
if (m_existsPattern.indexIn(line) != -1) {
|
||||||
|
kDebug() << "Detected file existing!! Filename " << m_existsPattern.cap(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::handleFileExistsMessage(const QString& line)
|
||||||
|
{
|
||||||
|
if (!checkForFileExistsMessage(line)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString filename = m_existsPattern.cap(1);
|
||||||
|
|
||||||
|
Kerfuffle::OverwriteQuery query(QDir::current().path() + QLatin1Char( '/' ) + filename);
|
||||||
|
query.setNoRenameMode(true);
|
||||||
|
emit userQuery(&query);
|
||||||
|
kDebug() << "Waiting response";
|
||||||
|
query.waitForResponse();
|
||||||
|
|
||||||
|
kDebug() << "Finished response";
|
||||||
|
|
||||||
|
QString responseToProcess;
|
||||||
|
const QStringList choices = m_param.value(FileExistsInput).toStringList();
|
||||||
|
|
||||||
|
if (query.responseOverwrite()) {
|
||||||
|
responseToProcess = choices.at(0);
|
||||||
|
} else if (query.responseSkip()) {
|
||||||
|
responseToProcess = choices.at(1);
|
||||||
|
} else if (query.responseOverwriteAll()) {
|
||||||
|
responseToProcess = choices.at(2);
|
||||||
|
} else if (query.responseAutoSkip()) {
|
||||||
|
responseToProcess = choices.at(3);
|
||||||
|
} else if (query.responseCancelled()) {
|
||||||
|
if (choices.count() < 5) { // If the program has no way to cancel the extraction, we resort to killing it
|
||||||
|
return doKill();
|
||||||
|
}
|
||||||
|
responseToProcess = choices.at(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!responseToProcess.isEmpty());
|
||||||
|
|
||||||
|
responseToProcess += QLatin1Char( '\n' );
|
||||||
|
|
||||||
|
writeToProcess(responseToProcess.toLocal8Bit());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::checkForErrorMessage(const QString& line, int parameterIndex)
|
||||||
|
{
|
||||||
|
QList<QRegExp> patterns;
|
||||||
|
|
||||||
|
if (m_patternCache.contains(parameterIndex)) {
|
||||||
|
patterns = m_patternCache.value(parameterIndex);
|
||||||
|
} else {
|
||||||
|
if (!m_param.contains(parameterIndex)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QString& rawPattern, m_param.value(parameterIndex).toStringList()) {
|
||||||
|
patterns << QRegExp(rawPattern);
|
||||||
|
}
|
||||||
|
m_patternCache[parameterIndex] = patterns;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QRegExp& pattern, patterns) {
|
||||||
|
if (pattern.indexIn(line) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::doKill()
|
||||||
|
{
|
||||||
|
if (m_process) {
|
||||||
|
// Give some time for the application to finish gracefully
|
||||||
|
m_abortingOperation = true;
|
||||||
|
if (!m_process->waitForFinished(5)) {
|
||||||
|
m_process->kill();
|
||||||
|
}
|
||||||
|
m_abortingOperation = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::doSuspend()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CliInterface::doResume()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::substituteListVariables(QStringList& params)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params.size(); ++i) {
|
||||||
|
const QString parameter = params.at(i);
|
||||||
|
|
||||||
|
if (parameter == QLatin1String( "$Archive" )) {
|
||||||
|
params[i] = filename();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CliInterface::escapeFileName(const QString& fileName) const
|
||||||
|
{
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CliInterface::writeToProcess(const QByteArray& data)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_process);
|
||||||
|
Q_ASSERT(!data.isNull());
|
||||||
|
|
||||||
|
kDebug() << "Writing" << data << "to the process";
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
m_process->write(data);
|
||||||
|
#else
|
||||||
|
m_process->pty()->write(data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "cliinterface.moc"
|
349
ark/kerfuffle/cliinterface.h
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef CLIINTERFACE_H
|
||||||
|
#define CLIINTERFACE_H
|
||||||
|
|
||||||
|
#include "archiveinterface.h"
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
#include <QtCore/QProcess>
|
||||||
|
#include <QtCore/QRegExp>
|
||||||
|
|
||||||
|
class KProcess;
|
||||||
|
class KPtyProcess;
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
enum CliInterfaceParameters {
|
||||||
|
|
||||||
|
///////////////[ COMMON ]/////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bool (default false)
|
||||||
|
* Will look for the %-sign in the stdout while working, in the form of
|
||||||
|
* (2%, 14%, 35%, etc etc), and report progress based upon this
|
||||||
|
*/
|
||||||
|
CaptureProgress = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QString
|
||||||
|
* Default: empty
|
||||||
|
* A regexp pattern that matches the program's password prompt.
|
||||||
|
*/
|
||||||
|
PasswordPromptPattern,
|
||||||
|
|
||||||
|
///////////////[ LIST ]/////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The names to the program that will handle listing of this
|
||||||
|
* archive (eg "rar"). Will be searched for in PATH
|
||||||
|
*/
|
||||||
|
ListProgram,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The arguments that are passed to the program above for
|
||||||
|
* listing the archive. Special strings that will be
|
||||||
|
* substituted:
|
||||||
|
* $Archive - the path of the archive
|
||||||
|
*/
|
||||||
|
ListArgs,
|
||||||
|
|
||||||
|
///////////////[ EXTRACT ]/////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The names to the program that will handle extracting of this
|
||||||
|
* archive (eg "rar"). Will be searched for in PATH
|
||||||
|
*/
|
||||||
|
ExtractProgram,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The arguments that are passed to the program above for
|
||||||
|
* extracting the archive. Special strings that will be
|
||||||
|
* substituted:
|
||||||
|
* $Archive - the path of the archive
|
||||||
|
* $Files - the files selected to be extracted, if any
|
||||||
|
* $PreservePathSwitch - the flag for extracting with full paths
|
||||||
|
* $RootNodeSwitch - the internal work dir in the archive (for example
|
||||||
|
* when the user has dragged a folder from the archive and wants it
|
||||||
|
* extracted relative to it)
|
||||||
|
* $PasswordSwitch - the switch setting the password. Note that this
|
||||||
|
* will not be inserted unless the listing function has emitted an
|
||||||
|
* entry with the IsPasswordProtected property set to true.
|
||||||
|
*/
|
||||||
|
ExtractArgs,
|
||||||
|
/**
|
||||||
|
* Bool (default false)
|
||||||
|
* When passing directories to the extract program, do not
|
||||||
|
* include trailing slashes
|
||||||
|
* e.g. if the user selected "foo/" and "foo/bar" in the gui, the
|
||||||
|
* paths "foo" and "foo/bar" will be sent to the program.
|
||||||
|
*/
|
||||||
|
NoTrailingSlashes,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* This should be a qstringlist with either two elements. The first
|
||||||
|
* string is what PreservePathSwitch in the ExtractArgs will be replaced
|
||||||
|
* with if PreservePath is True/enabled. The second is for the disabled
|
||||||
|
* case. An empty string means that the argument will not be used in
|
||||||
|
* that case.
|
||||||
|
* Example: for rar, "x" means extract with full paths, and "e" means
|
||||||
|
* extract without full paths. in this case we will use the stringlist
|
||||||
|
* ("x", "e"). Or, for another format that might use the switch
|
||||||
|
* "--extractFull" for preservePaths, and nothing otherwise: we use the
|
||||||
|
* stringlist ("--extractFull", "")
|
||||||
|
*/
|
||||||
|
PreservePathSwitch,
|
||||||
|
/**
|
||||||
|
* QStringList (default empty)
|
||||||
|
* The format of the root node switch. The variable $Path will be
|
||||||
|
* substituted for the path string.
|
||||||
|
* Example: ("--internalPath=$Path)
|
||||||
|
* or ("--path", "$Path")
|
||||||
|
*/
|
||||||
|
RootNodeSwitch,
|
||||||
|
/**
|
||||||
|
* QStringList (default empty)
|
||||||
|
* The format of the root node switch. The variable $Password will be
|
||||||
|
* substituted for the password string. NOTE: supplying passwords
|
||||||
|
* through a virtual terminal is not supported (yet?), because this
|
||||||
|
* is not cross platform compatible. As of KDE 4.3 there are no plans to
|
||||||
|
* change this.
|
||||||
|
* Example: ("-p$Password)
|
||||||
|
* or ("--password", "$Password")
|
||||||
|
*/
|
||||||
|
PasswordSwitch,
|
||||||
|
/**
|
||||||
|
* QString
|
||||||
|
* This is a regexp, defining how to recognize a "File already exists"
|
||||||
|
* prompt when extracting. It should have one captured string, which is
|
||||||
|
* the filename of the file/folder that already exists.
|
||||||
|
*/
|
||||||
|
FileExistsExpression,
|
||||||
|
/**
|
||||||
|
* int
|
||||||
|
* This sets on what output channel the FileExistsExpression regex
|
||||||
|
* should be applied on, in other words, on what stream the "file
|
||||||
|
* exists" output will appear in. Values accepted:
|
||||||
|
* 0 - Standard error, stderr (default)
|
||||||
|
* 1 - Standard output, stdout
|
||||||
|
*/
|
||||||
|
FileExistsMode,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The various responses that can be supplied as a response to the
|
||||||
|
* "file exists" prompt. The various items are to be supplied in the
|
||||||
|
* following order:
|
||||||
|
* index 0 - Yes (overwrite)
|
||||||
|
* index 1 - No (skip/do not overwrite)
|
||||||
|
* index 2 - All (overwrite all)
|
||||||
|
* index 3 - Do not overwrite any files (autoskip)
|
||||||
|
* index 4 - Cancel operation
|
||||||
|
*/
|
||||||
|
FileExistsInput,
|
||||||
|
|
||||||
|
///////////////[ DELETE ]/////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The names to the program that will handle deleting of elements in this
|
||||||
|
* archive format (eg "rar"). Will be searched for in PATH
|
||||||
|
*/
|
||||||
|
DeleteProgram,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The arguments that are passed to the program above for
|
||||||
|
* deleting from the archive. Special strings that will be
|
||||||
|
* substituted:
|
||||||
|
* $Archive - the path of the archive
|
||||||
|
* $Files - the files selected to be deleted
|
||||||
|
*/
|
||||||
|
DeleteArgs,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* Default: empty
|
||||||
|
* A list of regexp patterns that will cause the extraction to exit
|
||||||
|
* with a general fail message
|
||||||
|
*/
|
||||||
|
ExtractionFailedPatterns,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* Default: empty
|
||||||
|
* A list of regexp patterns that will alert the user that the password
|
||||||
|
* was wrong.
|
||||||
|
*/
|
||||||
|
WrongPasswordPatterns,
|
||||||
|
|
||||||
|
///////////////[ ADD ]/////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The names to the program that will handle adding in this
|
||||||
|
* archive format (eg "rar"). Will be searched for in PATH
|
||||||
|
*/
|
||||||
|
AddProgram,
|
||||||
|
/**
|
||||||
|
* QStringList
|
||||||
|
* The arguments that are passed to the program above for
|
||||||
|
* adding to the archive. Special strings that will be
|
||||||
|
* substituted:
|
||||||
|
* $Archive - the path of the archive
|
||||||
|
* $Files - the files selected to be added
|
||||||
|
*/
|
||||||
|
AddArgs
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QHash<int, QVariant> ParameterList;
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT CliInterface : public ReadWriteArchiveInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum OperationMode {
|
||||||
|
List, Copy, Add, Delete
|
||||||
|
};
|
||||||
|
OperationMode m_operationMode;
|
||||||
|
|
||||||
|
explicit CliInterface(QObject *parent, const QVariantList & args);
|
||||||
|
virtual ~CliInterface();
|
||||||
|
|
||||||
|
virtual bool list();
|
||||||
|
virtual bool copyFiles(const QList<QVariant> & files, const QString & destinationDirectory, ExtractionOptions options);
|
||||||
|
virtual bool addFiles(const QStringList & files, const CompressionOptions& options);
|
||||||
|
virtual bool deleteFiles(const QList<QVariant> & files);
|
||||||
|
|
||||||
|
virtual ParameterList parameterList() const = 0;
|
||||||
|
virtual bool readListLine(const QString &line) = 0;
|
||||||
|
|
||||||
|
bool doKill();
|
||||||
|
bool doSuspend();
|
||||||
|
bool doResume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of characters which are preceded by a
|
||||||
|
* backslash when a file name in an archive is passed to
|
||||||
|
* a program.
|
||||||
|
*
|
||||||
|
* @see setEscapedCharacters().
|
||||||
|
*/
|
||||||
|
QString escapedCharacters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets which characters will be preceded by a backslash when
|
||||||
|
* a file name in an archive is passed to a program.
|
||||||
|
*
|
||||||
|
* @see escapedCharacters().
|
||||||
|
*/
|
||||||
|
void setEscapedCharacters(const QString& characters);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the listing should include empty lines.
|
||||||
|
*
|
||||||
|
* The default value is false.
|
||||||
|
*/
|
||||||
|
void setListEmptyLines(bool emptyLines);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void substituteListVariables(QStringList& params);
|
||||||
|
|
||||||
|
void cacheParameterList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a line of the program's output is a password prompt.
|
||||||
|
*
|
||||||
|
* It uses the regular expression in the @c PasswordPromptPattern parameter
|
||||||
|
* for the check.
|
||||||
|
*
|
||||||
|
* @param line A line of the program's output.
|
||||||
|
*
|
||||||
|
* @return @c true if the given @p line is a password prompt, @c false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool checkForPasswordPromptMessage(const QString& line);
|
||||||
|
|
||||||
|
bool checkForFileExistsMessage(const QString& line);
|
||||||
|
bool handleFileExistsMessage(const QString& filename);
|
||||||
|
bool checkForErrorMessage(const QString& line, int parameterIndex);
|
||||||
|
void handleLine(const QString& line);
|
||||||
|
|
||||||
|
void failOperation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run @p programName with the given @p arguments.
|
||||||
|
* The method waits until @p programName is finished to exit.
|
||||||
|
*
|
||||||
|
* @param programName The program that will be run (not the whole path).
|
||||||
|
* @param arguments A list of arguments that will be passed to the program.
|
||||||
|
*
|
||||||
|
* @return @c true if the program was found and the process ran correctly,
|
||||||
|
* @c false otherwise.
|
||||||
|
*/
|
||||||
|
bool runProcess(const QStringList& programNames, const QStringList& arguments);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs any additional escaping and processing on @p fileName
|
||||||
|
* before passing it to the underlying process.
|
||||||
|
*
|
||||||
|
* The default implementation returns @p fileName unchanged.
|
||||||
|
*
|
||||||
|
* @param fileName String to escape.
|
||||||
|
*/
|
||||||
|
virtual QString escapeFileName(const QString &fileName) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around KProcess::write() or KPtyDevice::write(), depending on
|
||||||
|
* the platform.
|
||||||
|
*/
|
||||||
|
void writeToProcess(const QByteArray& data);
|
||||||
|
|
||||||
|
QByteArray m_stdOutData;
|
||||||
|
QRegExp m_existsPattern;
|
||||||
|
QRegExp m_passwordPromptPattern;
|
||||||
|
QHash<int, QList<QRegExp> > m_patternCache;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
KProcess *m_process;
|
||||||
|
#else
|
||||||
|
KPtyProcess *m_process;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ParameterList m_param;
|
||||||
|
QVariantList m_removedFiles;
|
||||||
|
bool m_listEmptyLines;
|
||||||
|
bool m_abortingOperation;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readStdout(bool handleAll = false);
|
||||||
|
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CLIINTERFACE_H */
|
234
ark/kerfuffle/extractiondialog.cpp
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "extractiondialog.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KIconLoader>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KStandardDirs>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include "ui_extractiondialog.h"
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
class ExtractionDialogUI: public QFrame, public Ui::ExtractionDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExtractionDialogUI(QWidget *parent = 0)
|
||||||
|
: QFrame(parent) {
|
||||||
|
setupUi(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ExtractionDialog::ExtractionDialog(QWidget *parent)
|
||||||
|
: KDirSelectDialog(KUrl(), false, parent)
|
||||||
|
{
|
||||||
|
m_ui = new ExtractionDialogUI(this);
|
||||||
|
|
||||||
|
mainWidget()->layout()->addWidget(m_ui);
|
||||||
|
setCaption(i18nc("@title:window", "Extract"));
|
||||||
|
m_ui->iconLabel->setPixmap(DesktopIcon(QLatin1String( "archive-extract" )));
|
||||||
|
|
||||||
|
m_ui->filesToExtractGroupBox->hide();
|
||||||
|
m_ui->allFilesButton->setChecked(true);
|
||||||
|
m_ui->extractAllLabel->show();
|
||||||
|
|
||||||
|
setSingleFolderArchive(false);
|
||||||
|
|
||||||
|
m_ui->autoSubfolders->hide();
|
||||||
|
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
|
connect(this, SIGNAL(finished(int)), SLOT(writeSettings()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::loadSettings()
|
||||||
|
{
|
||||||
|
setOpenDestinationFolderAfterExtraction(ArkSettings::openDestinationFolderAfterExtraction());
|
||||||
|
setCloseAfterExtraction(ArkSettings::closeAfterExtraction());
|
||||||
|
setPreservePaths(ArkSettings::preservePaths());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setSingleFolderArchive(bool value)
|
||||||
|
{
|
||||||
|
m_ui->singleFolderGroup->setChecked(!value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::batchModeOption()
|
||||||
|
{
|
||||||
|
m_ui->autoSubfolders->show();
|
||||||
|
m_ui->autoSubfolders->setEnabled(true);
|
||||||
|
m_ui->singleFolderGroup->hide();
|
||||||
|
m_ui->extractAllLabel->setText(i18n("Extract multiple archives"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::accept()
|
||||||
|
{
|
||||||
|
if (extractToSubfolder()) {
|
||||||
|
if (subfolder().contains(QLatin1String( "/" ))) {
|
||||||
|
KMessageBox::error(NULL, i18n("The subfolder name may not contain the character '/'."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString pathWithSubfolder = url().pathOrUrl(KUrl::AddTrailingSlash) + subfolder();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (KIO::NetAccess::exists(pathWithSubfolder, KIO::NetAccess::SourceSide, 0)) {
|
||||||
|
if (QFileInfo(pathWithSubfolder).isDir()) {
|
||||||
|
int overwrite = KMessageBox::questionYesNoCancel(0, i18nc("@info", "The folder <filename>%1</filename> already exists. Are you sure you want to extract here?", pathWithSubfolder), i18n("Folder exists"), KGuiItem(i18n("Extract here")), KGuiItem(i18n("Retry")), KGuiItem(i18n("Cancel")));
|
||||||
|
|
||||||
|
if (overwrite == KMessageBox::No) {
|
||||||
|
// The user clicked Retry.
|
||||||
|
continue;
|
||||||
|
} else if (overwrite == KMessageBox::Cancel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
KMessageBox::detailedError(0,
|
||||||
|
i18nc("@info", "The folder <filename>%1</filename> could not be created.", subfolder()),
|
||||||
|
i18nc("@info", "<filename>%1</filename> already exists, but is not a folder.", subfolder()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (!KIO::NetAccess::mkdir(pathWithSubfolder, 0)) {
|
||||||
|
KMessageBox::detailedError(0,
|
||||||
|
i18nc("@info", "The folder <filename>%1</filename> could not be created.", subfolder()),
|
||||||
|
i18n("Please check your permissions to create it."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KDirSelectDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setSubfolder(const QString& subfolder)
|
||||||
|
{
|
||||||
|
m_ui->subfolder->setText(subfolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExtractionDialog::subfolder() const
|
||||||
|
{
|
||||||
|
return m_ui->subfolder->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractionDialog::~ExtractionDialog()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
m_ui = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setShowSelectedFiles(bool value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
m_ui->filesToExtractGroupBox->show();
|
||||||
|
m_ui->selectedFilesButton->setChecked(true);
|
||||||
|
m_ui->extractAllLabel->hide();
|
||||||
|
} else {
|
||||||
|
m_ui->filesToExtractGroupBox->hide();
|
||||||
|
m_ui->selectedFilesButton->setChecked(false);
|
||||||
|
m_ui->extractAllLabel->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::extractAllFiles() const
|
||||||
|
{
|
||||||
|
return m_ui->allFilesButton->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setAutoSubfolder(bool value)
|
||||||
|
{
|
||||||
|
m_ui->autoSubfolders->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::autoSubfolders() const
|
||||||
|
{
|
||||||
|
return m_ui->autoSubfolders->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::extractToSubfolder() const
|
||||||
|
{
|
||||||
|
return m_ui->singleFolderGroup->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setOpenDestinationFolderAfterExtraction(bool value)
|
||||||
|
{
|
||||||
|
m_ui->openFolderCheckBox->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setCloseAfterExtraction(bool value)
|
||||||
|
{
|
||||||
|
m_ui->closeAfterExtraction->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::setPreservePaths(bool value)
|
||||||
|
{
|
||||||
|
m_ui->preservePaths->setChecked(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::preservePaths() const
|
||||||
|
{
|
||||||
|
return m_ui->preservePaths->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::openDestinationAfterExtraction() const
|
||||||
|
{
|
||||||
|
return m_ui->openFolderCheckBox->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExtractionDialog::closeAfterExtraction() const
|
||||||
|
{
|
||||||
|
return m_ui->closeAfterExtraction->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
KUrl ExtractionDialog::destinationDirectory() const
|
||||||
|
{
|
||||||
|
if (extractToSubfolder()) {
|
||||||
|
return QString(url().pathOrUrl(KUrl::AddTrailingSlash) + subfolder() + QLatin1Char( '/' ));
|
||||||
|
} else {
|
||||||
|
return url().pathOrUrl(KUrl::AddTrailingSlash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractionDialog::writeSettings()
|
||||||
|
{
|
||||||
|
ArkSettings::setOpenDestinationFolderAfterExtraction(openDestinationAfterExtraction());
|
||||||
|
ArkSettings::setCloseAfterExtraction(closeAfterExtraction());
|
||||||
|
ArkSettings::setPreservePaths(preservePaths());
|
||||||
|
ArkSettings::self()->writeConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "extractiondialog.moc"
|
78
ark/kerfuffle/extractiondialog.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXTRACTIONDIALOG_H
|
||||||
|
#define EXTRACTIONDIALOG_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <KDirSelectDialog>
|
||||||
|
|
||||||
|
#include <KDialog>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class KERFUFFLE_EXPORT ExtractionDialog : public KDirSelectDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ExtractionDialog(QWidget *parent = 0);
|
||||||
|
virtual ~ExtractionDialog();
|
||||||
|
|
||||||
|
void setShowSelectedFiles(bool);
|
||||||
|
void setSingleFolderArchive(bool);
|
||||||
|
void setPreservePaths(bool);
|
||||||
|
void batchModeOption();
|
||||||
|
void setOpenDestinationFolderAfterExtraction(bool);
|
||||||
|
void setCloseAfterExtraction(bool);
|
||||||
|
void setAutoSubfolder(bool value);
|
||||||
|
|
||||||
|
bool extractAllFiles() const;
|
||||||
|
bool openDestinationAfterExtraction() const;
|
||||||
|
bool closeAfterExtraction() const;
|
||||||
|
bool extractToSubfolder() const;
|
||||||
|
bool autoSubfolders() const;
|
||||||
|
bool preservePaths() const;
|
||||||
|
KUrl destinationDirectory() const;
|
||||||
|
QString subfolder() const;
|
||||||
|
virtual void accept();
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setSubfolder(const QString& subfolder);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void writeSettings();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadSettings();
|
||||||
|
|
||||||
|
class ExtractionDialogUI *m_ui;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EXTRACTIONDIALOG_H
|
220
ark/kerfuffle/extractiondialog.ui
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
<ui version="4.0" >
|
||||||
|
<author>Henrique Pinto <henrique.pinto@kdemail.net></author>
|
||||||
|
<class>ExtractionDialog</class>
|
||||||
|
<widget class="QWidget" name="ExtractionDialog" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>314</width>
|
||||||
|
<height>422</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Fixed" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Extraction Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" >
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="iconLabel" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Minimum" hsizetype="Fixed" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize" >
|
||||||
|
<size>
|
||||||
|
<width>256</width>
|
||||||
|
<height>256</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap" >
|
||||||
|
<pixmap>../../../../../kde-devel/ark-trunk/pics/ox32-action-ark_extract.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="extractAllLabel" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Maximum" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font" >
|
||||||
|
<font>
|
||||||
|
<pointsize>15</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Extract All Files</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="singleFolderGroup" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>&Extraction into subfolder:</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="KLineEdit" name="subfolder" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="showClearButton" stdset="0" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Expanding" hsizetype="Preferred" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title" >
|
||||||
|
<string>Options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout" >
|
||||||
|
<item row="6" column="0" >
|
||||||
|
<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="0" >
|
||||||
|
<widget class="QCheckBox" name="openFolderCheckBox" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Open &destination folder after extraction</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" >
|
||||||
|
<widget class="QCheckBox" name="closeAfterExtraction" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Close &Ark after extraction</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" >
|
||||||
|
<widget class="QCheckBox" name="preservePaths" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Preserve paths when extracting</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0" >
|
||||||
|
<widget class="QCheckBox" name="autoSubfolders" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Automatically create subfolders</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="filesToExtractGroupBox" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title" >
|
||||||
|
<string comment="@title:group">Extract</string>
|
||||||
|
</property>
|
||||||
|
<property name="flat" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checkable" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="selectedFilesButton" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Selected files only</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="allFilesButton" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>All &files</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>klineedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
346
ark/kerfuffle/jobs.cpp
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jobs.h"
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KLocale>
|
||||||
|
|
||||||
|
//#define DEBUG_RACECONDITION
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
class Job::Private : public QThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(Job *job, QObject *parent = 0)
|
||||||
|
: QThread(parent)
|
||||||
|
, q(job)
|
||||||
|
{
|
||||||
|
connect(q, SIGNAL(result(KJob*)), SLOT(quit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Job *q;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Job::Private::run()
|
||||||
|
{
|
||||||
|
q->doWork();
|
||||||
|
|
||||||
|
if (q->isRunning()) {
|
||||||
|
exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_RACECONDITION
|
||||||
|
QThread::sleep(2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Job::Job(ReadOnlyArchiveInterface *interface, QObject *parent)
|
||||||
|
: KJob(parent)
|
||||||
|
, m_archiveInterface(interface)
|
||||||
|
, m_isRunning(false)
|
||||||
|
, d(new Private(this))
|
||||||
|
{
|
||||||
|
static bool onlyOnce = false;
|
||||||
|
if (!onlyOnce) {
|
||||||
|
qRegisterMetaType<QPair<QString, QString> >("QPair<QString,QString>");
|
||||||
|
onlyOnce = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCapabilities(KJob::Killable);
|
||||||
|
}
|
||||||
|
|
||||||
|
Job::~Job()
|
||||||
|
{
|
||||||
|
if (d->isRunning()) {
|
||||||
|
d->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlyArchiveInterface *Job::archiveInterface()
|
||||||
|
{
|
||||||
|
return m_archiveInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Job::isRunning() const
|
||||||
|
{
|
||||||
|
return m_isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::start()
|
||||||
|
{
|
||||||
|
m_isRunning = true;
|
||||||
|
d->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::emitResult()
|
||||||
|
{
|
||||||
|
m_isRunning = false;
|
||||||
|
KJob::emitResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::connectToArchiveInterfaceSignals()
|
||||||
|
{
|
||||||
|
connect(archiveInterface(), SIGNAL(error(QString,QString)), SLOT(onError(QString,QString)));
|
||||||
|
connect(archiveInterface(), SIGNAL(entry(ArchiveEntry)), SLOT(onEntry(ArchiveEntry)));
|
||||||
|
connect(archiveInterface(), SIGNAL(entryRemoved(QString)), SLOT(onEntryRemoved(QString)));
|
||||||
|
connect(archiveInterface(), SIGNAL(progress(double)), SLOT(onProgress(double)));
|
||||||
|
connect(archiveInterface(), SIGNAL(info(QString)), SLOT(onInfo(QString)));
|
||||||
|
connect(archiveInterface(), SIGNAL(finished(bool)), SLOT(onFinished(bool)), Qt::DirectConnection);
|
||||||
|
connect(archiveInterface(), SIGNAL(userQuery(Query*)), SLOT(onUserQuery(Query*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onError(const QString & message, const QString & details)
|
||||||
|
{
|
||||||
|
Q_UNUSED(details)
|
||||||
|
|
||||||
|
setError(1);
|
||||||
|
setErrorText(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onEntry(const ArchiveEntry & archiveEntry)
|
||||||
|
{
|
||||||
|
emit newEntry(archiveEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onProgress(double value)
|
||||||
|
{
|
||||||
|
setPercent(static_cast<unsigned long>(100.0*value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onInfo(const QString& info)
|
||||||
|
{
|
||||||
|
emit infoMessage(this, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onEntryRemoved(const QString & path)
|
||||||
|
{
|
||||||
|
emit entryRemoved(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onFinished(bool result)
|
||||||
|
{
|
||||||
|
kDebug() << result;
|
||||||
|
|
||||||
|
archiveInterface()->disconnect(this);
|
||||||
|
|
||||||
|
emitResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Job::onUserQuery(Query *query)
|
||||||
|
{
|
||||||
|
emit userQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Job::doKill()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
bool ret = archiveInterface()->doKill();
|
||||||
|
if (!ret) {
|
||||||
|
kDebug() << "Killing does not seem to be supported here.";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListJob::ListJob(ReadOnlyArchiveInterface *interface, QObject *parent)
|
||||||
|
: Job(interface, parent)
|
||||||
|
, m_isSingleFolderArchive(true)
|
||||||
|
, m_isPasswordProtected(false)
|
||||||
|
, m_extractedFilesSize(0)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(newEntry(ArchiveEntry)),
|
||||||
|
this, SLOT(onNewEntry(ArchiveEntry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListJob::doWork()
|
||||||
|
{
|
||||||
|
emit description(this, i18n("Loading archive..."));
|
||||||
|
connectToArchiveInterfaceSignals();
|
||||||
|
bool ret = archiveInterface()->list();
|
||||||
|
|
||||||
|
if (!archiveInterface()->waitForFinishedSignal()) {
|
||||||
|
onFinished(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qlonglong ListJob::extractedFilesSize() const
|
||||||
|
{
|
||||||
|
return m_extractedFilesSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ListJob::isPasswordProtected() const
|
||||||
|
{
|
||||||
|
return m_isPasswordProtected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ListJob::isSingleFolderArchive() const
|
||||||
|
{
|
||||||
|
return m_isSingleFolderArchive;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListJob::onNewEntry(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
m_extractedFilesSize += entry[ Size ].toLongLong();
|
||||||
|
m_isPasswordProtected |= entry [ IsPasswordProtected ].toBool();
|
||||||
|
|
||||||
|
if (m_isSingleFolderArchive) {
|
||||||
|
const QString fileName(entry[FileName].toString());
|
||||||
|
const QString basePath(fileName.split(QLatin1Char( '/' )).at(0));
|
||||||
|
|
||||||
|
if (m_basePath.isEmpty()) {
|
||||||
|
m_basePath = basePath;
|
||||||
|
m_subfolderName = basePath;
|
||||||
|
} else {
|
||||||
|
if (m_basePath != basePath) {
|
||||||
|
m_isSingleFolderArchive = false;
|
||||||
|
m_subfolderName.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ListJob::subfolderName() const
|
||||||
|
{
|
||||||
|
return m_subfolderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob::ExtractJob(const QVariantList& files, const QString& destinationDir, ExtractionOptions options, ReadOnlyArchiveInterface *interface, QObject *parent)
|
||||||
|
: Job(interface, parent)
|
||||||
|
, m_files(files)
|
||||||
|
, m_destinationDir(destinationDir)
|
||||||
|
, m_options(options)
|
||||||
|
{
|
||||||
|
setDefaultOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractJob::doWork()
|
||||||
|
{
|
||||||
|
QString desc;
|
||||||
|
if (m_files.count() == 0) {
|
||||||
|
desc = i18n("Extracting all files");
|
||||||
|
} else {
|
||||||
|
desc = i18np("Extracting one file", "Extracting %1 files", m_files.count());
|
||||||
|
}
|
||||||
|
emit description(this, desc);
|
||||||
|
|
||||||
|
connectToArchiveInterfaceSignals();
|
||||||
|
|
||||||
|
kDebug() << "Starting extraction with selected files:"
|
||||||
|
<< m_files
|
||||||
|
<< "Destination dir:" << m_destinationDir
|
||||||
|
<< "Options:" << m_options;
|
||||||
|
|
||||||
|
bool ret = archiveInterface()->copyFiles(m_files, m_destinationDir, m_options);
|
||||||
|
|
||||||
|
if (!archiveInterface()->waitForFinishedSignal()) {
|
||||||
|
onFinished(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractJob::setDefaultOptions()
|
||||||
|
{
|
||||||
|
ExtractionOptions defaultOptions;
|
||||||
|
|
||||||
|
defaultOptions[QLatin1String("PreservePaths")] = false;
|
||||||
|
|
||||||
|
ExtractionOptions::const_iterator it = defaultOptions.constBegin();
|
||||||
|
for (; it != defaultOptions.constEnd(); ++it) {
|
||||||
|
if (!m_options.contains(it.key())) {
|
||||||
|
m_options[it.key()] = it.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExtractJob::destinationDirectory() const
|
||||||
|
{
|
||||||
|
return m_destinationDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractionOptions ExtractJob::extractionOptions() const
|
||||||
|
{
|
||||||
|
return m_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddJob::AddJob(const QStringList& files, const CompressionOptions& options , ReadWriteArchiveInterface *interface, QObject *parent)
|
||||||
|
: Job(interface, parent)
|
||||||
|
, m_files(files)
|
||||||
|
, m_options(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddJob::doWork()
|
||||||
|
{
|
||||||
|
emit description(this, i18np("Adding a file", "Adding %1 files", m_files.count()));
|
||||||
|
|
||||||
|
ReadWriteArchiveInterface *m_writeInterface =
|
||||||
|
qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());
|
||||||
|
|
||||||
|
Q_ASSERT(m_writeInterface);
|
||||||
|
|
||||||
|
connectToArchiveInterfaceSignals();
|
||||||
|
bool ret = m_writeInterface->addFiles(m_files, m_options);
|
||||||
|
|
||||||
|
if (!archiveInterface()->waitForFinishedSignal()) {
|
||||||
|
onFinished(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteJob::DeleteJob(const QVariantList& files, ReadWriteArchiveInterface *interface, QObject *parent)
|
||||||
|
: Job(interface, parent)
|
||||||
|
, m_files(files)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteJob::doWork()
|
||||||
|
{
|
||||||
|
emit description(this, i18np("Deleting a file from the archive", "Deleting %1 files", m_files.count()));
|
||||||
|
|
||||||
|
ReadWriteArchiveInterface *m_writeInterface =
|
||||||
|
qobject_cast<ReadWriteArchiveInterface*>(archiveInterface());
|
||||||
|
|
||||||
|
Q_ASSERT(m_writeInterface);
|
||||||
|
|
||||||
|
connectToArchiveInterfaceSignals();
|
||||||
|
int ret = m_writeInterface->deleteFiles(m_files);
|
||||||
|
|
||||||
|
if (!archiveInterface()->waitForFinishedSignal()) {
|
||||||
|
onFinished(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kerfuffle
|
||||||
|
|
||||||
|
#include "jobs.moc"
|
171
ark/kerfuffle/jobs.h
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (c) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JOBS_H
|
||||||
|
#define JOBS_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
#include "archiveinterface.h"
|
||||||
|
#include "archive.h"
|
||||||
|
#include "queries.h"
|
||||||
|
|
||||||
|
#include <KJob>
|
||||||
|
#include <QList>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
class ThreadExecution;
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT Job : public KJob
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
void start();
|
||||||
|
|
||||||
|
bool isRunning() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Job(ReadOnlyArchiveInterface *interface, QObject *parent = 0);
|
||||||
|
virtual ~Job();
|
||||||
|
virtual bool doKill();
|
||||||
|
virtual void emitResult();
|
||||||
|
|
||||||
|
ReadOnlyArchiveInterface *archiveInterface();
|
||||||
|
|
||||||
|
void connectToArchiveInterfaceSignals();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void doWork() = 0;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void onError(const QString &message, const QString &details);
|
||||||
|
virtual void onInfo(const QString &info);
|
||||||
|
virtual void onEntry(const ArchiveEntry &archiveEntry);
|
||||||
|
virtual void onProgress(double progress);
|
||||||
|
virtual void onEntryRemoved(const QString &path);
|
||||||
|
virtual void onFinished(bool result);
|
||||||
|
virtual void onUserQuery(Query *query);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void entryRemoved(const QString & entry);
|
||||||
|
void error(const QString& errorMessage, const QString& details);
|
||||||
|
void newEntry(const ArchiveEntry &);
|
||||||
|
void userQuery(Kerfuffle::Query*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReadOnlyArchiveInterface *m_archiveInterface;
|
||||||
|
|
||||||
|
bool m_isRunning;
|
||||||
|
|
||||||
|
class Private;
|
||||||
|
Private * const d;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT ListJob : public Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ListJob(ReadOnlyArchiveInterface *interface, QObject *parent = 0);
|
||||||
|
|
||||||
|
qlonglong extractedFilesSize() const;
|
||||||
|
bool isPasswordProtected() const;
|
||||||
|
bool isSingleFolderArchive() const;
|
||||||
|
QString subfolderName() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void doWork();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isSingleFolderArchive;
|
||||||
|
bool m_isPasswordProtected;
|
||||||
|
QString m_subfolderName;
|
||||||
|
QString m_basePath;
|
||||||
|
qlonglong m_extractedFilesSize;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onNewEntry(const ArchiveEntry&);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT ExtractJob : public Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ExtractJob(const QVariantList& files, const QString& destinationDir, ExtractionOptions options, ReadOnlyArchiveInterface *interface, QObject *parent = 0);
|
||||||
|
|
||||||
|
QString destinationDirectory() const;
|
||||||
|
ExtractionOptions extractionOptions() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void doWork();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO: Maybe this should be a method if ExtractionOptions were a class?
|
||||||
|
void setDefaultOptions();
|
||||||
|
|
||||||
|
QVariantList m_files;
|
||||||
|
QString m_destinationDir;
|
||||||
|
ExtractionOptions m_options;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT AddJob : public Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddJob(const QStringList& files, const CompressionOptions& options, ReadWriteArchiveInterface *interface, QObject *parent = 0);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void doWork();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_files;
|
||||||
|
CompressionOptions m_options;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT DeleteJob : public Job
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DeleteJob(const QVariantList& files, ReadWriteArchiveInterface *interface, QObject *parent = 0);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void doWork();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVariantList m_files;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kerfuffle
|
||||||
|
|
||||||
|
#endif // JOBS_H
|
74
ark/kerfuffle/kerfufflePlugin.desktop
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=ServiceType
|
||||||
|
X-KDE-ServiceType=Kerfuffle/Plugin
|
||||||
|
Comment=Plugin for handling of archive formats for the Kerfuffle library
|
||||||
|
Comment[ar]=ملحق للتحكم بهيئات الأرشيف لمكتبة Kerfuffle
|
||||||
|
Comment[ast]=Aplicación pa remanar los formatos de ficheru de la llibrería Kerfuffle
|
||||||
|
Comment[bg]=Приствка за работа с архиви за Kerfuffle
|
||||||
|
Comment[bs]=Priključak za rukovanje formatima arhiva za biblioteku Kerfafl
|
||||||
|
Comment[ca]=Connector per gestionar els formats d'arxiu per la biblioteca Kerfuffle
|
||||||
|
Comment[ca@valencia]=Connector per gestionar els formats d'arxiu per la biblioteca Kerfuffle
|
||||||
|
Comment[cs]=Modul pro správu formátů archivů pro knihovnu Kerfuffle
|
||||||
|
Comment[da]=Plugin til håndtering af arkivformater til Kerfuffle-biblioteket
|
||||||
|
Comment[de]=Modul zum Umgang mit Archivformaten der Kerfuffle-Bibliothek
|
||||||
|
Comment[el]=Πρόσθετο χειρισμού μορφών αρχειοθήκης για τη βιβλιοθήκη Kerfuffle
|
||||||
|
Comment[en_GB]=Plugin for handling of archive formats for the Kerfuffle library
|
||||||
|
Comment[es]=Complemento para manejar formatos de archivo de la biblioteca Kerfuffle
|
||||||
|
Comment[et]=Kerfuffle'i teegi arhiivifailide haldamise plugin
|
||||||
|
Comment[eu]=Kerfuffle liburutegiaren artxibo-formatuak erabiltzeko plugina
|
||||||
|
Comment[fi]=Kerfuffle-kirjaston pakettimuotojen tuki
|
||||||
|
Comment[fr]=Module externe de gestion des formats d'archives pour la bibliothèque « Kerfuffle »
|
||||||
|
Comment[ga]=Breiseán a láimhseálann formáidí cartlainne thar ceann na leabharlainne Kerfuffle
|
||||||
|
Comment[gl]=Extensión da biblioteca Kerfuffle para manexar formatos de arquivo
|
||||||
|
Comment[he]=תוסף לניהול פורמטי ארכיונים לספריית Kerfuffle
|
||||||
|
Comment[hne]=करफुफल लाइब्रेरी बर अभिलेख फारमेट हेंडल करे बर प्लगइन
|
||||||
|
Comment[hr]=Priključak za upravljanje arhivnim formatima za biblioteku Kerfuffle
|
||||||
|
Comment[hu]=Archívumkezelő modul a Kerfuffle programkönyvtárhoz
|
||||||
|
Comment[ia]=Plugin per manear formatos de archivo per le libreria Kerfuffle
|
||||||
|
Comment[id]=Pengaya untuk menangani format arsip pustaka Kerfuffle
|
||||||
|
Comment[it]=Estensione per gestire formati di archivio per la libreria Kerfuffle
|
||||||
|
Comment[ja]=Kerfuffle ライブラリのアーカイブ形式を扱うプラグイン
|
||||||
|
Comment[kk]=Kerfuffle жиын файлға арналған архив пішіндерімен айналасу плагині
|
||||||
|
Comment[km]=កម្មវិធីជំនួយសម្រាប់គ្រប់គ្រងទ្រង់ទ្រាយប័ណ្ណសារសម្រាប់បណ្ណាល័យ Kerfuffle
|
||||||
|
Comment[ko]=Kerfuffle 라이브러리를 위한 압축 파일 플러그인
|
||||||
|
Comment[lt]=Kerfuffle bibliotekos archyvų formatų palaikymo priedas
|
||||||
|
Comment[lv]=Arhīva failu tipu izmantošanas spraudnis Kerfuffle bibliotēkai.
|
||||||
|
Comment[mr]=कर्फफल लायब्ररी करिताचे संग्रह प्रकार हाताळणारे प्लगइन
|
||||||
|
Comment[nb]=Programtillegg som håndterer arkivformater, for Kerfuffle-biblioteket
|
||||||
|
Comment[nds]=Archievformaten-Moduul för de Kerfuffle-Bibliotheek
|
||||||
|
Comment[nl]=Plug-in voor het afhandelen van archiefformaten voor de Kerfuffle-bibliotheek
|
||||||
|
Comment[nn]=Programtillegg som handsamar arkivformat for Kerfuffle-biblioteket
|
||||||
|
Comment[pl]=Wtyczka do obsługi formatów archiwów w bibliotece Kerfuffle
|
||||||
|
Comment[pt]='Plugin' para lidar com os formatos de pacotes da biblioteca Kerfuffle
|
||||||
|
Comment[pt_BR]=Plugin para manipulação de formatos de arquivo, para a biblioteca Kerfuffle
|
||||||
|
Comment[ro]=Modul pentru pentru mînuirea formatelor de arhive pentru biblioteca Kerfuffle
|
||||||
|
Comment[ru]=Расширение для поддержки архивов с помощью библиотеки Kerfuffle
|
||||||
|
Comment[sk]=Modul pre spracovanie formátov archívov pre knižnicu Kerfuffle
|
||||||
|
Comment[sl]=Vstavek za ravnanje z arhivi za knjižnico Kerfuffle
|
||||||
|
Comment[sq]=Plugin që merret me formatet e arkivave për librarinë Kerfuffle
|
||||||
|
Comment[sr]=Прикључак за руковање форматима архива за библиотеку Керфафл
|
||||||
|
Comment[sr@ijekavian]=Прикључак за руковање форматима архива за библиотеку Керфафл
|
||||||
|
Comment[sr@ijekavianlatin]=Priključak za rukovanje formatima arhiva za biblioteku Kerfuffle
|
||||||
|
Comment[sr@latin]=Priključak za rukovanje formatima arhiva za biblioteku Kerfuffle
|
||||||
|
Comment[sv]=Insticksprogram för hantering av arkivformat för Kerfuffle-biblioteket
|
||||||
|
Comment[ta]=கெர்ஃபஃபில் ஃ நூலகத்துக்கு காப்பக வடிவமைப்பை கையாள சொருகிகள்
|
||||||
|
Comment[th]=ส่วนเสริมของไลบรารี Kerfuffle สำหรับจัดการแฟ้มจัดเก็บแบบต่าง ๆ
|
||||||
|
Comment[tr]=Kerfuffle kitaplığı için arşiv biçimleri eklentileri
|
||||||
|
Comment[uk]=Додаток для роботи з форматами архівів для бібліотеки Kerfuffle
|
||||||
|
Comment[x-test]=xxPlugin for handling of archive formats for the Kerfuffle libraryxx
|
||||||
|
Comment[zh_CN]=Kerfuffle 库的压缩归档格式处理插件
|
||||||
|
Comment[zh_TW]=處理 Kerfuffle 函式庫壓縮格式的外掛程式
|
||||||
|
|
||||||
|
# Priority. The greater the better.
|
||||||
|
[PropertyDef::X-KDE-Priority]
|
||||||
|
Type=int
|
||||||
|
|
||||||
|
# Revision of the plugin API.
|
||||||
|
[PropertyDef::X-KDE-Kerfuffle-APIRevision]
|
||||||
|
Type=int
|
||||||
|
|
||||||
|
# Is the plugin read-write or not? (i.e., can it create archives?)
|
||||||
|
[PropertyDef::X-KDE-Kerfuffle-ReadWrite]
|
||||||
|
Type=bool
|
||||||
|
|
||||||
|
|
53
ark/kerfuffle/kerfuffle_export.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 David Faure <faure@kde.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KERFUFFLE_EXPORT_H
|
||||||
|
#define KERFUFFLE_EXPORT_H
|
||||||
|
|
||||||
|
/* needed for KDE_EXPORT and KDE_IMPORT macros */
|
||||||
|
#include <kdemacros.h>
|
||||||
|
#include <kpluginfactory.h>
|
||||||
|
|
||||||
|
#ifndef KERFUFFLE_EXPORT
|
||||||
|
# if defined(MAKE_KERFUFFLE_LIB)
|
||||||
|
/* We are building this library */
|
||||||
|
# define KERFUFFLE_EXPORT KDE_EXPORT
|
||||||
|
# else
|
||||||
|
/* We are using this library */
|
||||||
|
# define KERFUFFLE_EXPORT KDE_IMPORT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
# ifndef KERFUFFLE_EXPORT_DEPRECATED
|
||||||
|
# define KERFUFFLE_EXPORT_DEPRECATED KDE_DEPRECATED KERFUFFLE_EXPORT
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#define KERFUFFLE_EXPORT_PLUGIN(p) \
|
||||||
|
K_PLUGIN_FACTORY( ArkPluginFactory, registerPlugin< p >(); ) \
|
||||||
|
K_EXPORT_PLUGIN( ArkPluginFactory("p") )
|
||||||
|
|
||||||
|
#endif
|
204
ark/kerfuffle/queries.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "queries.h"
|
||||||
|
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KPasswordDialog>
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kio/renamedialog.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
Query::Query()
|
||||||
|
{
|
||||||
|
m_responseMutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Query::response()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::waitForResponse()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
//if there is no response set yet, wait
|
||||||
|
if (!m_data.contains(QLatin1String("response"))) {
|
||||||
|
m_responseCondition.wait(&m_responseMutex);
|
||||||
|
}
|
||||||
|
m_responseMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Query::setResponse(QVariant response)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
m_data[QLatin1String( "response" )] = response;
|
||||||
|
m_responseCondition.wakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
OverwriteQuery::OverwriteQuery(const QString &filename) :
|
||||||
|
m_noRenameMode(false),
|
||||||
|
m_multiMode(true)
|
||||||
|
{
|
||||||
|
m_data[QLatin1String( "filename" )] = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverwriteQuery::execute()
|
||||||
|
{
|
||||||
|
// If we are being called from the KPart, the cursor is probably Qt::WaitCursor
|
||||||
|
// at the moment (#231974)
|
||||||
|
QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
|
||||||
|
|
||||||
|
KIO::RenameDialog_Mode mode = (KIO::RenameDialog_Mode)(KIO::M_OVERWRITE | KIO::M_SKIP);
|
||||||
|
if (m_noRenameMode) {
|
||||||
|
mode = (KIO::RenameDialog_Mode)(mode | KIO::M_NORENAME);
|
||||||
|
}
|
||||||
|
if (m_multiMode) {
|
||||||
|
mode = (KIO::RenameDialog_Mode)(mode | KIO::M_MULTI);
|
||||||
|
}
|
||||||
|
|
||||||
|
KUrl sourceUrl(m_data.value(QLatin1String( "filename" )).toString());
|
||||||
|
KUrl destUrl(m_data.value(QLatin1String( "filename" )).toString());
|
||||||
|
sourceUrl.cleanPath();
|
||||||
|
destUrl.cleanPath();
|
||||||
|
|
||||||
|
QWeakPointer<KIO::RenameDialog> dialog = new KIO::RenameDialog(
|
||||||
|
NULL,
|
||||||
|
i18n("File already exists"),
|
||||||
|
sourceUrl,
|
||||||
|
destUrl,
|
||||||
|
mode);
|
||||||
|
dialog.data()->exec();
|
||||||
|
|
||||||
|
m_data[QLatin1String("newFilename")] = dialog.data()->newDestUrl().pathOrUrl();
|
||||||
|
|
||||||
|
setResponse(dialog.data()->result());
|
||||||
|
|
||||||
|
delete dialog.data();
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::responseCancelled()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_CANCEL;
|
||||||
|
}
|
||||||
|
bool OverwriteQuery::responseOverwriteAll()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_OVERWRITE_ALL;
|
||||||
|
}
|
||||||
|
bool OverwriteQuery::responseOverwrite()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_OVERWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::responseRename()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_RENAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::responseSkip()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::responseAutoSkip()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "response" )).toInt() == KIO::R_AUTO_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OverwriteQuery::newFilename()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "newFilename" )).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverwriteQuery::setNoRenameMode(bool enableNoRenameMode)
|
||||||
|
{
|
||||||
|
m_noRenameMode = enableNoRenameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::noRenameMode()
|
||||||
|
{
|
||||||
|
return m_noRenameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverwriteQuery::setMultiMode(bool enableMultiMode)
|
||||||
|
{
|
||||||
|
m_multiMode = enableMultiMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverwriteQuery::multiMode()
|
||||||
|
{
|
||||||
|
return m_multiMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
PasswordNeededQuery::PasswordNeededQuery(const QString& archiveFilename, bool incorrectTryAgain)
|
||||||
|
{
|
||||||
|
m_data[QLatin1String( "archiveFilename" )] = archiveFilename;
|
||||||
|
m_data[QLatin1String( "incorrectTryAgain" )] = incorrectTryAgain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PasswordNeededQuery::execute()
|
||||||
|
{
|
||||||
|
// If we are being called from the KPart, the cursor is probably Qt::WaitCursor
|
||||||
|
// at the moment (#231974)
|
||||||
|
QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
|
||||||
|
|
||||||
|
QWeakPointer<KPasswordDialog> dlg = new KPasswordDialog;
|
||||||
|
dlg.data()->setPrompt(i18nc("@info", "The archive <filename>%1</filename> is password protected. Please enter the password to extract the file.", m_data.value(QLatin1String( "archiveFilename" )).toString()));
|
||||||
|
|
||||||
|
if (m_data.value(QLatin1String("incorrectTryAgain")).toBool()) {
|
||||||
|
dlg.data()->showErrorMessage(i18n("Incorrect password, please try again."), KPasswordDialog::PasswordError);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool notCancelled = dlg.data()->exec();
|
||||||
|
const QString password = dlg.data()->password();
|
||||||
|
|
||||||
|
m_data[QLatin1String("password")] = password;
|
||||||
|
setResponse(notCancelled && !password.isEmpty());
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
||||||
|
delete dlg.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PasswordNeededQuery::password()
|
||||||
|
{
|
||||||
|
return m_data.value(QLatin1String( "password" )).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PasswordNeededQuery::responseCancelled()
|
||||||
|
{
|
||||||
|
return !m_data.value(QLatin1String( "response" )).toBool();
|
||||||
|
}
|
||||||
|
}
|
111
ark/kerfuffle/queries.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QUERIES_H
|
||||||
|
#define QUERIES_H
|
||||||
|
|
||||||
|
#include "kerfuffle_export.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef QHash<QString, QVariant> QueryData;
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT Query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Execute the response. Will happen in the GUI thread, so it's
|
||||||
|
* safe to use widgets/gui elements here. Must call setResponse
|
||||||
|
* when done.
|
||||||
|
*/
|
||||||
|
virtual void execute() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will block until the response have been set
|
||||||
|
*/
|
||||||
|
void waitForResponse();
|
||||||
|
|
||||||
|
QVariant response();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Protected constructor
|
||||||
|
*/
|
||||||
|
Query();
|
||||||
|
virtual ~Query() {}
|
||||||
|
|
||||||
|
void setResponse(QVariant response);
|
||||||
|
|
||||||
|
QueryData m_data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWaitCondition m_responseCondition;
|
||||||
|
QMutex m_responseMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT OverwriteQuery : public Query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OverwriteQuery(const QString& filename);
|
||||||
|
void execute();
|
||||||
|
bool responseCancelled();
|
||||||
|
bool responseOverwriteAll();
|
||||||
|
bool responseOverwrite();
|
||||||
|
bool responseRename();
|
||||||
|
bool responseSkip();
|
||||||
|
bool responseAutoSkip();
|
||||||
|
QString newFilename();
|
||||||
|
|
||||||
|
void setNoRenameMode(bool enableNoRenameMode);
|
||||||
|
bool noRenameMode();
|
||||||
|
void setMultiMode(bool enableMultiMode);
|
||||||
|
bool multiMode();
|
||||||
|
private:
|
||||||
|
bool m_noRenameMode;
|
||||||
|
bool m_multiMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KERFUFFLE_EXPORT PasswordNeededQuery : public Query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PasswordNeededQuery(const QString& archiveFilename, bool incorrectTryAgain = false);
|
||||||
|
void execute();
|
||||||
|
|
||||||
|
bool responseCancelled();
|
||||||
|
QString password();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ifndef QUERIES_H */
|
7
ark/kerfuffle/settings.kcfgc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
File=ark.kcfg
|
||||||
|
ClassName=ArkSettings
|
||||||
|
Singleton=true
|
||||||
|
Mutators=true
|
||||||
|
SetUserTexts=true
|
||||||
|
IncludeFiles=\"kerfuffle/kerfuffle_export.h\"
|
||||||
|
Visibility=KERFUFFLE_EXPORT
|
21
ark/kerfuffle/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
include_directories(${KERFUFFLE_QJSON_INCLUDE_DIR})
|
||||||
|
|
||||||
|
set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
set(JSONINTERFACE_SOURCES
|
||||||
|
jsonarchiveinterface.cpp
|
||||||
|
jsonparser.cpp
|
||||||
|
)
|
||||||
|
kde4_add_library(jsoninterface STATIC ${JSONINTERFACE_SOURCES})
|
||||||
|
|
||||||
|
macro(KERFUFFLE_UNIT_TESTS)
|
||||||
|
foreach(_testname ${ARGN})
|
||||||
|
kde4_add_unit_test(${_testname} NOGUI ${_testname}.cpp)
|
||||||
|
target_link_libraries(${_testname} jsoninterface kerfuffle ${KDE4_KDEUI_LIBS} ${QT_QTTEST_LIBRARY} ${KERFUFFLE_QJSON_LIBRARIES})
|
||||||
|
endforeach(_testname)
|
||||||
|
endmacro(KERFUFFLE_UNIT_TESTS)
|
||||||
|
|
||||||
|
KERFUFFLE_UNIT_TESTS(
|
||||||
|
archivetest
|
||||||
|
jobstest
|
||||||
|
)
|
76
ark/kerfuffle/tests/archivetest.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
#include <qtest_kde.h>
|
||||||
|
|
||||||
|
class ArchiveTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void testFileName();
|
||||||
|
void testIsPasswordProtected();
|
||||||
|
void testOpenNonExistentFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_KDEMAIN_CORE(ArchiveTest)
|
||||||
|
|
||||||
|
void ArchiveTest::testFileName()
|
||||||
|
{
|
||||||
|
Kerfuffle::Archive *archive = Kerfuffle::Archive::create(QLatin1String("/tmp/foo.tar.gz"), this);
|
||||||
|
|
||||||
|
if (!archive) {
|
||||||
|
QSKIP("There is no plugin to handle tar.gz files. Skipping test.", SkipSingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(archive->fileName(), QLatin1String("/tmp/foo.tar.gz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveTest::testIsPasswordProtected()
|
||||||
|
{
|
||||||
|
Kerfuffle::Archive *archive;
|
||||||
|
|
||||||
|
archive = Kerfuffle::Archive::create(QLatin1String(KDESRCDIR "data/archivetest_encrypted.zip"), this);
|
||||||
|
if (!archive) {
|
||||||
|
QSKIP("There is no plugin to handle zip files. Skipping test.", SkipSingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVERIFY(archive->isPasswordProtected());
|
||||||
|
|
||||||
|
archive->deleteLater();
|
||||||
|
|
||||||
|
archive = Kerfuffle::Archive::create(QLatin1String(KDESRCDIR "data/archivetest_unencrypted.zip"), this);
|
||||||
|
|
||||||
|
QVERIFY(!archive->isPasswordProtected());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveTest::testOpenNonExistentFile()
|
||||||
|
{
|
||||||
|
QSKIP("How should we deal with files that do not exist? Should factory() return NULL?", SkipSingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "archivetest.moc"
|
20
ark/kerfuffle/tests/data/archive-deepsinglehierarchy.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/b.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/aDirInside/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/aDirInside/anotherDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/aDirInside/anotherDir/file.txt"
|
||||||
|
}
|
||||||
|
]
|
16
ark/kerfuffle/tests/data/archive-multiplefolders.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/b.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "anotherDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "anotherDir/file.txt"
|
||||||
|
}
|
||||||
|
]
|
8
ark/kerfuffle/tests/data/archive-nodir-manyfiles.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "a.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "file.txt"
|
||||||
|
}
|
||||||
|
]
|
9
ark/kerfuffle/tests/data/archive-onetopfolder.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/b.txt"
|
||||||
|
}
|
||||||
|
]
|
13
ark/kerfuffle/tests/data/archive-password.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "foo.txt",
|
||||||
|
"IsPasswordProtected": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "bar.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDirectory/",
|
||||||
|
"IsDirectory": true
|
||||||
|
}
|
||||||
|
]
|
5
ark/kerfuffle/tests/data/archive-singlefile.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "a.txt"
|
||||||
|
}
|
||||||
|
]
|
16
ark/kerfuffle/tests/data/archive-unorderedsinglefolder.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "aDir/anotherDir/bar.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/foo.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/anotherDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
}
|
||||||
|
]
|
15
ark/kerfuffle/tests/data/archive001.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "a.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/b.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "c.txt"
|
||||||
|
}
|
||||||
|
]
|
18
ark/kerfuffle/tests/data/archive002.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"FileName": "a.txt",
|
||||||
|
"Size": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/",
|
||||||
|
"IsDirectory": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "aDir/b.txt",
|
||||||
|
"Size": 954
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileName": "c.txt",
|
||||||
|
"Size": 45000
|
||||||
|
}
|
||||||
|
]
|
BIN
ark/kerfuffle/tests/data/archivetest_encrypted.zip
Normal file
BIN
ark/kerfuffle/tests/data/archivetest_unencrypted.zip
Normal file
BIN
ark/kerfuffle/tests/data/simplearchive.tar.gz
Normal file
366
ark/kerfuffle/tests/jobstest.cpp
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kerfuffle/jobs.h"
|
||||||
|
|
||||||
|
#include "jsonarchiveinterface.h"
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <kglobal.h>
|
||||||
|
#include <qtest_kde.h>
|
||||||
|
|
||||||
|
#include <qeventloop.h>
|
||||||
|
#include <qsignalspy.h>
|
||||||
|
|
||||||
|
using Kerfuffle::ArchiveEntry;
|
||||||
|
|
||||||
|
class JobsTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
JobsTest();
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void slotNewEntry(const ArchiveEntry& entry);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
// ListJob-related tests
|
||||||
|
void testExtractedFilesSize();
|
||||||
|
void testIsPasswordProtected();
|
||||||
|
void testIsSingleFolderArchive();
|
||||||
|
void testListEntries();
|
||||||
|
|
||||||
|
// ExtractJob-related tests
|
||||||
|
void testExtractJobAccessors();
|
||||||
|
|
||||||
|
// DeleteJob-related tests
|
||||||
|
void testRemoveEntry();
|
||||||
|
|
||||||
|
// AddJob-related tests
|
||||||
|
void testAddEntry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSONArchiveInterface *createArchiveInterface(const QString& filePath);
|
||||||
|
QList<Kerfuffle::ArchiveEntry> listEntries(JSONArchiveInterface *iface);
|
||||||
|
void startAndWaitForResult(KJob *job);
|
||||||
|
|
||||||
|
QList<Kerfuffle::ArchiveEntry> m_entries;
|
||||||
|
QEventLoop m_eventLoop;
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_KDEMAIN_CORE(JobsTest)
|
||||||
|
|
||||||
|
JobsTest::JobsTest()
|
||||||
|
: QObject(0)
|
||||||
|
, m_eventLoop(this)
|
||||||
|
{
|
||||||
|
// Hackish way to make sure the i18n stuff
|
||||||
|
// is called from the main thread
|
||||||
|
KGlobal::locale();
|
||||||
|
|
||||||
|
qRegisterMetaType<ArchiveEntry>("ArchiveEntry");
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::init()
|
||||||
|
{
|
||||||
|
m_entries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArchiveInterface *JobsTest::createArchiveInterface(const QString& filePath)
|
||||||
|
{
|
||||||
|
QVariantList args;
|
||||||
|
args.append(filePath);
|
||||||
|
|
||||||
|
JSONArchiveInterface *iface = new JSONArchiveInterface(this, args);
|
||||||
|
if (!iface->open()) {
|
||||||
|
kDebug() << "Could not open" << filePath;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::startAndWaitForResult(KJob *job)
|
||||||
|
{
|
||||||
|
connect(job, SIGNAL(result(KJob*)), &m_eventLoop, SLOT(quit()));
|
||||||
|
job->start();
|
||||||
|
m_eventLoop.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testExtractedFilesSize()
|
||||||
|
{
|
||||||
|
Kerfuffle::ListJob *listJob;
|
||||||
|
|
||||||
|
JSONArchiveInterface *noSizeIface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
JSONArchiveInterface *sizeIface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive002.json"));
|
||||||
|
|
||||||
|
listJob = new Kerfuffle::ListJob(noSizeIface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
|
||||||
|
QCOMPARE(listJob->extractedFilesSize(), 0LL);
|
||||||
|
|
||||||
|
listJob = new Kerfuffle::ListJob(sizeIface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
|
||||||
|
QCOMPARE(listJob->extractedFilesSize(), 45959LL);
|
||||||
|
|
||||||
|
noSizeIface->deleteLater();
|
||||||
|
sizeIface->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testIsPasswordProtected()
|
||||||
|
{
|
||||||
|
Kerfuffle::ListJob *listJob;
|
||||||
|
|
||||||
|
JSONArchiveInterface *noPasswordIface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive002.json"));
|
||||||
|
JSONArchiveInterface *passwordIface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive-password.json"));
|
||||||
|
|
||||||
|
listJob = new Kerfuffle::ListJob(noPasswordIface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
|
||||||
|
QVERIFY(!listJob->isPasswordProtected());
|
||||||
|
|
||||||
|
listJob = new Kerfuffle::ListJob(passwordIface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
|
||||||
|
QVERIFY(listJob->isPasswordProtected());
|
||||||
|
|
||||||
|
noPasswordIface->deleteLater();
|
||||||
|
passwordIface->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testIsSingleFolderArchive()
|
||||||
|
{
|
||||||
|
JSONArchiveInterface *iface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
|
||||||
|
Kerfuffle::ListJob *listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(!listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QString());
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface(QLatin1String(KDESRCDIR "data/archive-singlefile.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QLatin1String("a.txt"));
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface(QLatin1String(KDESRCDIR "data/archive-onetopfolder.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QLatin1String("aDir"));
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface
|
||||||
|
(QLatin1String(KDESRCDIR "data/archive-multiplefolders.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(!listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QString());
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface
|
||||||
|
(QLatin1String(KDESRCDIR "data/archive-nodir-manyfiles.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(!listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QString());
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface
|
||||||
|
(QLatin1String(KDESRCDIR "data/archive-deepsinglehierarchy.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QLatin1String("aDir"));
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
iface = createArchiveInterface
|
||||||
|
(QLatin1String(KDESRCDIR "data/archive-unorderedsinglefolder.json"));
|
||||||
|
listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
listJob->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
QVERIFY(listJob->isSingleFolderArchive());
|
||||||
|
QCOMPARE(listJob->subfolderName(), QLatin1String("aDir"));
|
||||||
|
iface->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testListEntries()
|
||||||
|
{
|
||||||
|
JSONArchiveInterface *iface =
|
||||||
|
createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
|
||||||
|
QList<Kerfuffle::ArchiveEntry> archiveEntries(listEntries(iface));
|
||||||
|
|
||||||
|
QStringList entries;
|
||||||
|
entries.append(QLatin1String("a.txt"));
|
||||||
|
entries.append(QLatin1String("aDir/"));
|
||||||
|
entries.append(QLatin1String("aDir/b.txt"));
|
||||||
|
entries.append(QLatin1String("c.txt"));
|
||||||
|
|
||||||
|
QCOMPARE(entries.count(), archiveEntries.count());
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.count(); ++i) {
|
||||||
|
Kerfuffle::ArchiveEntry e(archiveEntries.at(i));
|
||||||
|
|
||||||
|
QCOMPARE(entries[i], e[Kerfuffle::FileName].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
iface->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::slotNewEntry(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
m_entries.append(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Kerfuffle::ArchiveEntry> JobsTest::listEntries(JSONArchiveInterface *iface)
|
||||||
|
{
|
||||||
|
m_entries.clear();
|
||||||
|
|
||||||
|
Kerfuffle::ListJob *listJob = new Kerfuffle::ListJob(iface, this);
|
||||||
|
connect(listJob, SIGNAL(newEntry(ArchiveEntry)),
|
||||||
|
SLOT(slotNewEntry(ArchiveEntry)));
|
||||||
|
|
||||||
|
startAndWaitForResult(listJob);
|
||||||
|
|
||||||
|
return m_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testExtractJobAccessors()
|
||||||
|
{
|
||||||
|
JSONArchiveInterface *iface = createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
Kerfuffle::ExtractJob *job =
|
||||||
|
new Kerfuffle::ExtractJob(QVariantList(), QLatin1String("/tmp/some-dir"),
|
||||||
|
Kerfuffle::ExtractionOptions(), iface, this);
|
||||||
|
Kerfuffle::ExtractionOptions defaultOptions;
|
||||||
|
defaultOptions[QLatin1String("PreservePaths")] = false;
|
||||||
|
|
||||||
|
QCOMPARE(job->destinationDirectory(), QLatin1String("/tmp/some-dir"));
|
||||||
|
QCOMPARE(job->extractionOptions(), defaultOptions);
|
||||||
|
|
||||||
|
job->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(job);
|
||||||
|
|
||||||
|
QCOMPARE(job->destinationDirectory(), QLatin1String("/tmp/some-dir"));
|
||||||
|
QCOMPARE(job->extractionOptions(), defaultOptions);
|
||||||
|
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
options[QLatin1String("PreservePaths")] = true;
|
||||||
|
options[QLatin1String("foo")] = QLatin1String("bar");
|
||||||
|
options[QLatin1String("pi")] = 3.14f;
|
||||||
|
|
||||||
|
job = new Kerfuffle::ExtractJob(QVariantList(), QLatin1String("/root"),
|
||||||
|
options, iface, this);
|
||||||
|
|
||||||
|
QCOMPARE(job->destinationDirectory(), QLatin1String("/root"));
|
||||||
|
QCOMPARE(job->extractionOptions(), options);
|
||||||
|
|
||||||
|
job->setAutoDelete(false);
|
||||||
|
startAndWaitForResult(job);
|
||||||
|
|
||||||
|
QCOMPARE(job->destinationDirectory(), QLatin1String("/root"));
|
||||||
|
QCOMPARE(job->extractionOptions(), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testRemoveEntry()
|
||||||
|
{
|
||||||
|
QVariantList filesToDelete;
|
||||||
|
JSONArchiveInterface *iface;
|
||||||
|
Kerfuffle::DeleteJob *deleteJob;
|
||||||
|
QStringList expectedEntries;
|
||||||
|
|
||||||
|
filesToDelete.append(QLatin1String("c.txt"));
|
||||||
|
iface = createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
deleteJob = new Kerfuffle::DeleteJob(filesToDelete, iface, this);
|
||||||
|
startAndWaitForResult(deleteJob);
|
||||||
|
QList<Kerfuffle::ArchiveEntry> archiveEntries(listEntries(iface));
|
||||||
|
expectedEntries.append(QLatin1String("a.txt"));
|
||||||
|
expectedEntries.append(QLatin1String("aDir/"));
|
||||||
|
expectedEntries.append(QLatin1String("aDir/b.txt"));
|
||||||
|
QCOMPARE(archiveEntries.count(), expectedEntries.count());
|
||||||
|
for (int i = 0; i < expectedEntries.count(); ++i) {
|
||||||
|
const Kerfuffle::ArchiveEntry e(archiveEntries.at(i));
|
||||||
|
QCOMPARE(expectedEntries[i], e[Kerfuffle::FileName].toString());
|
||||||
|
}
|
||||||
|
iface->deleteLater();
|
||||||
|
|
||||||
|
// TODO: test for errors
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobsTest::testAddEntry()
|
||||||
|
{
|
||||||
|
JSONArchiveInterface *iface = createArchiveInterface(QLatin1String(KDESRCDIR "data/archive001.json"));
|
||||||
|
|
||||||
|
QList<Kerfuffle::ArchiveEntry> archiveEntries = listEntries(iface);
|
||||||
|
QCOMPARE(archiveEntries.count(), 4);
|
||||||
|
|
||||||
|
QStringList newEntries = QStringList() << QLatin1String("foo");
|
||||||
|
|
||||||
|
Kerfuffle::AddJob *addJob =
|
||||||
|
new Kerfuffle::AddJob(newEntries, Kerfuffle::CompressionOptions(), iface, this);
|
||||||
|
startAndWaitForResult(addJob);
|
||||||
|
|
||||||
|
archiveEntries = listEntries(iface);
|
||||||
|
QCOMPARE(archiveEntries.count(), 5);
|
||||||
|
|
||||||
|
addJob = new Kerfuffle::AddJob(newEntries, Kerfuffle::CompressionOptions(), iface, this);
|
||||||
|
startAndWaitForResult(addJob);
|
||||||
|
|
||||||
|
archiveEntries = listEntries(iface);
|
||||||
|
QCOMPARE(archiveEntries.count(), 5);
|
||||||
|
|
||||||
|
newEntries = QStringList() << QLatin1String("bar") << QLatin1String("aDir/test.txt");
|
||||||
|
|
||||||
|
addJob = new Kerfuffle::AddJob(newEntries, Kerfuffle::CompressionOptions(), iface, this);
|
||||||
|
startAndWaitForResult(addJob);
|
||||||
|
|
||||||
|
archiveEntries = listEntries(iface);
|
||||||
|
QCOMPARE(archiveEntries.count(), 7);
|
||||||
|
|
||||||
|
iface->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "jobstest.moc"
|
109
ark/kerfuffle/tests/jsonarchiveinterface.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jsonarchiveinterface.h"
|
||||||
|
|
||||||
|
#include <kdebug.h>
|
||||||
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
|
#include <qfile.h>
|
||||||
|
|
||||||
|
JSONArchiveInterface::JSONArchiveInterface(QObject *parent, const QVariantList& args)
|
||||||
|
: Kerfuffle::ReadWriteArchiveInterface(parent, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArchiveInterface::~JSONArchiveInterface()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSONArchiveInterface::list()
|
||||||
|
{
|
||||||
|
JSONParser::JSONArchive::const_iterator it = m_archive.constBegin();
|
||||||
|
for (; it != m_archive.constEnd(); ++it) {
|
||||||
|
emit entry(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSONArchiveInterface::open()
|
||||||
|
{
|
||||||
|
QFile file(filename());
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_archive = JSONParser::parse(&file);
|
||||||
|
|
||||||
|
return !m_archive.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSONArchiveInterface::addFiles(const QStringList& files, const Kerfuffle::CompressionOptions& options)
|
||||||
|
{
|
||||||
|
Q_UNUSED(options)
|
||||||
|
|
||||||
|
foreach (const QString& file, files) {
|
||||||
|
if (m_archive.contains(file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::ArchiveEntry e;
|
||||||
|
e[Kerfuffle::FileName] = file;
|
||||||
|
|
||||||
|
m_archive[file] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSONArchiveInterface::copyFiles(const QList<QVariant>& files, const QString& destinationDirectory, Kerfuffle::ExtractionOptions options)
|
||||||
|
{
|
||||||
|
Q_UNUSED(files)
|
||||||
|
Q_UNUSED(destinationDirectory)
|
||||||
|
Q_UNUSED(options)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JSONArchiveInterface::deleteFiles(const QList<QVariant>& files)
|
||||||
|
{
|
||||||
|
foreach (const QVariant& file, files) {
|
||||||
|
const QString fileName = file.toString();
|
||||||
|
if (m_archive.contains(fileName)) {
|
||||||
|
m_archive.remove(fileName);
|
||||||
|
emit entryRemoved(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "jsonarchiveinterface.moc"
|
67
ark/kerfuffle/tests/jsonarchiveinterface.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JSONARCHIVEINTERFACE_H
|
||||||
|
#define JSONARCHIVEINTERFACE_H
|
||||||
|
|
||||||
|
#include "jsonparser.h"
|
||||||
|
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "kerfuffle/archiveinterface.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dummy archive interface used by our test cases.
|
||||||
|
*
|
||||||
|
* It reads a JSON file which defines the contents of the archive.
|
||||||
|
* For the file format description, see the documentation for @c JSONParser.
|
||||||
|
*
|
||||||
|
* The file's content is read to memory when open() is called and the archive
|
||||||
|
* is then closed. This means that this class never changes the file's content
|
||||||
|
* on disk, and entry addition or deletion do not change the original file.
|
||||||
|
*
|
||||||
|
* @sa JSONParser
|
||||||
|
*
|
||||||
|
* @author Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*/
|
||||||
|
class JSONArchiveInterface : public Kerfuffle::ReadWriteArchiveInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit JSONArchiveInterface(QObject *parent, const QVariantList& args);
|
||||||
|
virtual ~JSONArchiveInterface();
|
||||||
|
|
||||||
|
virtual bool list();
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual bool addFiles(const QStringList& files, const Kerfuffle::CompressionOptions& options);
|
||||||
|
virtual bool copyFiles(const QList<QVariant>& files, const QString& destinationDirectory, Kerfuffle::ExtractionOptions options);
|
||||||
|
virtual bool deleteFiles(const QList<QVariant>& files);
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSONParser::JSONArchive m_archive;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
133
ark/kerfuffle/tests/jsonparser.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jsonparser.h"
|
||||||
|
|
||||||
|
#include "kerfuffle/archiveinterface.h"
|
||||||
|
|
||||||
|
#include <KDE/KDebug>
|
||||||
|
|
||||||
|
#include <QtCore/QLatin1String>
|
||||||
|
|
||||||
|
#include <qjson/parser.h>
|
||||||
|
|
||||||
|
typedef QMap<QString, Kerfuffle::EntryMetaDataType> ArchiveProperties;
|
||||||
|
|
||||||
|
static ArchiveProperties archiveProperties()
|
||||||
|
{
|
||||||
|
static ArchiveProperties properties;
|
||||||
|
|
||||||
|
if (!properties.isEmpty()) {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties[QLatin1String("FileName")] = Kerfuffle::FileName;
|
||||||
|
properties[QLatin1String("InternalID")] = Kerfuffle::InternalID;
|
||||||
|
properties[QLatin1String("Permissions")] = Kerfuffle::Permissions;
|
||||||
|
properties[QLatin1String("Owner")] = Kerfuffle::Owner;
|
||||||
|
properties[QLatin1String("Group")] = Kerfuffle::Group;
|
||||||
|
properties[QLatin1String("Size")] = Kerfuffle::Size;
|
||||||
|
properties[QLatin1String("CompressedSize")] = Kerfuffle::CompressedSize;
|
||||||
|
properties[QLatin1String("Link")] = Kerfuffle::Link;
|
||||||
|
properties[QLatin1String("Ratio")] = Kerfuffle::Ratio;
|
||||||
|
properties[QLatin1String("CRC")] = Kerfuffle::CRC;
|
||||||
|
properties[QLatin1String("Method")] = Kerfuffle::Method;
|
||||||
|
properties[QLatin1String("Version")] = Kerfuffle::Version;
|
||||||
|
properties[QLatin1String("Timestamp")] = Kerfuffle::Timestamp;
|
||||||
|
properties[QLatin1String("IsDirectory")] = Kerfuffle::IsDirectory;
|
||||||
|
properties[QLatin1String("Comment")] = Kerfuffle::Comment;
|
||||||
|
properties[QLatin1String("IsPasswordProtected")] = Kerfuffle::IsPasswordProtected;
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONParser::JSONParser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONParser::~JSONParser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONParser::JSONArchive JSONParser::parse(const QString &json)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
QJson::Parser parser;
|
||||||
|
|
||||||
|
const QVariant result = parser.parse(json.toUtf8(), &ok);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
kDebug() << "Line" << parser.errorLine() << ":" << parser.errorString();
|
||||||
|
return JSONParser::JSONArchive();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createJSONArchive(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONParser::JSONArchive JSONParser::parse(QIODevice *json)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
QJson::Parser parser;
|
||||||
|
|
||||||
|
const QVariant result = parser.parse(json, &ok);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
kDebug() << "Line" << parser.errorLine() << ":" << parser.errorString();
|
||||||
|
return JSONParser::JSONArchive();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createJSONArchive(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONParser::JSONArchive JSONParser::createJSONArchive(const QVariant &json)
|
||||||
|
{
|
||||||
|
static const ArchiveProperties properties = archiveProperties();
|
||||||
|
|
||||||
|
JSONParser::JSONArchive archive;
|
||||||
|
|
||||||
|
foreach (const QVariant &entry, json.toList()) {
|
||||||
|
const QVariantMap entryMap = entry.toMap();
|
||||||
|
|
||||||
|
if (!entryMap.contains(QLatin1String("FileName"))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::ArchiveEntry archiveEntry;
|
||||||
|
|
||||||
|
QVariantMap::const_iterator entryIterator = entryMap.constBegin();
|
||||||
|
for (; entryIterator != entryMap.constEnd(); ++entryIterator) {
|
||||||
|
if (properties.contains(entryIterator.key())) {
|
||||||
|
archiveEntry[properties[entryIterator.key()]] = entryIterator.value();
|
||||||
|
} else {
|
||||||
|
kDebug() << entryIterator.key() << "is not a valid entry key";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString fileName = entryMap[QLatin1String("FileName")].toString();
|
||||||
|
archive[fileName] = archiveEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return archive;
|
||||||
|
}
|
82
ark/kerfuffle/tests/jsonparser.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011 Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JSONPARSER_H
|
||||||
|
#define JSONPARSER_H
|
||||||
|
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
#include <QtCore/QIODevice>
|
||||||
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QString>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple parser which reads JSON files and creates @c ArchiveEntry objects
|
||||||
|
* from it.
|
||||||
|
*
|
||||||
|
* The JSON file is expected to follow a specific format that describes an
|
||||||
|
* archive read by Kerfuffle.
|
||||||
|
*
|
||||||
|
* The format consists of a list of dictionaries whose keys are values from the
|
||||||
|
* EntryMetaDataType enum. The only required key for each entry is FileName;
|
||||||
|
* other values which are omitted for each entry are assumed to be 0 or false.
|
||||||
|
*
|
||||||
|
* Example file:
|
||||||
|
* @code
|
||||||
|
* [
|
||||||
|
* { "FileName": "foo", "IsPasswordProtected": true },
|
||||||
|
* { "FileName": "aDir/", "IsDirectory": true }
|
||||||
|
* ]
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @author Raphael Kubo da Costa <rakuco@FreeBSD.org>
|
||||||
|
*/
|
||||||
|
class JSONParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QMap<QString, Kerfuffle::ArchiveEntry> JSONArchive;
|
||||||
|
|
||||||
|
~JSONParser();
|
||||||
|
|
||||||
|
static JSONArchive parse(const QString &json);
|
||||||
|
static JSONArchive parse(QIODevice *json);
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSONParser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses each entry in the QVariant obtained from parsing a JSON file and
|
||||||
|
* creates a @c JSONArchive from them.
|
||||||
|
*
|
||||||
|
* If an entry does not have a "FileName" key, it is ignored. Keys which do
|
||||||
|
* not correspond to a value in the EntryMetaDataType enum are ignored.
|
||||||
|
*
|
||||||
|
* @return A new @c JSONArchive corresponding to the parsed JSON file. If a
|
||||||
|
* parsing error occurs, it is empty.
|
||||||
|
*/
|
||||||
|
static JSONArchive createJSONArchive(const QVariant &json);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JSONPARSER_H
|
30
ark/part/CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
set(arkpart_PART_SRCS
|
||||||
|
part.cpp
|
||||||
|
infopanel.cpp
|
||||||
|
arkviewer.cpp
|
||||||
|
archivemodel.cpp
|
||||||
|
archiveview.cpp
|
||||||
|
jobtracker.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
qt4_add_dbus_adaptor(arkpart_PART_SRCS dnddbusinterface.xml part.h Ark::Part)
|
||||||
|
|
||||||
|
kde4_add_ui_files(arkpart_PART_SRCS infopanel.ui )
|
||||||
|
kde4_add_ui_files(arkpart_PART_SRCS jobtracker.ui )
|
||||||
|
|
||||||
|
kde4_add_plugin(arkpart ${arkpart_PART_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(arkpart kerfuffle ${KDE4_KFILE_LIBS} ${KDE4_KPARTS_LIBS} ${KDE4_KDEUI_LIBS})
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ark_part.desktop.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/ark_part.desktop
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS arkpart DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||||
|
|
||||||
|
|
||||||
|
########### install files ###############
|
||||||
|
|
||||||
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/ark_part.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
||||||
|
install( FILES ark_part.rc DESTINATION ${DATA_INSTALL_DIR}/ark )
|
986
ark/part/archivemodel.cpp
Normal file
|
@ -0,0 +1,986 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2010-2012 Raphael Kubo da Costa <rakuco@FreeBSD.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 "archivemodel.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "kerfuffle/jobs.h"
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KIconLoader>
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KMimeType>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QLatin1String>
|
||||||
|
#include <QList>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QPersistentModelIndex>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QtDBus/QtDBus>
|
||||||
|
|
||||||
|
using namespace Kerfuffle;
|
||||||
|
|
||||||
|
class ArchiveDirNode;
|
||||||
|
|
||||||
|
//used to speed up the loading of large archives
|
||||||
|
static ArchiveNode* s_previousMatch = NULL;
|
||||||
|
K_GLOBAL_STATIC(QStringList, s_previousPieces)
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: This class hierarchy needs some love.
|
||||||
|
// Having a parent take a child class as a parameter in the constructor
|
||||||
|
// should trigger one's spider-sense (TM).
|
||||||
|
class ArchiveNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArchiveNode(ArchiveDirNode *parent, const ArchiveEntry & entry)
|
||||||
|
: m_parent(parent)
|
||||||
|
{
|
||||||
|
setEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ArchiveNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const ArchiveEntry &entry() const
|
||||||
|
{
|
||||||
|
return m_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEntry(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
m_entry = entry;
|
||||||
|
|
||||||
|
const QStringList pieces = entry[FileName].toString().split(QLatin1Char( '/' ), QString::SkipEmptyParts);
|
||||||
|
m_name = pieces.isEmpty() ? QString() : pieces.last();
|
||||||
|
|
||||||
|
if (entry[IsDirectory].toBool()) {
|
||||||
|
m_icon = KIconLoader::global()->loadMimeTypeIcon(KMimeType::mimeType(QLatin1String("inode/directory"))->iconName(), KIconLoader::Small);
|
||||||
|
} else {
|
||||||
|
const KMimeType::Ptr mimeType = KMimeType::findByPath(m_entry[FileName].toString(), 0, true);
|
||||||
|
m_icon = KIconLoader::global()->loadMimeTypeIcon(mimeType->iconName(), KIconLoader::Small);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveDirNode *parent() const
|
||||||
|
{
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row() const;
|
||||||
|
|
||||||
|
virtual bool isDir() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap icon() const
|
||||||
|
{
|
||||||
|
return m_icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setIcon(const QPixmap &icon)
|
||||||
|
{
|
||||||
|
m_icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ArchiveEntry m_entry;
|
||||||
|
QPixmap m_icon;
|
||||||
|
QString m_name;
|
||||||
|
ArchiveDirNode *m_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ArchiveDirNode: public ArchiveNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArchiveDirNode(ArchiveDirNode *parent, const ArchiveEntry & entry)
|
||||||
|
: ArchiveNode(parent, entry)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ArchiveDirNode()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ArchiveNode*> entries()
|
||||||
|
{
|
||||||
|
return m_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEntryAt(int index, ArchiveNode* value)
|
||||||
|
{
|
||||||
|
m_entries[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendEntry(ArchiveNode* entry)
|
||||||
|
{
|
||||||
|
m_entries.append(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeEntryAt(int index)
|
||||||
|
{
|
||||||
|
delete m_entries.takeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isDir() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveNode* find(const QString & name)
|
||||||
|
{
|
||||||
|
foreach(ArchiveNode *node, m_entries) {
|
||||||
|
if (node && (node->name() == name)) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveNode* findByPath(const QStringList & pieces, int index = 0)
|
||||||
|
{
|
||||||
|
if (index == pieces.count()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveNode *next = find(pieces.at(index));
|
||||||
|
|
||||||
|
if (index == pieces.count() - 1) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
if (next && next->isDir()) {
|
||||||
|
return static_cast<ArchiveDirNode*>(next)->findByPath(pieces, index + 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void returnDirNodes(QList<ArchiveDirNode*> *store)
|
||||||
|
{
|
||||||
|
foreach(ArchiveNode *node, m_entries) {
|
||||||
|
if (node->isDir()) {
|
||||||
|
store->prepend(static_cast<ArchiveDirNode*>(node));
|
||||||
|
static_cast<ArchiveDirNode*>(node)->returnDirNodes(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
qDeleteAll(m_entries);
|
||||||
|
m_entries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<ArchiveNode*> m_entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper functor used by qStableSort.
|
||||||
|
*
|
||||||
|
* It always sorts folders before files.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class ArchiveModelSorter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArchiveModelSorter(int column, Qt::SortOrder order)
|
||||||
|
: m_sortColumn(column)
|
||||||
|
, m_sortOrder(order)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ArchiveModelSorter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator()(const QPair<ArchiveNode*, int> &left, const QPair<ArchiveNode*, int> &right) const
|
||||||
|
{
|
||||||
|
if (m_sortOrder == Qt::AscendingOrder) {
|
||||||
|
return lessThan(left, right);
|
||||||
|
} else {
|
||||||
|
return !lessThan(left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool lessThan(const QPair<ArchiveNode*, int> &left, const QPair<ArchiveNode*, int> &right) const
|
||||||
|
{
|
||||||
|
const ArchiveNode * const leftNode = left.first;
|
||||||
|
const ArchiveNode * const rightNode = right.first;
|
||||||
|
|
||||||
|
// #234373: sort folders before files
|
||||||
|
if ((leftNode->isDir()) && (!rightNode->isDir())) {
|
||||||
|
return (m_sortOrder == Qt::AscendingOrder);
|
||||||
|
} else if ((!leftNode->isDir()) && (rightNode->isDir())) {
|
||||||
|
return !(m_sortOrder == Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariant &leftEntry = leftNode->entry()[m_sortColumn];
|
||||||
|
const QVariant &rightEntry = rightNode->entry()[m_sortColumn];
|
||||||
|
|
||||||
|
switch (m_sortColumn) {
|
||||||
|
case FileName:
|
||||||
|
return leftNode->name() < rightNode->name();
|
||||||
|
case Size:
|
||||||
|
case CompressedSize:
|
||||||
|
return leftEntry.toInt() < rightEntry.toInt();
|
||||||
|
default:
|
||||||
|
return leftEntry.toString() < rightEntry.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should not get here.
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_sortColumn;
|
||||||
|
Qt::SortOrder m_sortOrder;
|
||||||
|
};
|
||||||
|
|
||||||
|
int ArchiveNode::row() const
|
||||||
|
{
|
||||||
|
if (parent()) {
|
||||||
|
return parent()->entries().indexOf(const_cast<ArchiveNode*>(this));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveModel::ArchiveModel(const QString &dbusPathName, QObject *parent)
|
||||||
|
: QAbstractItemModel(parent)
|
||||||
|
, m_rootNode(new ArchiveDirNode(0, ArchiveEntry()))
|
||||||
|
, m_dbusPathName(dbusPathName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveModel::~ArchiveModel()
|
||||||
|
{
|
||||||
|
delete m_rootNode;
|
||||||
|
m_rootNode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ArchiveModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
ArchiveNode *node = static_cast<ArchiveNode*>(index.internalPointer());
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
//TODO: complete the columns
|
||||||
|
int columnId = m_showColumns.at(index.column());
|
||||||
|
switch (columnId) {
|
||||||
|
case FileName:
|
||||||
|
return node->name();
|
||||||
|
case Size:
|
||||||
|
if (node->isDir()) {
|
||||||
|
int dirs;
|
||||||
|
int files;
|
||||||
|
const int children = childCount(index, dirs, files);
|
||||||
|
return KIO::itemsSummaryString(children, files, dirs, 0, false);
|
||||||
|
} else if (node->entry().contains(Link)) {
|
||||||
|
return QVariant();
|
||||||
|
} else {
|
||||||
|
return KIO::convertSize(node->entry()[ Size ].toULongLong());
|
||||||
|
}
|
||||||
|
case CompressedSize:
|
||||||
|
if (node->isDir() || node->entry().contains(Link)) {
|
||||||
|
return QVariant();
|
||||||
|
} else {
|
||||||
|
qulonglong compressedSize = node->entry()[ CompressedSize ].toULongLong();
|
||||||
|
if (compressedSize != 0) {
|
||||||
|
return KIO::convertSize(compressedSize);
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Ratio: // TODO: Use node->entry()[Ratio] when available
|
||||||
|
if (node->isDir() || node->entry().contains(Link)) {
|
||||||
|
return QVariant();
|
||||||
|
} else {
|
||||||
|
qulonglong compressedSize = node->entry()[ CompressedSize ].toULongLong();
|
||||||
|
qulonglong size = node->entry()[ Size ].toULongLong();
|
||||||
|
if (compressedSize == 0 || size == 0) {
|
||||||
|
return QVariant();
|
||||||
|
} else {
|
||||||
|
int ratio = int(100 * ((double)size - compressedSize) / size);
|
||||||
|
return QString(QString::number(ratio) + QLatin1String( " %" ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case Timestamp: {
|
||||||
|
const QDateTime timeStamp = node->entry().value(Timestamp).toDateTime();
|
||||||
|
return KGlobal::locale()->formatDateTime(timeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return node->entry().value(columnId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::DecorationRole:
|
||||||
|
if (index.column() == 0) {
|
||||||
|
return node->icon();
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
case Qt::FontRole: {
|
||||||
|
QFont f;
|
||||||
|
f.setItalic(node->entry()[ IsPasswordProtected ].toBool());
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags ArchiveModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
|
||||||
|
|
||||||
|
if (index.isValid()) {
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | defaultFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ArchiveModel::headerData(int section, Qt::Orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
if (section >= m_showColumns.size()) {
|
||||||
|
kDebug() << "WEIRD: showColumns.size = " << m_showColumns.size()
|
||||||
|
<< " and section = " << section;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
int columnId = m_showColumns.at(section);
|
||||||
|
|
||||||
|
switch (columnId) {
|
||||||
|
case FileName:
|
||||||
|
return i18nc("Name of a file inside an archive", "Name");
|
||||||
|
case Size:
|
||||||
|
return i18nc("Uncompressed size of a file inside an archive", "Size");
|
||||||
|
case CompressedSize:
|
||||||
|
return i18nc("Compressed size of a file inside an archive", "Compressed");
|
||||||
|
case Ratio:
|
||||||
|
return i18nc("Compression rate of file", "Rate");
|
||||||
|
case Owner:
|
||||||
|
return i18nc("File's owner username", "Owner");
|
||||||
|
case Group:
|
||||||
|
return i18nc("File's group", "Group");
|
||||||
|
case Permissions:
|
||||||
|
return i18nc("File permissions", "Mode");
|
||||||
|
case CRC:
|
||||||
|
return i18nc("CRC hash code", "CRC");
|
||||||
|
case Method:
|
||||||
|
return i18nc("Compression method", "Method");
|
||||||
|
case Version:
|
||||||
|
//TODO: what exactly is a file version?
|
||||||
|
return i18nc("File version", "Version");
|
||||||
|
case Timestamp:
|
||||||
|
return i18nc("Timestamp", "Date");
|
||||||
|
case Comment:
|
||||||
|
return i18nc("File comment", "Comment");
|
||||||
|
default:
|
||||||
|
return i18nc("Unnamed column", "??");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ArchiveModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (hasIndex(row, column, parent)) {
|
||||||
|
ArchiveDirNode *parentNode = parent.isValid() ? static_cast<ArchiveDirNode*>(parent.internalPointer()) : m_rootNode;
|
||||||
|
|
||||||
|
Q_ASSERT(parentNode->isDir());
|
||||||
|
|
||||||
|
ArchiveNode *item = parentNode->entries().value(row, 0);
|
||||||
|
if (item) {
|
||||||
|
return createIndex(row, column, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex ArchiveModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
ArchiveNode *item = static_cast<ArchiveNode*>(index.internalPointer());
|
||||||
|
Q_ASSERT(item);
|
||||||
|
if (item->parent() && (item->parent() != m_rootNode)) {
|
||||||
|
return createIndex(item->parent()->row(), 0, item->parent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveEntry ArchiveModel::entryForIndex(const QModelIndex &index)
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
ArchiveNode *item = static_cast<ArchiveNode*>(index.internalPointer());
|
||||||
|
Q_ASSERT(item);
|
||||||
|
return item->entry();
|
||||||
|
}
|
||||||
|
return ArchiveEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArchiveModel::childCount(const QModelIndex &index, int &dirs, int &files) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
dirs = files = 0;
|
||||||
|
ArchiveNode *item = static_cast<ArchiveNode*>(index.internalPointer());
|
||||||
|
Q_ASSERT(item);
|
||||||
|
if (item->isDir()) {
|
||||||
|
const QList<ArchiveNode*> entries = static_cast<ArchiveDirNode*>(item)->entries();
|
||||||
|
foreach(const ArchiveNode *node, entries) {
|
||||||
|
if (node->isDir()) {
|
||||||
|
dirs++;
|
||||||
|
} else {
|
||||||
|
files++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries.count();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArchiveModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (parent.column() <= 0) {
|
||||||
|
ArchiveNode *parentNode = parent.isValid() ? static_cast<ArchiveNode*>(parent.internalPointer()) : m_rootNode;
|
||||||
|
|
||||||
|
if (parentNode && parentNode->isDir()) {
|
||||||
|
return static_cast<ArchiveDirNode*>(parentNode)->entries().count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ArchiveModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return m_showColumns.size();
|
||||||
|
if (parent.isValid()) {
|
||||||
|
return static_cast<ArchiveNode*>(parent.internalPointer())->entry().size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::sort(int column, Qt::SortOrder order)
|
||||||
|
{
|
||||||
|
if (m_showColumns.size() <= column) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
QList<ArchiveDirNode*> dirNodes;
|
||||||
|
m_rootNode->returnDirNodes(&dirNodes);
|
||||||
|
dirNodes.append(m_rootNode);
|
||||||
|
|
||||||
|
const ArchiveModelSorter modelSorter(m_showColumns.at(column), order);
|
||||||
|
|
||||||
|
foreach(ArchiveDirNode* dir, dirNodes) {
|
||||||
|
QVector < QPair<ArchiveNode*,int> > sorting(dir->entries().count());
|
||||||
|
for (int i = 0; i < dir->entries().count(); ++i) {
|
||||||
|
ArchiveNode *item = dir->entries().at(i);
|
||||||
|
sorting[i].first = item;
|
||||||
|
sorting[i].second = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
qStableSort(sorting.begin(), sorting.end(), modelSorter);
|
||||||
|
|
||||||
|
QModelIndexList fromIndexes;
|
||||||
|
QModelIndexList toIndexes;
|
||||||
|
for (int r = 0; r < sorting.count(); ++r) {
|
||||||
|
ArchiveNode *item = sorting.at(r).first;
|
||||||
|
toIndexes.append(createIndex(r, 0, item));
|
||||||
|
fromIndexes.append(createIndex(sorting.at(r).second, 0, sorting.at(r).first));
|
||||||
|
dir->setEntryAt(r, sorting.at(r).first);
|
||||||
|
}
|
||||||
|
|
||||||
|
changePersistentIndexList(fromIndexes, toIndexes);
|
||||||
|
|
||||||
|
emit dataChanged(
|
||||||
|
index(0, 0, indexForNode(dir)),
|
||||||
|
index(dir->entries().size() - 1, 0, indexForNode(dir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::DropActions ArchiveModel::supportedDropActions() const
|
||||||
|
{
|
||||||
|
return Qt::CopyAction | Qt::MoveAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ArchiveModel::mimeTypes() const
|
||||||
|
{
|
||||||
|
QStringList types;
|
||||||
|
|
||||||
|
// MIME types we accept for dragging (eg. Dolphin -> Ark).
|
||||||
|
types << QLatin1String("text/uri-list")
|
||||||
|
<< QLatin1String("text/plain")
|
||||||
|
<< QLatin1String("text/x-moz-url");
|
||||||
|
|
||||||
|
// MIME types we accept for dropping (eg. Ark -> Dolphin).
|
||||||
|
types << QLatin1String("application/x-kde-ark-dndextract-service")
|
||||||
|
<< QLatin1String("application/x-kde-ark-dndextract-path");
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMimeData *ArchiveModel::mimeData(const QModelIndexList &indexes) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(indexes)
|
||||||
|
|
||||||
|
QMimeData *mimeData = new QMimeData;
|
||||||
|
mimeData->setData(QLatin1String("application/x-kde-ark-dndextract-service"),
|
||||||
|
QDBusConnection::sessionBus().baseService().toUtf8());
|
||||||
|
mimeData->setData(QLatin1String("application/x-kde-ark-dndextract-path"),
|
||||||
|
m_dbusPathName.toUtf8());
|
||||||
|
|
||||||
|
return mimeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArchiveModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(action)
|
||||||
|
Q_UNUSED(row)
|
||||||
|
Q_UNUSED(column)
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
|
||||||
|
if (!data->hasUrls()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList paths;
|
||||||
|
foreach(const QUrl &url, data->urls()) {
|
||||||
|
paths << url.toLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
//for now, this code is not used because adding files to paths inside the
|
||||||
|
//archive is not supported yet. need a solution for this later.
|
||||||
|
QString path;
|
||||||
|
#if 0
|
||||||
|
if (parent.isValid()) {
|
||||||
|
QModelIndex droppedOnto = index(row, column, parent);
|
||||||
|
if (entryForIndex(droppedOnto).value(IsDirectory).toBool()) {
|
||||||
|
kDebug() << "Using entry";
|
||||||
|
path = entryForIndex(droppedOnto).value(FileName).toString();
|
||||||
|
} else {
|
||||||
|
path = entryForIndex(parent).value(FileName).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Dropped onto " << path;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
emit droppedFiles(paths, path);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a rationale, see bugs #194241 and #241967
|
||||||
|
QString ArchiveModel::cleanFileName(const QString& fileName)
|
||||||
|
{
|
||||||
|
if ((fileName == QLatin1String("/")) ||
|
||||||
|
(fileName == QLatin1String("."))) { // "." is present in ISO files
|
||||||
|
return QString();
|
||||||
|
} else if (fileName.startsWith(QLatin1String("./"))) {
|
||||||
|
return fileName.mid(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveDirNode* ArchiveModel::parentFor(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
QStringList pieces = entry[ FileName ].toString().split(QLatin1Char( '/' ), QString::SkipEmptyParts);
|
||||||
|
if (pieces.isEmpty()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pieces.removeLast();
|
||||||
|
|
||||||
|
if (s_previousMatch) {
|
||||||
|
//the number of path elements must be the same for the shortcut
|
||||||
|
//to work
|
||||||
|
if (s_previousPieces->count() == pieces.count()) {
|
||||||
|
bool equal = true;
|
||||||
|
|
||||||
|
//make sure all the pieces match up
|
||||||
|
for (int i = 0; i < s_previousPieces->count(); ++i) {
|
||||||
|
if (s_previousPieces->at(i) != pieces.at(i)) {
|
||||||
|
equal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if match return it
|
||||||
|
if (equal) {
|
||||||
|
return static_cast<ArchiveDirNode*>(s_previousMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveDirNode *parent = m_rootNode;
|
||||||
|
|
||||||
|
foreach(const QString &piece, pieces) {
|
||||||
|
ArchiveNode *node = parent->find(piece);
|
||||||
|
if (!node) {
|
||||||
|
ArchiveEntry e;
|
||||||
|
e[ FileName ] = (parent == m_rootNode) ?
|
||||||
|
piece : parent->entry()[ FileName ].toString() + QLatin1Char( '/' ) + piece;
|
||||||
|
e[ IsDirectory ] = true;
|
||||||
|
node = new ArchiveDirNode(parent, e);
|
||||||
|
insertNode(node);
|
||||||
|
}
|
||||||
|
if (!node->isDir()) {
|
||||||
|
ArchiveEntry e(node->entry());
|
||||||
|
node = new ArchiveDirNode(parent, e);
|
||||||
|
//Maybe we have both a file and a directory of the same name
|
||||||
|
// We avoid removing previous entries unless necessary
|
||||||
|
insertNode(node);
|
||||||
|
}
|
||||||
|
parent = static_cast<ArchiveDirNode*>(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_previousMatch = parent;
|
||||||
|
*s_previousPieces = pieces;
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
QModelIndex ArchiveModel::indexForNode(ArchiveNode *node)
|
||||||
|
{
|
||||||
|
Q_ASSERT(node);
|
||||||
|
if (node != m_rootNode) {
|
||||||
|
Q_ASSERT(node->parent());
|
||||||
|
Q_ASSERT(node->parent()->isDir());
|
||||||
|
return createIndex(node->row(), 0, node);
|
||||||
|
}
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotEntryRemoved(const QString & path)
|
||||||
|
{
|
||||||
|
kDebug() << "Removed node at path " << path;
|
||||||
|
|
||||||
|
const QString entryFileName(cleanFileName(path));
|
||||||
|
if (entryFileName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveNode *entry = m_rootNode->findByPath(entryFileName.split(QLatin1Char( '/' ), QString::SkipEmptyParts));
|
||||||
|
if (entry) {
|
||||||
|
ArchiveDirNode *parent = entry->parent();
|
||||||
|
QModelIndex index = indexForNode(entry);
|
||||||
|
|
||||||
|
beginRemoveRows(indexForNode(parent), entry->row(), entry->row());
|
||||||
|
|
||||||
|
//delete parent->entries()[ entry->row() ];
|
||||||
|
//parent->entries()[ entry->row() ] = 0;
|
||||||
|
parent->removeEntryAt(entry->row());
|
||||||
|
|
||||||
|
endRemoveRows();
|
||||||
|
} else {
|
||||||
|
kDebug() << "Did not find the removed node";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotUserQuery(Kerfuffle::Query *query)
|
||||||
|
{
|
||||||
|
query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotNewEntryFromSetArchive(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
// we cache all entries that appear when opening a new archive
|
||||||
|
// so we can all them together once it's done, this is a huge
|
||||||
|
// performance improvement because we save from doing lots of
|
||||||
|
// begin/endInsertRows
|
||||||
|
m_newArchiveEntries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotNewEntry(const ArchiveEntry& entry)
|
||||||
|
{
|
||||||
|
newEntry(entry, NotifyViews);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::newEntry(const ArchiveEntry& receivedEntry, InsertBehaviour behaviour)
|
||||||
|
{
|
||||||
|
if (receivedEntry[FileName].toString().isEmpty()) {
|
||||||
|
kDebug() << "Weird, received empty entry (no filename) - skipping";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if there are no addidional columns registered, then have a look at the
|
||||||
|
//entry and populate some
|
||||||
|
if (m_showColumns.isEmpty()) {
|
||||||
|
//these are the columns we are interested in showing in the display
|
||||||
|
static const QList<int> columnsForDisplay =
|
||||||
|
QList<int>()
|
||||||
|
<< FileName
|
||||||
|
<< Size
|
||||||
|
<< CompressedSize
|
||||||
|
<< Permissions
|
||||||
|
<< Owner
|
||||||
|
<< Group
|
||||||
|
<< Ratio
|
||||||
|
<< CRC
|
||||||
|
<< Method
|
||||||
|
<< Version
|
||||||
|
<< Timestamp
|
||||||
|
<< Comment;
|
||||||
|
|
||||||
|
QList<int> toInsert;
|
||||||
|
|
||||||
|
foreach(int column, columnsForDisplay) {
|
||||||
|
if (receivedEntry.contains(column)) {
|
||||||
|
toInsert << column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beginInsertColumns(QModelIndex(), 0, toInsert.size() - 1);
|
||||||
|
m_showColumns << toInsert;
|
||||||
|
endInsertColumns();
|
||||||
|
|
||||||
|
kDebug() << "Show columns detected: " << m_showColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
//make a copy
|
||||||
|
ArchiveEntry entry = receivedEntry;
|
||||||
|
|
||||||
|
//#194241: Filenames such as "./file" should be displayed as "file"
|
||||||
|
//#241967: Entries called "/" should be ignored
|
||||||
|
QString entryFileName = cleanFileName(entry[FileName].toString());
|
||||||
|
if (entryFileName.isEmpty()) { // The entry contains only "." or "./"
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entry[FileName] = entryFileName;
|
||||||
|
|
||||||
|
/// 1. Skip already created nodes
|
||||||
|
if (m_rootNode) {
|
||||||
|
ArchiveNode *existing = m_rootNode->findByPath(entry[ FileName ].toString().split(QLatin1Char( '/' )));
|
||||||
|
if (existing) {
|
||||||
|
kDebug() << "Refreshing entry for" << entry[FileName].toString();
|
||||||
|
|
||||||
|
// Multi-volume files are repeated at least in RAR archives.
|
||||||
|
// In that case, we need to sum the compressed size for each volume
|
||||||
|
qulonglong currentCompressedSize = existing->entry()[CompressedSize].toULongLong();
|
||||||
|
entry[CompressedSize] = currentCompressedSize + entry[CompressedSize].toULongLong();
|
||||||
|
|
||||||
|
//TODO: benchmark whether it's a bad idea to reset the entry here.
|
||||||
|
existing->setEntry(entry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 2. Find Parent Node, creating missing ArchiveDirNodes in the process
|
||||||
|
ArchiveDirNode *parent = parentFor(entry);
|
||||||
|
|
||||||
|
/// 3. Create an ArchiveNode
|
||||||
|
QString name = entry[ FileName ].toString().split(QLatin1Char( '/' ), QString::SkipEmptyParts).last();
|
||||||
|
ArchiveNode *node = parent->find(name);
|
||||||
|
if (node) {
|
||||||
|
node->setEntry(entry);
|
||||||
|
} else {
|
||||||
|
if (entry[ FileName ].toString().endsWith(QLatin1Char( '/' )) || (entry.contains(IsDirectory) && entry[ IsDirectory ].toBool())) {
|
||||||
|
node = new ArchiveDirNode(parent, entry);
|
||||||
|
} else {
|
||||||
|
node = new ArchiveNode(parent, entry);
|
||||||
|
}
|
||||||
|
insertNode(node, behaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotLoadingFinished(KJob *job)
|
||||||
|
{
|
||||||
|
//kDebug() << entry;
|
||||||
|
foreach(const ArchiveEntry &entry, m_newArchiveEntries) {
|
||||||
|
newEntry(entry, DoNotNotifyViews);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
m_newArchiveEntries.clear();
|
||||||
|
|
||||||
|
emit loadingFinished(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::insertNode(ArchiveNode *node, InsertBehaviour behaviour)
|
||||||
|
{
|
||||||
|
Q_ASSERT(node);
|
||||||
|
ArchiveDirNode *parent = node->parent();
|
||||||
|
Q_ASSERT(parent);
|
||||||
|
if (behaviour == NotifyViews) {
|
||||||
|
beginInsertRows(indexForNode(parent), parent->entries().count(), parent->entries().count());
|
||||||
|
}
|
||||||
|
parent->appendEntry(node);
|
||||||
|
if (behaviour == NotifyViews) {
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::Archive* ArchiveModel::archive() const
|
||||||
|
{
|
||||||
|
return m_archive.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob* ArchiveModel::setArchive(Kerfuffle::Archive *archive)
|
||||||
|
{
|
||||||
|
m_archive.reset(archive);
|
||||||
|
|
||||||
|
m_rootNode->clear();
|
||||||
|
s_previousMatch = 0;
|
||||||
|
s_previousPieces->clear();
|
||||||
|
|
||||||
|
Kerfuffle::ListJob *job = NULL;
|
||||||
|
|
||||||
|
m_newArchiveEntries.clear();
|
||||||
|
if (m_archive) {
|
||||||
|
job = m_archive->list(); // TODO: call "open" or "create"?
|
||||||
|
|
||||||
|
connect(job, SIGNAL(newEntry(ArchiveEntry)),
|
||||||
|
this, SLOT(slotNewEntryFromSetArchive(ArchiveEntry)));
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotLoadingFinished(KJob*)));
|
||||||
|
|
||||||
|
connect(job, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
this, SLOT(slotUserQuery(Kerfuffle::Query*)));
|
||||||
|
|
||||||
|
emit loadingStarted();
|
||||||
|
|
||||||
|
// TODO: make sure if it's ok to not have calls to beginRemoveColumns here
|
||||||
|
m_showColumns.clear();
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob* ArchiveModel::extractFile(const QVariant& fileName, const QString & destinationDir, const Kerfuffle::ExtractionOptions options) const
|
||||||
|
{
|
||||||
|
QList<QVariant> files;
|
||||||
|
files << fileName;
|
||||||
|
return extractFiles(files, destinationDir, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob* ArchiveModel::extractFiles(const QList<QVariant>& files, const QString & destinationDir, const Kerfuffle::ExtractionOptions options) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_archive);
|
||||||
|
ExtractJob *newJob = m_archive->copyFiles(files, destinationDir, options);
|
||||||
|
connect(newJob, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
this, SLOT(slotUserQuery(Kerfuffle::Query*)));
|
||||||
|
return newJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddJob* ArchiveModel::addFiles(const QStringList & filenames, const CompressionOptions& options)
|
||||||
|
{
|
||||||
|
if (!m_archive) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_archive->isReadOnly()) {
|
||||||
|
AddJob *job = m_archive->addFiles(filenames, options);
|
||||||
|
connect(job, SIGNAL(newEntry(ArchiveEntry)),
|
||||||
|
this, SLOT(slotNewEntry(ArchiveEntry)));
|
||||||
|
connect(job, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
this, SLOT(slotUserQuery(Kerfuffle::Query*)));
|
||||||
|
|
||||||
|
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteJob* ArchiveModel::deleteFiles(const QList<QVariant> & files)
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_archive);
|
||||||
|
if (!m_archive->isReadOnly()) {
|
||||||
|
DeleteJob *job = m_archive->deleteFiles(files);
|
||||||
|
connect(job, SIGNAL(entryRemoved(QString)),
|
||||||
|
this, SLOT(slotEntryRemoved(QString)));
|
||||||
|
|
||||||
|
connect(job, SIGNAL(finished(KJob*)),
|
||||||
|
this, SLOT(slotCleanupEmptyDirs()));
|
||||||
|
|
||||||
|
connect(job, SIGNAL(userQuery(Kerfuffle::Query*)),
|
||||||
|
this, SLOT(slotUserQuery(Kerfuffle::Query*)));
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveModel::slotCleanupEmptyDirs()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
QList<QPersistentModelIndex> queue;
|
||||||
|
QList<QPersistentModelIndex> nodesToDelete;
|
||||||
|
|
||||||
|
//add root nodes
|
||||||
|
for (int i = 0; i < rowCount(); ++i) {
|
||||||
|
queue.append(QPersistentModelIndex(index(i, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//breadth-first traverse
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
QPersistentModelIndex node = queue.takeFirst();
|
||||||
|
ArchiveEntry entry = entryForIndex(node);
|
||||||
|
//kDebug() << "Trying " << entry[FileName].toString();
|
||||||
|
|
||||||
|
if (!hasChildren(node)) {
|
||||||
|
if (!entry.contains(InternalID)) {
|
||||||
|
nodesToDelete << node;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < rowCount(node); ++i) {
|
||||||
|
queue.append(QPersistentModelIndex(index(i, 0, node)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QPersistentModelIndex& node, nodesToDelete) {
|
||||||
|
ArchiveNode *rawNode = static_cast<ArchiveNode*>(node.internalPointer());
|
||||||
|
kDebug() << "Delete with parent entries " << rawNode->parent()->entries() << " and row " << rawNode->row();
|
||||||
|
beginRemoveRows(parent(node), rawNode->row(), rawNode->row());
|
||||||
|
rawNode->parent()->removeEntryAt(rawNode->row());
|
||||||
|
endRemoveRows();
|
||||||
|
//kDebug() << "Removed entry " << entry[FileName].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "archivemodel.moc"
|
126
ark/part/archivemodel.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 ARCHIVEMODEL_H
|
||||||
|
#define ARCHIVEMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
|
||||||
|
#include <kjobtrackerinterface.h>
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
using Kerfuffle::ArchiveEntry;
|
||||||
|
|
||||||
|
namespace Kerfuffle
|
||||||
|
{
|
||||||
|
class Query;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArchiveNode;
|
||||||
|
class ArchiveDirNode;
|
||||||
|
|
||||||
|
class ArchiveModel: public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ArchiveModel(const QString &dbusPathName, QObject *parent = 0);
|
||||||
|
~ArchiveModel();
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const;
|
||||||
|
QModelIndex index(int row, int column,
|
||||||
|
const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
|
||||||
|
virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
|
||||||
|
|
||||||
|
//drag and drop related
|
||||||
|
virtual Qt::DropActions supportedDropActions() const;
|
||||||
|
virtual QStringList mimeTypes() const;
|
||||||
|
virtual QMimeData * mimeData(const QModelIndexList & indexes) const;
|
||||||
|
|
||||||
|
virtual bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent);
|
||||||
|
|
||||||
|
KJob* setArchive(Kerfuffle::Archive *archive);
|
||||||
|
Kerfuffle::Archive *archive() const;
|
||||||
|
|
||||||
|
Kerfuffle::ArchiveEntry entryForIndex(const QModelIndex &index);
|
||||||
|
int childCount(const QModelIndex &index, int &dirs, int &files) const;
|
||||||
|
|
||||||
|
Kerfuffle::ExtractJob* extractFile(const QVariant& fileName, const QString & destinationDir, const Kerfuffle::ExtractionOptions options = Kerfuffle::ExtractionOptions()) const;
|
||||||
|
Kerfuffle::ExtractJob* extractFiles(const QList<QVariant>& files, const QString & destinationDir, const Kerfuffle::ExtractionOptions options = Kerfuffle::ExtractionOptions()) const;
|
||||||
|
|
||||||
|
Kerfuffle::AddJob* addFiles(const QStringList & paths, const Kerfuffle::CompressionOptions& options = Kerfuffle::CompressionOptions());
|
||||||
|
Kerfuffle::DeleteJob* deleteFiles(const QList<QVariant> & files);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loadingStarted();
|
||||||
|
void loadingFinished(KJob *);
|
||||||
|
void extractionFinished(bool success);
|
||||||
|
void error(const QString& error, const QString& details);
|
||||||
|
void droppedFiles(const QStringList& files, const QString& path = QString());
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotNewEntryFromSetArchive(const ArchiveEntry& entry);
|
||||||
|
void slotNewEntry(const ArchiveEntry& entry);
|
||||||
|
void slotLoadingFinished(KJob *job);
|
||||||
|
void slotEntryRemoved(const QString & path);
|
||||||
|
void slotUserQuery(Kerfuffle::Query *query);
|
||||||
|
void slotCleanupEmptyDirs();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Strips file names that start with './'.
|
||||||
|
*
|
||||||
|
* For more information, see bug 194241.
|
||||||
|
*
|
||||||
|
* @param fileName The file name that will be stripped.
|
||||||
|
*
|
||||||
|
* @return @p fileName without the leading './'
|
||||||
|
*/
|
||||||
|
QString cleanFileName(const QString& fileName);
|
||||||
|
|
||||||
|
ArchiveDirNode* parentFor(const Kerfuffle::ArchiveEntry& entry);
|
||||||
|
QModelIndex indexForNode(ArchiveNode *node);
|
||||||
|
static bool compareAscending(const QModelIndex& a, const QModelIndex& b);
|
||||||
|
static bool compareDescending(const QModelIndex& a, const QModelIndex& b);
|
||||||
|
/**
|
||||||
|
* Insert the node @p node into the model, ensuring all views are notified
|
||||||
|
* of the change.
|
||||||
|
*/
|
||||||
|
enum InsertBehaviour { NotifyViews, DoNotNotifyViews };
|
||||||
|
void insertNode(ArchiveNode *node, InsertBehaviour behaviour = NotifyViews);
|
||||||
|
void newEntry(const Kerfuffle::ArchiveEntry& entry, InsertBehaviour behaviour);
|
||||||
|
|
||||||
|
QList<Kerfuffle::ArchiveEntry> m_newArchiveEntries; // holds entries from opening a new archive until it's totally open
|
||||||
|
QList<int> m_showColumns;
|
||||||
|
QScopedPointer<Kerfuffle::Archive> m_archive;
|
||||||
|
ArchiveDirNode *m_rootNode;
|
||||||
|
|
||||||
|
QString m_dbusPathName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ARCHIVEMODEL_H
|
142
ark/part/archiveview.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv (at@at) stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 "archiveview.h"
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KGlobalSettings>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QDragMoveEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
ArchiveView::ArchiveView(QWidget *parent)
|
||||||
|
: QTreeView(parent)
|
||||||
|
, m_mouseButtons(Qt::NoButton)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(pressed(QModelIndex)),
|
||||||
|
SLOT(updateMouseButtons()));
|
||||||
|
connect(this, SIGNAL(clicked(QModelIndex)),
|
||||||
|
SLOT(slotClicked(QModelIndex)));
|
||||||
|
connect(this, SIGNAL(doubleClicked(QModelIndex)),
|
||||||
|
SLOT(slotDoubleClicked(QModelIndex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: this is a workaround taken from Dolphin until QTBUG-1067 is resolved
|
||||||
|
void ArchiveView::updateMouseButtons()
|
||||||
|
{
|
||||||
|
m_mouseButtons = QApplication::mouseButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::slotClicked(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (KGlobalSettings::singleClick()) {
|
||||||
|
if (m_mouseButtons != Qt::LeftButton) { // FIXME: see QTBUG-1067
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user is pressing shift or control, more than one item is being selected
|
||||||
|
const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
|
||||||
|
if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit itemTriggered(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::slotDoubleClicked(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (!KGlobalSettings::singleClick()) {
|
||||||
|
emit itemTriggered(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::setModel(QAbstractItemModel *model)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
QTreeView::setModel(model);
|
||||||
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
setAlternatingRowColors(true);
|
||||||
|
setAnimated(true);
|
||||||
|
setAllColumnsShowFocus(true);
|
||||||
|
setSortingEnabled(true);
|
||||||
|
|
||||||
|
//drag and drop
|
||||||
|
setDragEnabled(true);
|
||||||
|
setAcceptDrops(true);
|
||||||
|
setDropIndicatorShown(true);
|
||||||
|
setDragDropMode(QAbstractItemView::DragDrop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::startDrag(Qt::DropActions supportedActions)
|
||||||
|
{
|
||||||
|
//only start the drag if it's over the filename column. this allows dragging selection in
|
||||||
|
//tree/detail view
|
||||||
|
if (currentIndex().column() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Singling out the current selection...";
|
||||||
|
selectionModel()->setCurrentIndex(currentIndex(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||||
|
QTreeView::startDrag(supportedActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ArchiveView::dragEnterEvent(QDragEnterEvent * event)
|
||||||
|
{
|
||||||
|
//TODO: if no model, trigger some mechanism to create one automatically!
|
||||||
|
kDebug() << event;
|
||||||
|
|
||||||
|
if (event->source() == this) {
|
||||||
|
//we don't support internal drops yet.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeView::dragEnterEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::dropEvent(QDropEvent * event)
|
||||||
|
{
|
||||||
|
kDebug() << event;
|
||||||
|
|
||||||
|
if (event->source() == this) {
|
||||||
|
//we don't support internal drops yet.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeView::dropEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveView::dragMoveEvent(QDragMoveEvent * event)
|
||||||
|
{
|
||||||
|
if (event->source() == this) {
|
||||||
|
//we don't support internal drops yet.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeView::dragMoveEvent(event);
|
||||||
|
if (event->mimeData()->hasFormat(QLatin1String("text/uri-list"))) {
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
}
|
54
ark/part/archiveview.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv (at@at) stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 ARCHIVEVIEW_H
|
||||||
|
#define ARCHIVEVIEW_H
|
||||||
|
|
||||||
|
#include <QTreeView>
|
||||||
|
|
||||||
|
class ArchiveView : public QTreeView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ArchiveView(QWidget *parent = 0);
|
||||||
|
virtual void dragEnterEvent(class QDragEnterEvent * event);
|
||||||
|
virtual void dropEvent(class QDropEvent * event);
|
||||||
|
virtual void dragMoveEvent(class QDragMoveEvent * event);
|
||||||
|
virtual void startDrag(Qt::DropActions supportedActions);
|
||||||
|
|
||||||
|
void setModel(QAbstractItemModel *model);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void slotClicked(const QModelIndex & index);
|
||||||
|
void slotDoubleClicked(const QModelIndex & index);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateMouseButtons();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void itemTriggered(const QModelIndex & index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Qt::MouseButtons m_mouseButtons; // FIXME: workaround until QTBUG-1067 is resolved
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ARCHIVEVIEW_H */
|
152
ark/part/ark_part.desktop.cmake
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Icon=ark
|
||||||
|
Name=Archiver
|
||||||
|
Name[af]=Argifeerder
|
||||||
|
Name[ar]=المؤرشف
|
||||||
|
Name[ast]=Archivador
|
||||||
|
Name[bg]=Архиватор
|
||||||
|
Name[br]=Dieller
|
||||||
|
Name[bs]=Arhivar
|
||||||
|
Name[ca]=Arxivador
|
||||||
|
Name[ca@valencia]=Arxivador
|
||||||
|
Name[cs]=Archivátor
|
||||||
|
Name[cy]=Archifydd
|
||||||
|
Name[da]=Arkivbehandler
|
||||||
|
Name[de]=Archivprogramm
|
||||||
|
Name[el]=Πρόγραμμα αρχειοθέτησης
|
||||||
|
Name[en_GB]=Archiver
|
||||||
|
Name[eo]=Arkivilo
|
||||||
|
Name[es]=Archivador
|
||||||
|
Name[et]=Arhiveerija
|
||||||
|
Name[eu]=Artxibatzeko programa
|
||||||
|
Name[fa]=بایگانیکننده
|
||||||
|
Name[fi]=Pakkausohjelma
|
||||||
|
Name[fr]=Archiveur
|
||||||
|
Name[ga]=Archiver
|
||||||
|
Name[gl]=Arquivador
|
||||||
|
Name[he]=מנהל הארכיונים
|
||||||
|
Name[hne]=अभिलेखक
|
||||||
|
Name[hr]=Arhiver
|
||||||
|
Name[hu]=Ark fájltömörítő
|
||||||
|
Name[ia]=Archivator
|
||||||
|
Name[id]=Pengarsip
|
||||||
|
Name[is]=Skráasafnari
|
||||||
|
Name[it]=Utilità di archiviazione
|
||||||
|
Name[ja]=アーカイバ
|
||||||
|
Name[kk]=Архивтегіш
|
||||||
|
Name[km]=កម្មវិធីប័ណ្ណសារ
|
||||||
|
Name[ko]=Archiver
|
||||||
|
Name[lt]=Archyvatorius
|
||||||
|
Name[lv]=Arhivātors
|
||||||
|
Name[mk]=Архивер
|
||||||
|
Name[mr]=संग्रहकर्ता
|
||||||
|
Name[ms]=Pengarkib
|
||||||
|
Name[nb]=Arkivbehandler
|
||||||
|
Name[nds]=Archivater
|
||||||
|
Name[ne]=सङ्ग्रहक
|
||||||
|
Name[nl]=Archiefgereedschap
|
||||||
|
Name[nn]=Arkivprogram
|
||||||
|
Name[pa]=ਅਕਾਇਵਰ
|
||||||
|
Name[pl]=Ark
|
||||||
|
Name[pt]=Ark
|
||||||
|
Name[pt_BR]=Arquivador
|
||||||
|
Name[ro]=Arhivator
|
||||||
|
Name[ru]=Архиватор
|
||||||
|
Name[sk]=Archivačný nástroj
|
||||||
|
Name[sl]=Pakirnik
|
||||||
|
Name[sq]=Arkivues
|
||||||
|
Name[sr]=Архивар
|
||||||
|
Name[sr@ijekavian]=Архивар
|
||||||
|
Name[sr@ijekavianlatin]=Arhivar
|
||||||
|
Name[sr@latin]=Arhivar
|
||||||
|
Name[sv]=Arkiverare
|
||||||
|
Name[ta]=காப்பகம் உருவாக்கி
|
||||||
|
Name[tg]=Бойгонигар
|
||||||
|
Name[th]=ตัวสร้างแฟ้มจัดเก็บ
|
||||||
|
Name[tr]=Arşivleyici
|
||||||
|
Name[uk]=Архіватор
|
||||||
|
Name[uz]=Arxivlagich
|
||||||
|
Name[uz@cyrillic]=Архивлагич
|
||||||
|
Name[vi]=Trình Lưu Trữ
|
||||||
|
Name[wa]=Årtchiveu
|
||||||
|
Name[xh]=Umenzi woshicilelo lukawonke-wonke noxwebhu lweMbali
|
||||||
|
Name[x-test]=xxArchiverxx
|
||||||
|
Name[zh_CN]=压缩存档工具
|
||||||
|
Name[zh_TW]=壓縮檔處理器
|
||||||
|
Comment=Archive Handling Tool
|
||||||
|
Comment[af]=Argief Handtering Program
|
||||||
|
Comment[ar]=أداة التعامل مع الملفات المضغوطة
|
||||||
|
Comment[ast]=Ferramienta pa remanar archivadores
|
||||||
|
Comment[bg]=Работа с архиви
|
||||||
|
Comment[br]=Ostilh merañ an dielloù
|
||||||
|
Comment[bs]=Alatka za rukovanje arhivama
|
||||||
|
Comment[ca]=Eina per a treballar amb arxius
|
||||||
|
Comment[ca@valencia]=Eina per a treballar amb arxius
|
||||||
|
Comment[cs]=Program pro práci s archivy
|
||||||
|
Comment[cy]=Erfyn Triniaeth Archif
|
||||||
|
Comment[da]=Arkivbehandlingsværktøj
|
||||||
|
Comment[de]=Archiv-Verwaltung
|
||||||
|
Comment[el]=Εργαλείο χειρισμού αρχειοθηκών
|
||||||
|
Comment[en_GB]=Archive Handling Tool
|
||||||
|
Comment[eo]=Administrilo por arĥivoj
|
||||||
|
Comment[es]=Herramienta de gestión de archivos
|
||||||
|
Comment[et]=Arhiivide haldamise rakendus
|
||||||
|
Comment[eu]=Artxiboak kudeatzeko tresna
|
||||||
|
Comment[fa]=ابزار گرداندن بایگانی
|
||||||
|
Comment[fi]=Pakkausohjelma
|
||||||
|
Comment[fr]=Outil de manipulation d'archives
|
||||||
|
Comment[ga]=Uirlis Láimhseála Cartlainne
|
||||||
|
Comment[gl]=Utilidade de manexo de arquivos
|
||||||
|
Comment[he]=כלי לניהול ארכיונים
|
||||||
|
Comment[hne]=अभिलेख संभाल औजार
|
||||||
|
Comment[hr]=Uslužni program za arhiviranje
|
||||||
|
Comment[hu]=Tömörítőprogram
|
||||||
|
Comment[ia]=Instrumento de manear archivo
|
||||||
|
Comment[id]=Perkakas Penanganan Arsip
|
||||||
|
Comment[is]=Vinna með safnskrár
|
||||||
|
Comment[it]=Gestione degli archivi
|
||||||
|
Comment[ja]=アーカイブを操作するツール
|
||||||
|
Comment[kk]=Архивпен айналысу құралы
|
||||||
|
Comment[km]=ឧបករណ៍គ្រប់គ្រងប័ណ្ណសារ
|
||||||
|
Comment[ko]=압축 파일 도구
|
||||||
|
Comment[lt]=Archyvo valdymo priemonė
|
||||||
|
Comment[lv]=Arhīvu apstrādes rīks
|
||||||
|
Comment[mk]=Алатка за справување со архивирани датотеки
|
||||||
|
Comment[mr]=संग्रह हाताळणारे साधन
|
||||||
|
Comment[ms]=Alatan Pengendalian Arkib
|
||||||
|
Comment[nb]=Arkivbehandlingsverktøy
|
||||||
|
Comment[nds]=En Warktüüch för de Archievpleeg
|
||||||
|
Comment[ne]=ह्यान्डलिङ उपकरण सङ्ग्रह गर्नुहोस्
|
||||||
|
Comment[nl]=Hulpprogramma voor het beheren van archieven
|
||||||
|
Comment[nn]=Verktøy for arkivhandsaming
|
||||||
|
Comment[pa]=ਅਕਾਇਵ ਹੈਡਲਿੰਗ ਟੂਲ
|
||||||
|
Comment[pl]=Program obsługi archiwów
|
||||||
|
Comment[pt]=Programa de gestão de arquivos
|
||||||
|
Comment[pt_BR]=Ferramenta de manipulação de arquivos
|
||||||
|
Comment[ro]=Utilitar de manipulare arhive
|
||||||
|
Comment[ru]=Программа работы с архивами
|
||||||
|
Comment[sk]=Nástroj na prácu s archívmi
|
||||||
|
Comment[sl]=Orodje za ravnanje z arhivi
|
||||||
|
Comment[sq]=Mjet Për Përpunimin e Arkivave
|
||||||
|
Comment[sr]=Алатка за руковање архивама
|
||||||
|
Comment[sr@ijekavian]=Алатка за руковање архивама
|
||||||
|
Comment[sr@ijekavianlatin]=Alatka za rukovanje arhivama
|
||||||
|
Comment[sr@latin]=Alatka za rukovanje arhivama
|
||||||
|
Comment[sv]=Verktyg för att hantera filarkiv
|
||||||
|
Comment[ta]=காப்பகத்தை கையாளும் கருவி
|
||||||
|
Comment[tg]=Асбобҳои Дасткории Бойгонӣ
|
||||||
|
Comment[th]=เครื่องมือจัดการแฟ้มจัดเก็บ
|
||||||
|
Comment[tr]=Arşiv İşleme Aracı
|
||||||
|
Comment[uk]=Засіб роботи з архівами
|
||||||
|
Comment[uz]=Arxiv uchun vosita
|
||||||
|
Comment[uz@cyrillic]=Архив учун восита
|
||||||
|
Comment[vi]=Công Cụ Xử Lý Các Tập Tin Nén
|
||||||
|
Comment[wa]=Usteye po-z apougnî les årtchives
|
||||||
|
Comment[xh]=Isixhobo sokuphatha i Archive
|
||||||
|
Comment[x-test]=xxArchive Handling Toolxx
|
||||||
|
Comment[zh_CN]=压缩归档处理工具
|
||||||
|
Comment[zh_TW]=壓縮檔處理工具
|
||||||
|
X-KDE-ServiceTypes=KParts/ReadOnlyPart,Browser/View
|
||||||
|
X-KDE-Library=arkpart
|
||||||
|
Type=Service
|
||||||
|
MimeType=@SUPPORTED_ARK_MIMETYPES@
|
28
ark/part/ark_part.rc
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE kpartgui>
|
||||||
|
<kpartgui name="ark_part" version="1">
|
||||||
|
<MenuBar>
|
||||||
|
<Menu name="file">
|
||||||
|
<text>&File</text>
|
||||||
|
<Action name="file_save_as" group="file_save"/>
|
||||||
|
</Menu>
|
||||||
|
<Menu name="action">
|
||||||
|
<text>&Action</text>
|
||||||
|
<Action name="add"/>
|
||||||
|
<Action name="add-dir"/>
|
||||||
|
<Action name="delete"/>
|
||||||
|
<Action name="extract"/>
|
||||||
|
<Action name="preview"/>
|
||||||
|
</Menu>
|
||||||
|
<Menu name="settings">
|
||||||
|
<text>&Settings</text>
|
||||||
|
<Action name="show-infopanel" group="settings_show"/>
|
||||||
|
</Menu>
|
||||||
|
</MenuBar>
|
||||||
|
<ToolBar name="mainToolBar">
|
||||||
|
<Action name="add"/>
|
||||||
|
<Action name="add-dir"/>
|
||||||
|
<Action name="delete"/>
|
||||||
|
<Action name="extract"/>
|
||||||
|
<Action name="preview"/>
|
||||||
|
</ToolBar>
|
||||||
|
</kpartgui>
|
266
ark/part/arkviewer.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
/*
|
||||||
|
* ark: A program for modifying archives via a GUI.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004-2008 Henrique Pinto <henrique.pinto@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 "arkviewer.h"
|
||||||
|
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KMimeTypeTrader>
|
||||||
|
#include <KMimeType>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KUrl>
|
||||||
|
#include <KGlobal>
|
||||||
|
#include <KIconLoader>
|
||||||
|
#include <KVBox>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KProgressDialog>
|
||||||
|
#include <KPushButton>
|
||||||
|
#include <KRun>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
ArkViewer::ArkViewer(QWidget * parent, Qt::WFlags flags)
|
||||||
|
: KDialog(parent, flags)
|
||||||
|
{
|
||||||
|
setButtons(Close);
|
||||||
|
m_widget = new KVBox(this);
|
||||||
|
m_widget->layout()->setSpacing(10);
|
||||||
|
|
||||||
|
setMainWidget(m_widget);
|
||||||
|
|
||||||
|
connect(this, SIGNAL(finished()), SLOT(dialogClosed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArkViewer::~ArkViewer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArkViewer::dialogClosed()
|
||||||
|
{
|
||||||
|
KConfigGroup conf = KGlobal::config()->group("Viewer");
|
||||||
|
saveDialogSize(conf);
|
||||||
|
|
||||||
|
if (m_part) {
|
||||||
|
KProgressDialog progressDialog
|
||||||
|
(this, i18n("Closing preview"),
|
||||||
|
i18n("Please wait while the preview is being closed..."));
|
||||||
|
|
||||||
|
progressDialog.setMinimumDuration(500);
|
||||||
|
progressDialog.setModal(true);
|
||||||
|
progressDialog.setAllowCancel(false);
|
||||||
|
progressDialog.progressBar()->setRange(0, 0);
|
||||||
|
|
||||||
|
// #261785: this preview dialog is not modal, so we need to delete
|
||||||
|
// the previewed file ourselves when the dialog is closed;
|
||||||
|
// we used to remove it at the end of ArkViewer::view() when
|
||||||
|
// QDialog::exec() was called instead of QDialog::show().
|
||||||
|
const QString previewedFilePath(m_part.data()->url().pathOrUrl());
|
||||||
|
|
||||||
|
m_part.data()->closeUrl();
|
||||||
|
|
||||||
|
if (!previewedFilePath.isEmpty()) {
|
||||||
|
QFile::remove(previewedFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArkViewer::view(const QString& fileName, QWidget *parent)
|
||||||
|
{
|
||||||
|
KMimeType::Ptr mimeType = KMimeType::findByPath(fileName);
|
||||||
|
kDebug() << "MIME type" << mimeType->name();
|
||||||
|
KService::Ptr viewer = ArkViewer::getViewer(mimeType);
|
||||||
|
|
||||||
|
const bool needsExternalViewer = (!viewer.isNull() &&
|
||||||
|
!viewer->hasServiceType(QLatin1String("KParts/ReadOnlyPart")));
|
||||||
|
if (needsExternalViewer) {
|
||||||
|
// We have already resolved the MIME type and the service above.
|
||||||
|
// So there is no point in using KRun::runUrl() which would need
|
||||||
|
// to do the same again.
|
||||||
|
|
||||||
|
const KUrl::List fileUrlList = KUrl(fileName);
|
||||||
|
// The last argument (tempFiles) set to true means that the temporary
|
||||||
|
// file will be removed when the viewer application exits.
|
||||||
|
KRun::run(*viewer, fileUrlList, parent, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool viewInInternalViewer = true;
|
||||||
|
if (viewer.isNull()) {
|
||||||
|
// No internal viewer available for the file. Ask the user if it
|
||||||
|
// should be previewed as text/plain.
|
||||||
|
|
||||||
|
int response;
|
||||||
|
if (!mimeType->isDefault()) {
|
||||||
|
// File has a defined MIME type, and not the default
|
||||||
|
// application/octet-stream. So it could be viewable as
|
||||||
|
// plain text, ask the user.
|
||||||
|
response = KMessageBox::warningContinueCancel(parent,
|
||||||
|
i18n("The internal viewer cannot preview this type of file<nl/>(%1).<nl/><nl/>Do you want to try to view it as plain text?", mimeType->name()),
|
||||||
|
i18nc("@title:window", "Cannot Preview File"),
|
||||||
|
KGuiItem(i18nc("@action:button", "Preview as Text"), KIcon(QLatin1String("text-plain"))),
|
||||||
|
KStandardGuiItem::cancel(),
|
||||||
|
QString(QLatin1String("PreviewAsText_%1")).arg(mimeType->name()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// No defined MIME type, or the default application/octet-stream.
|
||||||
|
// There is still a possibility that it could be viewable as plain
|
||||||
|
// text, so ask the user. Not the same as the message/question
|
||||||
|
// above, because the wording and default are different.
|
||||||
|
response = KMessageBox::warningContinueCancel(parent,
|
||||||
|
i18n("The internal viewer cannot preview this unknown type of file.<nl/><nl/>Do you want to try to view it as plain text?"),
|
||||||
|
i18nc("@title:window", "Cannot Preview File"),
|
||||||
|
KGuiItem(i18nc("@action:button", "Preview as Text"), KIcon(QLatin1String("text-plain"))),
|
||||||
|
KStandardGuiItem::cancel(),
|
||||||
|
QString(),
|
||||||
|
KMessageBox::Dangerous);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == KMessageBox::Cancel) {
|
||||||
|
viewInInternalViewer = false;
|
||||||
|
}
|
||||||
|
else { // set for viewer later
|
||||||
|
mimeType = KMimeType::mimeType(QLatin1String("text/plain"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewInInternalViewer) {
|
||||||
|
ArkViewer *internalViewer = new ArkViewer(parent, Qt::Window);
|
||||||
|
if (internalViewer->viewInInternalViewer(fileName, mimeType)) {
|
||||||
|
internalViewer->show();
|
||||||
|
// The internal viewer is showing the file, and will
|
||||||
|
// remove the temporary file in dialogClosed(). So there
|
||||||
|
// is no more to do here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
KMessageBox::sorry(parent, i18n("The internal viewer cannot preview this file."));
|
||||||
|
delete internalViewer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only get here if there is no internal viewer available or could be
|
||||||
|
// used for the file, and no external viewer was opened. Nothing can be
|
||||||
|
// done with the temporary file, so remove it now.
|
||||||
|
QFile::remove(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArkViewer::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
KPushButton *defButton = button(defaultButton());
|
||||||
|
|
||||||
|
// Only handle the event the usual way if the default button has focus
|
||||||
|
// Otherwise, pressing enter on KatePart still closes the dialog, for example.
|
||||||
|
if ((defButton) && (defButton->hasFocus())) {
|
||||||
|
KDialog::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This sets the default size of the dialog. It will only take effect in the case
|
||||||
|
// where there is no saved size in the config file - it sets the default values
|
||||||
|
// for KDialog::restoreDialogSize().
|
||||||
|
QSize ArkViewer::sizeHint() const
|
||||||
|
{
|
||||||
|
return QSize(560, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArkViewer::viewInInternalViewer(const QString& fileName, const KMimeType::Ptr& mimeType)
|
||||||
|
{
|
||||||
|
const KUrl fileUrl(fileName);
|
||||||
|
|
||||||
|
setCaption(fileUrl.fileName());
|
||||||
|
restoreDialogSize(KGlobal::config()->group("Viewer"));
|
||||||
|
|
||||||
|
QFrame *header = new QFrame(m_widget);
|
||||||
|
QHBoxLayout *headerLayout = new QHBoxLayout(header);
|
||||||
|
|
||||||
|
QLabel *iconLabel = new QLabel(header);
|
||||||
|
headerLayout->addWidget(iconLabel);
|
||||||
|
iconLabel->setPixmap(KIconLoader::global()->loadMimeTypeIcon(mimeType->iconName(), KIconLoader::Desktop));
|
||||||
|
iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
KVBox *headerRight = new KVBox(header);
|
||||||
|
headerLayout->addWidget(headerRight);
|
||||||
|
new QLabel(QString(QLatin1String( "<qt><b>%1</b></qt>" ))
|
||||||
|
.arg(fileUrl.fileName()), headerRight
|
||||||
|
);
|
||||||
|
new QLabel(mimeType->comment(), headerRight);
|
||||||
|
|
||||||
|
header->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||||
|
|
||||||
|
m_part = KMimeTypeTrader::self()->createPartInstanceFromQuery<KParts::ReadOnlyPart>(mimeType->name(),
|
||||||
|
m_widget,
|
||||||
|
this);
|
||||||
|
|
||||||
|
if (!m_part.data()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_part.data()->browserExtension()) {
|
||||||
|
connect(m_part.data()->browserExtension(),
|
||||||
|
SIGNAL(openUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)),
|
||||||
|
SLOT(slotOpenUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_part.data()->openUrl(fileUrl);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArkViewer::slotOpenUrlRequestDelayed(const KUrl& url, const KParts::OpenUrlArguments& arguments, const KParts::BrowserArguments& browserArguments)
|
||||||
|
{
|
||||||
|
kDebug() << "Opening URL: " << url;
|
||||||
|
|
||||||
|
Q_UNUSED(arguments)
|
||||||
|
Q_UNUSED(browserArguments)
|
||||||
|
|
||||||
|
KRun *runner = new KRun(url, 0, 0, false);
|
||||||
|
runner->setRunExecutables(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
KService::Ptr ArkViewer::getViewer(const KMimeType::Ptr &mimeType)
|
||||||
|
{
|
||||||
|
// No point in even trying to find anything for application/octet-stream
|
||||||
|
if (mimeType->isDefault()) {
|
||||||
|
return KService::Ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get a read-only kpart for the internal viewer
|
||||||
|
KService::List offers = KMimeTypeTrader::self()->query(mimeType->name(), QString::fromLatin1("KParts/ReadOnlyPart"));
|
||||||
|
|
||||||
|
// If we can't find a kpart, try to get an external application
|
||||||
|
if (offers.size() == 0) {
|
||||||
|
offers = KMimeTypeTrader::self()->query(mimeType->name(), QString::fromLatin1("Application"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offers.size() > 0) {
|
||||||
|
return offers.first();
|
||||||
|
} else {
|
||||||
|
return KService::Ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "arkviewer.moc"
|
63
ark/part/arkviewer.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* ark: A program for modifying archives via a GUI.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004-2008, Henrique Pinto <henrique.pinto@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 ARKVIEWER_H
|
||||||
|
#define ARKVIEWER_H
|
||||||
|
|
||||||
|
#include <KDialog>
|
||||||
|
#include <KMimeType>
|
||||||
|
#include <KParts/BrowserExtension>
|
||||||
|
#include <KParts/ReadOnlyPart>
|
||||||
|
#include <KService>
|
||||||
|
|
||||||
|
#include <QtCore/QWeakPointer>
|
||||||
|
|
||||||
|
class ArkViewer : public KDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~ArkViewer();
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
|
||||||
|
static void view(const QString& fileName, QWidget* parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void keyPressEvent(QKeyEvent *event);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void slotOpenUrlRequestDelayed(const KUrl& url, const KParts::OpenUrlArguments& arguments, const KParts::BrowserArguments& browserArguments);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void dialogClosed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit ArkViewer(QWidget* parent = 0, Qt::WFlags flags = 0);
|
||||||
|
|
||||||
|
static KService::Ptr getViewer(const KMimeType::Ptr& mimeType);
|
||||||
|
bool viewInInternalViewer(const QString& fileName, const KMimeType::Ptr& mimeType);
|
||||||
|
|
||||||
|
QWeakPointer<KParts::ReadOnlyPart> m_part;
|
||||||
|
QWidget *m_widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ARKVIEWER_H
|
||||||
|
|
8
ark/part/dnddbusinterface.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<node>
|
||||||
|
<interface name="org.kde.ark.DndExtract">
|
||||||
|
<method name="extractSelectedFilesTo">
|
||||||
|
<arg direction="in" type="s" name="path" />
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
213
ark/part/infopanel.cpp
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@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 "infopanel.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include <KLocale>
|
||||||
|
#include <KMimeType>
|
||||||
|
#include <KIconLoader>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
|
||||||
|
using namespace Kerfuffle;
|
||||||
|
|
||||||
|
static QPixmap getMimeIcon(const QString& mimeName)
|
||||||
|
{
|
||||||
|
return KIconLoader::global()->loadMimeTypeIcon(mimeName, KIconLoader::Desktop, KIconLoader::SizeHuge);
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoPanel::InfoPanel(ArchiveModel *model, QWidget *parent)
|
||||||
|
: QFrame(parent), m_model(model)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
// Make the file name font bigger than the rest
|
||||||
|
QFont fnt = fileName->font();
|
||||||
|
if (fnt.pointSize() > -1) {
|
||||||
|
fnt.setPointSize(fnt.pointSize() + 1);
|
||||||
|
} else {
|
||||||
|
fnt.setPixelSize(fnt.pixelSize() + 3);
|
||||||
|
}
|
||||||
|
fileName->setFont(fnt);
|
||||||
|
|
||||||
|
updateWithDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoPanel::~InfoPanel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::updateWithDefaults()
|
||||||
|
{
|
||||||
|
iconLabel->setPixmap(KIconLoader::global()->loadIcon(QLatin1String( "utilities-file-archiver" ), KIconLoader::Desktop, KIconLoader::SizeHuge));
|
||||||
|
|
||||||
|
const QString currentFileName = prettyFileName();
|
||||||
|
|
||||||
|
if (currentFileName.isEmpty()) {
|
||||||
|
fileName->setText(i18n("No archive loaded"));
|
||||||
|
} else {
|
||||||
|
fileName->setText(currentFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalInfo->setText(QString());
|
||||||
|
hideMetaData();
|
||||||
|
hideActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString InfoPanel::prettyFileName() const
|
||||||
|
{
|
||||||
|
if (m_prettyFileName.isEmpty()) {
|
||||||
|
if (m_model->archive()) {
|
||||||
|
QFileInfo fileInfo(m_model->archive()->fileName());
|
||||||
|
return fileInfo.fileName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_prettyFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::setPrettyFileName(const QString& fileName)
|
||||||
|
{
|
||||||
|
m_prettyFileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::setIndex(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (!index.isValid()) {
|
||||||
|
updateWithDefaults();
|
||||||
|
} else {
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
|
||||||
|
KMimeType::Ptr mimeType;
|
||||||
|
|
||||||
|
if (entry[ IsDirectory ].toBool()) {
|
||||||
|
mimeType = KMimeType::mimeType(QLatin1String( "inode/directory" ));
|
||||||
|
} else {
|
||||||
|
mimeType = KMimeType::findByPath(entry[ FileName ].toString(), 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
iconLabel->setPixmap(getMimeIcon(mimeType->iconName()));
|
||||||
|
if (entry[ IsDirectory ].toBool()) {
|
||||||
|
int dirs;
|
||||||
|
int files;
|
||||||
|
const int children = m_model->childCount(index, dirs, files);
|
||||||
|
additionalInfo->setText(KIO::itemsSummaryString(children, files, dirs, 0, false));
|
||||||
|
} else if (entry.contains(Link)) {
|
||||||
|
additionalInfo->setText(i18n("Symbolic Link"));
|
||||||
|
} else {
|
||||||
|
if (entry.contains(Size)) {
|
||||||
|
additionalInfo->setText(KIO::convertSize(entry[ Size ].toULongLong()));
|
||||||
|
} else {
|
||||||
|
additionalInfo->setText(i18n("Unknown size"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList nameParts = entry[ FileName ].toString().split(QLatin1Char( '/' ), QString::SkipEmptyParts);
|
||||||
|
const QString name = (nameParts.count() > 0) ? nameParts.last() : entry[ FileName ].toString();
|
||||||
|
fileName->setText(name);
|
||||||
|
|
||||||
|
metadataLabel->setText(metadataTextFor(index));
|
||||||
|
showMetaData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::setIndexes(const QModelIndexList &list)
|
||||||
|
{
|
||||||
|
if (list.size() == 0) {
|
||||||
|
setIndex(QModelIndex());
|
||||||
|
} else if (list.size() == 1) {
|
||||||
|
setIndex(list[ 0 ]);
|
||||||
|
} else {
|
||||||
|
iconLabel->setPixmap(KIconLoader::global()->loadIcon(QLatin1String( "utilities-file-archiver" ), KIconLoader::Desktop, KIconLoader::SizeHuge));
|
||||||
|
fileName->setText(i18np("One file selected", "%1 files selected", list.size()));
|
||||||
|
quint64 totalSize = 0;
|
||||||
|
foreach(const QModelIndex& index, list) {
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
totalSize += entry[ Size ].toULongLong();
|
||||||
|
}
|
||||||
|
additionalInfo->setText(KIO::convertSize(totalSize));
|
||||||
|
hideMetaData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::showMetaData()
|
||||||
|
{
|
||||||
|
firstSeparator->show();
|
||||||
|
metadataLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::hideMetaData()
|
||||||
|
{
|
||||||
|
firstSeparator->hide();
|
||||||
|
metadataLabel->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::showActions()
|
||||||
|
{
|
||||||
|
secondSeparator->show();
|
||||||
|
actionsLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoPanel::hideActions()
|
||||||
|
{
|
||||||
|
secondSeparator->hide();
|
||||||
|
actionsLabel->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString InfoPanel::metadataTextFor(const QModelIndex &index)
|
||||||
|
{
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
KMimeType::Ptr mimeType;
|
||||||
|
|
||||||
|
if (entry[ IsDirectory ].toBool()) {
|
||||||
|
mimeType = KMimeType::mimeType(QLatin1String( "inode/directory" ));
|
||||||
|
} else {
|
||||||
|
mimeType = KMimeType::findByPath(entry[ FileName ].toString(), 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
text += i18n("<b>Type:</b> %1<br/>", mimeType->comment());
|
||||||
|
|
||||||
|
if (entry.contains(Owner)) {
|
||||||
|
text += i18n("<b>Owner:</b> %1<br/>", entry[ Owner ].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.contains(Group)) {
|
||||||
|
text += i18n("<b>Group:</b> %1<br/>", entry[ Group ].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.contains(Link)) {
|
||||||
|
text += i18n("<b>Target:</b> %1<br/>", entry[ Link ].toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.contains(IsPasswordProtected) && entry[ IsPasswordProtected ].toBool()) {
|
||||||
|
text += i18n("<b>Password protected:</b> Yes<br/>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "infopanel.moc"
|
76
ark/part/infopanel.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@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 INFOPANEL_H
|
||||||
|
#define INFOPANEL_H
|
||||||
|
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "archivemodel.h"
|
||||||
|
#include "ui_infopanel.h"
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
class InfoPanel: public QFrame, Ui::InformationPanel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit InfoPanel(ArchiveModel *model, QWidget *parent = 0);
|
||||||
|
virtual ~InfoPanel();
|
||||||
|
|
||||||
|
void setIndex(const QModelIndex &);
|
||||||
|
void setIndexes(const QModelIndexList &list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file name that is displayed on the info panel.
|
||||||
|
*
|
||||||
|
* @return The current file name. If no pretty name has been
|
||||||
|
* set, it returns the name of the loaded archive.
|
||||||
|
*/
|
||||||
|
QString prettyFileName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a different file name for the current open archive.
|
||||||
|
*
|
||||||
|
* This is particularly useful when a temporary archive (from
|
||||||
|
* a remote location) is loaded, and the window title shows the
|
||||||
|
* remote file name and the info panel, by default, would show
|
||||||
|
* the name of the temporary downloaded file.
|
||||||
|
*
|
||||||
|
* @param fileName The new file name.
|
||||||
|
*/
|
||||||
|
void setPrettyFileName(const QString& fileName);
|
||||||
|
|
||||||
|
void updateWithDefaults();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void showMetaData();
|
||||||
|
void hideMetaData();
|
||||||
|
|
||||||
|
void showActions();
|
||||||
|
void hideActions();
|
||||||
|
|
||||||
|
QString metadataTextFor(const QModelIndex &);
|
||||||
|
|
||||||
|
ArchiveModel *m_model;
|
||||||
|
QString m_prettyFileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INFOPANEL_H
|
126
ark/part/infopanel.ui
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>InformationPanel</class>
|
||||||
|
<widget class="QWidget" name="InformationPanel" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>118</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Maximum" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Information Panel</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="iconLabel" >
|
||||||
|
<property name="text" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="KSqueezedTextLabel" name="fileName">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">KSqueezedTextLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textElideMode">
|
||||||
|
<enum>Qt::ElideRight</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="additionalInfo" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Unknown file type</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="firstSeparator" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="metadataLabel" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Metadata Label</string>
|
||||||
|
</property>
|
||||||
|
<property name="margin" >
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="indent" >
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="secondSeparator" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="actionsLabel" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>ActionsLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KSqueezedTextLabel</class>
|
||||||
|
<extends>QLabel</extends>
|
||||||
|
<header>ksqueezedtextlabel.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
37
ark/part/interface.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@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 INTERFACE_H
|
||||||
|
#define INTERFACE_H
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QtPlugin>
|
||||||
|
|
||||||
|
class Interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Interface() {}
|
||||||
|
|
||||||
|
virtual bool isBusy() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_INTERFACE(Interface, "org.kde.kerfuffle.partinterface/0.42")
|
||||||
|
|
||||||
|
#endif // INTERFACE_H
|
107
ark/part/jobtracker.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 "jobtracker.h"
|
||||||
|
|
||||||
|
#include <KDebug>
|
||||||
|
|
||||||
|
JobTrackerWidget::JobTrackerWidget(QWidget *parent)
|
||||||
|
: QFrame(parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JobTracker::JobTracker(QWidget *parent)
|
||||||
|
: KAbstractWidgetJobTracker(parent)
|
||||||
|
{
|
||||||
|
m_ui = new JobTrackerWidget(parent);
|
||||||
|
resetUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
JobTracker::~JobTracker()
|
||||||
|
{
|
||||||
|
foreach(KJob *job, m_jobs) {
|
||||||
|
job->kill();
|
||||||
|
delete job;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::description(KJob *job, const QString &title, const QPair< QString, QString > &f1, const QPair< QString, QString > &f2)
|
||||||
|
{
|
||||||
|
Q_UNUSED(job)
|
||||||
|
Q_UNUSED(f1)
|
||||||
|
Q_UNUSED(f2)
|
||||||
|
m_ui->descriptionLabel->setText(QString(QLatin1String( "<b>%1</b>" )).arg(title));
|
||||||
|
m_ui->descriptionLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::infoMessage(KJob *job, const QString &plain, const QString &rich)
|
||||||
|
{
|
||||||
|
Q_UNUSED(job)
|
||||||
|
Q_UNUSED(rich)
|
||||||
|
m_ui->informationLabel->setText(plain);
|
||||||
|
m_ui->informationLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::warning(KJob *job, const QString &plain, const QString &rich)
|
||||||
|
{
|
||||||
|
Q_UNUSED(job)
|
||||||
|
Q_UNUSED(rich)
|
||||||
|
m_ui->informationLabel->setText(plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::registerJob(KJob *job)
|
||||||
|
{
|
||||||
|
m_jobs << job;
|
||||||
|
KJobTrackerInterface::registerJob(job);
|
||||||
|
m_ui->show();
|
||||||
|
m_ui->informationLabel->hide();
|
||||||
|
m_ui->progressBar->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::percent(KJob *job, unsigned long percent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(job)
|
||||||
|
m_ui->progressBar->setMaximum(100);
|
||||||
|
m_ui->progressBar->setMinimum(0);
|
||||||
|
m_ui->progressBar->setValue(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::unregisterJob(KJob *job)
|
||||||
|
{
|
||||||
|
m_jobs.remove(job);
|
||||||
|
KJobTrackerInterface::unregisterJob(job);
|
||||||
|
resetUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JobTracker::resetUi()
|
||||||
|
{
|
||||||
|
m_ui->hide();
|
||||||
|
m_ui->descriptionLabel->hide();
|
||||||
|
m_ui->informationLabel->hide();
|
||||||
|
m_ui->progressBar->setMaximum(0);
|
||||||
|
m_ui->progressBar->setMinimum(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* JobTracker::widget(KJob *)
|
||||||
|
{
|
||||||
|
return m_ui;
|
||||||
|
}
|
68
ark/part/jobtracker.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
*
|
||||||
|
* 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 JOBTRACKER_H
|
||||||
|
#define JOBTRACKER_H
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <kabstractwidgetjobtracker.h>
|
||||||
|
#include "ui_jobtracker.h"
|
||||||
|
|
||||||
|
class KJob;
|
||||||
|
|
||||||
|
class JobTrackerWidget: public QFrame, public Ui::JobTrackerWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
JobTrackerWidget(QWidget *parent = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
class JobTracker: public KAbstractWidgetJobTracker
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
JobTracker(QWidget *parent = 0);
|
||||||
|
~JobTracker();
|
||||||
|
|
||||||
|
virtual QWidget *widget(KJob *);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void registerJob(KJob *job);
|
||||||
|
virtual void unregisterJob(KJob *job);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void description(KJob *job, const QString &title, const QPair< QString, QString > &f1, const QPair< QString, QString > &f2);
|
||||||
|
virtual void infoMessage(KJob *job, const QString &plain, const QString &rich);
|
||||||
|
virtual void warning(KJob *job, const QString &plain, const QString &rich);
|
||||||
|
|
||||||
|
virtual void percent(KJob *job, unsigned long percent);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void resetUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
JobTrackerWidget *m_ui;
|
||||||
|
QSet<KJob*> m_jobs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JOBTRACKER_H
|
92
ark/part/jobtracker.ui
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<ui version="4.0" >
|
||||||
|
<class>JobTrackerWidget</class>
|
||||||
|
<widget class="QWidget" name="JobTrackerWidget" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>409</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Job Tracker</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<property name="leftMargin" >
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin" >
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin" >
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin" >
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="descriptionLabel" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string><b>Job Description</b></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="informationLabel" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Some Information about the job</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progressBar" >
|
||||||
|
<property name="sizePolicy" >
|
||||||
|
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize" >
|
||||||
|
<size>
|
||||||
|
<width>50</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum" >
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="value" >
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
916
ark/part/part.cpp
Normal file
|
@ -0,0 +1,916 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.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 "part.h"
|
||||||
|
#include "archivemodel.h"
|
||||||
|
#include "archiveview.h"
|
||||||
|
#include "arkviewer.h"
|
||||||
|
#include "dnddbusinterfaceadaptor.h"
|
||||||
|
#include "infopanel.h"
|
||||||
|
#include "jobtracker.h"
|
||||||
|
#include "kerfuffle/archive.h"
|
||||||
|
#include "kerfuffle/extractiondialog.h"
|
||||||
|
#include "kerfuffle/jobs.h"
|
||||||
|
#include "kerfuffle/settings.h"
|
||||||
|
|
||||||
|
#include <KAboutData>
|
||||||
|
#include <KAction>
|
||||||
|
#include <KActionCollection>
|
||||||
|
#include <KApplication>
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KDebug>
|
||||||
|
#include <KFileDialog>
|
||||||
|
#include <KGuiItem>
|
||||||
|
#include <KIO/Job>
|
||||||
|
#include <KIO/NetAccess>
|
||||||
|
#include <KIcon>
|
||||||
|
#include <KInputDialog>
|
||||||
|
#include <KMessageBox>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
#include <KRun>
|
||||||
|
#include <KSelectAction>
|
||||||
|
#include <KStandardDirs>
|
||||||
|
#include <KStandardGuiItem>
|
||||||
|
#include <KTempDir>
|
||||||
|
#include <KToggleAction>
|
||||||
|
#include <KXMLGUIFactory>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWeakPointer>
|
||||||
|
#include <QtDBus/QtDBus>
|
||||||
|
|
||||||
|
using namespace Kerfuffle;
|
||||||
|
|
||||||
|
K_PLUGIN_FACTORY(Factory, registerPlugin<Ark::Part>();)
|
||||||
|
K_EXPORT_PLUGIN(Factory("ark"))
|
||||||
|
|
||||||
|
namespace Ark
|
||||||
|
{
|
||||||
|
|
||||||
|
static quint32 s_instanceCounter = 1;
|
||||||
|
|
||||||
|
Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList& args)
|
||||||
|
: KParts::ReadWritePart(parent),
|
||||||
|
m_splitter(0),
|
||||||
|
m_busy(false),
|
||||||
|
m_jobTracker(0)
|
||||||
|
{
|
||||||
|
Q_UNUSED(args)
|
||||||
|
setComponentData(Factory::componentData(), false);
|
||||||
|
|
||||||
|
new DndExtractAdaptor(this);
|
||||||
|
|
||||||
|
const QString pathName = QString(QLatin1String("/DndExtract/%1")).arg(s_instanceCounter++);
|
||||||
|
if (!QDBusConnection::sessionBus().registerObject(pathName, this)) {
|
||||||
|
kFatal() << "Could not register a D-Bus object for drag'n'drop";
|
||||||
|
}
|
||||||
|
|
||||||
|
m_model = new ArchiveModel(pathName, this);
|
||||||
|
|
||||||
|
m_splitter = new QSplitter(Qt::Horizontal, parentWidget);
|
||||||
|
setWidget(m_splitter);
|
||||||
|
|
||||||
|
m_view = new ArchiveView;
|
||||||
|
m_infoPanel = new InfoPanel(m_model);
|
||||||
|
|
||||||
|
m_splitter->addWidget(m_view);
|
||||||
|
m_splitter->addWidget(m_infoPanel);
|
||||||
|
|
||||||
|
QList<int> splitterSizes = ArkSettings::splitterSizes();
|
||||||
|
if (splitterSizes.isEmpty()) {
|
||||||
|
splitterSizes.append(200);
|
||||||
|
splitterSizes.append(100);
|
||||||
|
}
|
||||||
|
m_splitter->setSizes(splitterSizes);
|
||||||
|
|
||||||
|
setupView();
|
||||||
|
setupActions();
|
||||||
|
|
||||||
|
connect(m_model, SIGNAL(loadingStarted()),
|
||||||
|
this, SLOT(slotLoadingStarted()));
|
||||||
|
connect(m_model, SIGNAL(loadingFinished(KJob*)),
|
||||||
|
this, SLOT(slotLoadingFinished(KJob*)));
|
||||||
|
connect(m_model, SIGNAL(droppedFiles(QStringList,QString)),
|
||||||
|
this, SLOT(slotAddFiles(QStringList,QString)));
|
||||||
|
connect(m_model, SIGNAL(error(QString,QString)),
|
||||||
|
this, SLOT(slotError(QString,QString)));
|
||||||
|
|
||||||
|
connect(this, SIGNAL(busy()),
|
||||||
|
this, SLOT(setBusyGui()));
|
||||||
|
connect(this, SIGNAL(ready()),
|
||||||
|
this, SLOT(setReadyGui()));
|
||||||
|
connect(this, SIGNAL(completed()),
|
||||||
|
this, SLOT(setFileNameFromArchive()));
|
||||||
|
|
||||||
|
m_statusBarExtension = new KParts::StatusBarExtension(this);
|
||||||
|
|
||||||
|
setXMLFile(QLatin1String( "ark_part.rc" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
Part::~Part()
|
||||||
|
{
|
||||||
|
factory()->removeClient(this);
|
||||||
|
|
||||||
|
saveSplitterSizes();
|
||||||
|
|
||||||
|
m_extractFilesAction->menu()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::registerJob(KJob* job)
|
||||||
|
{
|
||||||
|
if (!m_jobTracker) {
|
||||||
|
m_jobTracker = new JobTracker(widget());
|
||||||
|
m_statusBarExtension->addStatusBarItem(m_jobTracker->widget(0), 0, true);
|
||||||
|
m_jobTracker->widget(job)->show();
|
||||||
|
}
|
||||||
|
m_jobTracker->registerJob(job);
|
||||||
|
|
||||||
|
emit busy();
|
||||||
|
connect(job, SIGNAL(result(KJob*)), this, SIGNAL(ready()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: One should construct a KUrl out of localPath in order to be able to handle
|
||||||
|
// non-local destinations (ie. trash:/ or a remote location)
|
||||||
|
// See bugs #189322 and #204323.
|
||||||
|
void Part::extractSelectedFilesTo(const QString& localPath)
|
||||||
|
{
|
||||||
|
kDebug() << "Extract to " << localPath;
|
||||||
|
if (!m_model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_view->selectionModel()->selectedRows().count() != 1) {
|
||||||
|
m_view->selectionModel()->setCurrentIndex(m_view->currentIndex(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||||
|
}
|
||||||
|
if (m_view->selectionModel()->selectedRows().count() != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant internalRoot;
|
||||||
|
kDebug() << "valid " << m_view->currentIndex().parent().isValid();
|
||||||
|
if (m_view->currentIndex().parent().isValid()) {
|
||||||
|
internalRoot = m_model->entryForIndex(m_view->currentIndex().parent()).value(InternalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internalRoot.isNull()) {
|
||||||
|
//we have the special case valid parent, but the parent does not
|
||||||
|
//actually correspond to an item in the archive, but an automatically
|
||||||
|
//created folder. for now, we will just use the filename of the node
|
||||||
|
//instead, but for plugins that rely on a non-filename value as the
|
||||||
|
//InternalId, this WILL break things. TODO find a solution
|
||||||
|
internalRoot = m_model->entryForIndex(m_view->currentIndex().parent()).value(FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QVariant> files = selectedFilesWithChildren();
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "selected files are " << files;
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
options[QLatin1String( "PreservePaths" )] = true;
|
||||||
|
if (!internalRoot.isNull()) {
|
||||||
|
options[QLatin1String("RootNode")] = internalRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtractJob *job = m_model->extractFiles(files, localPath, options);
|
||||||
|
registerJob(job);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotExtractionDone(KJob*)));
|
||||||
|
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setupView()
|
||||||
|
{
|
||||||
|
m_view->setModel(m_model);
|
||||||
|
|
||||||
|
m_view->setSortingEnabled(true);
|
||||||
|
|
||||||
|
connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||||
|
this, SLOT(updateActions()));
|
||||||
|
connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||||
|
this, SLOT(selectionChanged()));
|
||||||
|
|
||||||
|
//TODO: fix an actual eventhandler
|
||||||
|
connect(m_view, SIGNAL(itemTriggered(QModelIndex)),
|
||||||
|
this, SLOT(slotPreview(QModelIndex)));
|
||||||
|
|
||||||
|
connect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
||||||
|
this, SLOT(adjustColumns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setupActions()
|
||||||
|
{
|
||||||
|
KToggleAction *showInfoPanelAction = new KToggleAction(i18nc("@action:inmenu", "Show information panel"), this);
|
||||||
|
actionCollection()->addAction(QLatin1String( "show-infopanel" ), showInfoPanelAction);
|
||||||
|
showInfoPanelAction->setChecked(m_splitter->sizes().at(1) > 0);
|
||||||
|
connect(showInfoPanelAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotToggleInfoPanel(bool)));
|
||||||
|
|
||||||
|
m_saveAsAction = KStandardAction::saveAs(this, SLOT(slotSaveAs()), actionCollection());
|
||||||
|
|
||||||
|
m_previewAction = actionCollection()->addAction(QLatin1String( "preview" ));
|
||||||
|
m_previewAction->setText(i18nc("to preview a file inside an archive", "Pre&view"));
|
||||||
|
m_previewAction->setIcon(KIcon( QLatin1String( "document-preview-archive" )));
|
||||||
|
m_previewAction->setStatusTip(i18n("Click to preview the selected file"));
|
||||||
|
m_previewAction->setShortcuts(QList<QKeySequence>() << Qt::Key_Return << Qt::Key_Space);
|
||||||
|
connect(m_previewAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotPreview()));
|
||||||
|
|
||||||
|
m_extractFilesAction = actionCollection()->addAction(QLatin1String( "extract" ));
|
||||||
|
m_extractFilesAction->setText(i18n("E&xtract"));
|
||||||
|
m_extractFilesAction->setIcon(KIcon( QLatin1String( "archive-extract" )));
|
||||||
|
m_extractFilesAction->setStatusTip(i18n("Click to open an extraction dialog, where you can choose to extract either all files or just the selected ones"));
|
||||||
|
m_extractFilesAction->setShortcut(QKeySequence( QLatin1String( "Ctrl+E" ) ));
|
||||||
|
connect(m_extractFilesAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotExtractFiles()));
|
||||||
|
|
||||||
|
m_addFilesAction = actionCollection()->addAction(QLatin1String( "add" ));
|
||||||
|
m_addFilesAction->setIcon(KIcon( QLatin1String( "archive-insert" )));
|
||||||
|
m_addFilesAction->setText(i18n("Add &File..."));
|
||||||
|
m_addFilesAction->setStatusTip(i18n("Click to add files to the archive"));
|
||||||
|
connect(m_addFilesAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotAddFiles()));
|
||||||
|
|
||||||
|
m_addDirAction = actionCollection()->addAction(QLatin1String( "add-dir" ));
|
||||||
|
m_addDirAction->setIcon(KIcon( QLatin1String( "archive-insert-directory" )));
|
||||||
|
m_addDirAction->setText(i18n("Add Fo&lder..."));
|
||||||
|
m_addDirAction->setStatusTip(i18n("Click to add a folder to the archive"));
|
||||||
|
connect(m_addDirAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotAddDir()));
|
||||||
|
|
||||||
|
m_deleteFilesAction = actionCollection()->addAction(QLatin1String( "delete" ));
|
||||||
|
m_deleteFilesAction->setIcon(KIcon( QLatin1String( "archive-remove" )));
|
||||||
|
m_deleteFilesAction->setText(i18n("De&lete"));
|
||||||
|
m_deleteFilesAction->setShortcut(Qt::Key_Delete);
|
||||||
|
m_deleteFilesAction->setStatusTip(i18n("Click to delete the selected files"));
|
||||||
|
connect(m_deleteFilesAction, SIGNAL(triggered(bool)),
|
||||||
|
this, SLOT(slotDeleteFiles()));
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::updateActions()
|
||||||
|
{
|
||||||
|
bool isWritable = m_model->archive() && (!m_model->archive()->isReadOnly());
|
||||||
|
|
||||||
|
m_previewAction->setEnabled(!isBusy() && (m_view->selectionModel()->selectedRows().count() == 1)
|
||||||
|
&& isPreviewable(m_view->selectionModel()->currentIndex()));
|
||||||
|
m_extractFilesAction->setEnabled(!isBusy() && (m_model->rowCount() > 0));
|
||||||
|
m_addFilesAction->setEnabled(!isBusy() && isWritable);
|
||||||
|
m_addDirAction->setEnabled(!isBusy() && isWritable);
|
||||||
|
m_deleteFilesAction->setEnabled(!isBusy() && (m_view->selectionModel()->selectedRows().count() > 0)
|
||||||
|
&& isWritable);
|
||||||
|
|
||||||
|
QMenu *menu = m_extractFilesAction->menu();
|
||||||
|
if (!menu) {
|
||||||
|
menu = new QMenu;
|
||||||
|
m_extractFilesAction->setMenu(menu);
|
||||||
|
connect(menu, SIGNAL(triggered(QAction*)),
|
||||||
|
this, SLOT(slotQuickExtractFiles(QAction*)));
|
||||||
|
|
||||||
|
// Remember to keep this action's properties as similar to
|
||||||
|
// m_extractFilesAction's as possible (except where it does not make
|
||||||
|
// sense, such as the text or the shortcut).
|
||||||
|
QAction *extractTo = menu->addAction(i18n("Extract To..."));
|
||||||
|
extractTo->setIcon(m_extractFilesAction->icon());
|
||||||
|
extractTo->setStatusTip(m_extractFilesAction->statusTip());
|
||||||
|
connect(extractTo, SIGNAL(triggered(bool)), SLOT(slotExtractFiles()));
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
|
QAction *header = menu->addAction(i18n("Quick Extract To..."));
|
||||||
|
header->setEnabled(false);
|
||||||
|
header->setIcon(KIcon( QLatin1String( "archive-extract" )));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (menu->actions().size() > 3) {
|
||||||
|
menu->removeAction(menu->actions().last());
|
||||||
|
}
|
||||||
|
|
||||||
|
const KConfigGroup conf(KGlobal::config(), "DirSelect Dialog");
|
||||||
|
const QStringList dirHistory = conf.readPathEntry("History Items", QStringList());
|
||||||
|
|
||||||
|
for (int i = 0; i < qMin(10, dirHistory.size()); ++i) {
|
||||||
|
const KUrl dirUrl(dirHistory.at(i));
|
||||||
|
QAction *newAction = menu->addAction(dirUrl.pathOrUrl());
|
||||||
|
newAction->setData(dirUrl.pathOrUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotQuickExtractFiles(QAction *triggeredAction)
|
||||||
|
{
|
||||||
|
// #190507: triggeredAction->data.isNull() means it's the "Extract to..."
|
||||||
|
// action, and we do not want it to run here
|
||||||
|
if (!triggeredAction->data().isNull()) {
|
||||||
|
kDebug() << "Extract to " << triggeredAction->data().toString();
|
||||||
|
|
||||||
|
const QString userDestination = triggeredAction->data().toString();
|
||||||
|
QString finalDestinationDirectory;
|
||||||
|
const QString detectedSubfolder = detectSubfolder();
|
||||||
|
|
||||||
|
if (!isSingleFolderArchive()) {
|
||||||
|
finalDestinationDirectory = userDestination +
|
||||||
|
QDir::separator() + detectedSubfolder;
|
||||||
|
QDir(userDestination).mkdir(detectedSubfolder);
|
||||||
|
} else {
|
||||||
|
finalDestinationDirectory = userDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
options[QLatin1String( "PreservePaths" )] = true;
|
||||||
|
QList<QVariant> files = selectedFiles();
|
||||||
|
ExtractJob *job = m_model->extractFiles(files, finalDestinationDirectory, options);
|
||||||
|
registerJob(job);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotExtractionDone(KJob*)));
|
||||||
|
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Part::isPreviewable(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
return index.isValid() && (!m_model->entryForIndex(index)[ IsDirectory ].toBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::selectionChanged()
|
||||||
|
{
|
||||||
|
m_infoPanel->setIndexes(m_view->selectionModel()->selectedRows());
|
||||||
|
}
|
||||||
|
|
||||||
|
KAboutData* Part::createAboutData()
|
||||||
|
{
|
||||||
|
return new KAboutData("ark", 0, ki18n("ArkPart"), "3.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Part::openFile()
|
||||||
|
{
|
||||||
|
const QString localFile(localFilePath());
|
||||||
|
const QFileInfo localFileInfo(localFile);
|
||||||
|
const bool creatingNewArchive =
|
||||||
|
arguments().metaData()[QLatin1String("createNewArchive")] == QLatin1String("true");
|
||||||
|
|
||||||
|
if (localFileInfo.isDir()) {
|
||||||
|
KMessageBox::error(NULL, i18nc("@info",
|
||||||
|
"<filename>%1</filename> is a directory.",
|
||||||
|
localFile));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creatingNewArchive) {
|
||||||
|
if (localFileInfo.exists()) {
|
||||||
|
int overwrite = KMessageBox::questionYesNo(NULL, i18nc("@info", "The archive <filename>%1</filename> already exists. Would you like to open it instead?", localFile), i18nc("@title:window", "File Exists"), KGuiItem(i18n("Open File")), KStandardGuiItem::cancel());
|
||||||
|
|
||||||
|
if (overwrite == KMessageBox::No) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!localFileInfo.exists()) {
|
||||||
|
KMessageBox::sorry(NULL, i18nc("@info", "The archive <filename>%1</filename> was not found.", localFile), i18nc("@title:window", "Error Opening Archive"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QScopedPointer<Kerfuffle::Archive> archive(Kerfuffle::Archive::create(localFile, m_model));
|
||||||
|
|
||||||
|
if ((!archive) || ((creatingNewArchive) && (archive->isReadOnly()))) {
|
||||||
|
QStringList mimeTypeList;
|
||||||
|
QHash<QString, QString> mimeTypes;
|
||||||
|
|
||||||
|
if (creatingNewArchive) {
|
||||||
|
mimeTypeList = Kerfuffle::supportedWriteMimeTypes();
|
||||||
|
} else {
|
||||||
|
mimeTypeList = Kerfuffle::supportedMimeTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(const QString& mime, mimeTypeList) {
|
||||||
|
KMimeType::Ptr mimePtr(KMimeType::mimeType(mime));
|
||||||
|
if (mimePtr) {
|
||||||
|
// Key = "application/zip", Value = "Zip Archive"
|
||||||
|
mimeTypes[mime] = mimePtr->comment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList mimeComments(mimeTypes.values());
|
||||||
|
mimeComments.sort();
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
QString item;
|
||||||
|
|
||||||
|
if (creatingNewArchive) {
|
||||||
|
item = KInputDialog::getItem(i18nc("@title:window", "Invalid Archive Type"),
|
||||||
|
i18nc("@info", "Ark cannot create archives of the type you have chosen.<nl/><nl/>Please choose another archive type below."),
|
||||||
|
mimeComments, 0, false, &ok);
|
||||||
|
} else {
|
||||||
|
item = KInputDialog::getItem(i18nc("@title:window", "Unable to Determine Archive Type"),
|
||||||
|
i18nc("@info", "Ark was unable to determine the archive type of the filename.<nl/><nl/>Please choose the correct archive type below."),
|
||||||
|
mimeComments,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
&ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!ok) || (item.isEmpty())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.reset(Kerfuffle::Archive::create(localFile, mimeTypes.key(item), m_model));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!archive) {
|
||||||
|
KMessageBox::sorry(NULL, i18nc("@info", "Ark was not able to open the archive <filename>%1</filename>. No plugin capable of handling the file was found.", localFile), i18nc("@title:window", "Error Opening Archive"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KJob *job = m_model->setArchive(archive.take());
|
||||||
|
registerJob(job);
|
||||||
|
job->start();
|
||||||
|
m_infoPanel->setIndex(QModelIndex());
|
||||||
|
|
||||||
|
if (arguments().metaData()[QLatin1String( "showExtractDialog" )] == QLatin1String( "true" )) {
|
||||||
|
QTimer::singleShot(0, this, SLOT(slotExtractFiles()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Part::saveFile()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Part::isBusy() const
|
||||||
|
{
|
||||||
|
return m_busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotLoadingStarted()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotLoadingFinished(KJob *job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
if (job->error()) {
|
||||||
|
if (arguments().metaData()[QLatin1String( "createNewArchive" )] != QLatin1String( "true" )) {
|
||||||
|
KMessageBox::sorry(NULL, i18nc("@info", "Loading the archive <filename>%1</filename> failed with the following error: <message>%2</message>", localFilePath(), job->errorText()), i18nc("@title:window", "Error Opening Archive"));
|
||||||
|
|
||||||
|
// The file failed to open, so reset the open archive, info panel and caption.
|
||||||
|
m_model->setArchive(NULL);
|
||||||
|
|
||||||
|
m_infoPanel->setPrettyFileName(QString());
|
||||||
|
m_infoPanel->updateWithDefaults();
|
||||||
|
|
||||||
|
emit setWindowCaption(QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_view->sortByColumn(0, Qt::AscendingOrder);
|
||||||
|
m_view->expandToDepth(0);
|
||||||
|
|
||||||
|
// After loading all files, resize the columns to fit all fields
|
||||||
|
m_view->header()->resizeSections(QHeaderView::ResizeToContents);
|
||||||
|
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setReadyGui()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
m_busy = false;
|
||||||
|
m_view->setEnabled(true);
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setBusyGui()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
m_busy = true;
|
||||||
|
m_view->setEnabled(false);
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setFileNameFromArchive()
|
||||||
|
{
|
||||||
|
const QString prettyName = url().fileName();
|
||||||
|
|
||||||
|
m_infoPanel->setPrettyFileName(prettyName);
|
||||||
|
m_infoPanel->updateWithDefaults();
|
||||||
|
|
||||||
|
emit setWindowCaption(prettyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotPreview()
|
||||||
|
{
|
||||||
|
slotPreview(m_view->selectionModel()->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotPreview(const QModelIndex & index)
|
||||||
|
{
|
||||||
|
if (!isPreviewable(index)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
|
||||||
|
if (!entry.isEmpty()) {
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
options[QLatin1String( "PreservePaths" )] = true;
|
||||||
|
|
||||||
|
ExtractJob *job = m_model->extractFile(entry[ InternalID ], m_previewDir.name(), options);
|
||||||
|
registerJob(job);
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotPreviewExtracted(KJob*)));
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotPreviewExtracted(KJob *job)
|
||||||
|
{
|
||||||
|
// FIXME: the error checking here isn't really working
|
||||||
|
// if there's an error or an overwrite dialog,
|
||||||
|
// the preview dialog will be launched anyway
|
||||||
|
if (!job->error()) {
|
||||||
|
const ArchiveEntry& entry =
|
||||||
|
m_model->entryForIndex(m_view->selectionModel()->currentIndex());
|
||||||
|
|
||||||
|
QString fullName =
|
||||||
|
m_previewDir.name() + QLatin1Char('/') + entry[FileName].toString();
|
||||||
|
|
||||||
|
// Make sure a maliciously crafted archive with parent folders named ".." do
|
||||||
|
// not cause the previewed file path to be located outside the temporary
|
||||||
|
// directory, resulting in a directory traversal issue.
|
||||||
|
fullName.remove(QLatin1String("../"));
|
||||||
|
|
||||||
|
ArkViewer::view(fullName, widget());
|
||||||
|
} else {
|
||||||
|
KMessageBox::error(widget(), job->errorString());
|
||||||
|
}
|
||||||
|
setReadyGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotError(const QString& errorMessage, const QString& details)
|
||||||
|
{
|
||||||
|
if (details.isEmpty()) {
|
||||||
|
KMessageBox::error(widget(), errorMessage);
|
||||||
|
} else {
|
||||||
|
KMessageBox::detailedError(widget(), errorMessage, details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Part::isSingleFolderArchive() const
|
||||||
|
{
|
||||||
|
return m_model->archive()->isSingleFolderArchive();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Part::detectSubfolder() const
|
||||||
|
{
|
||||||
|
if (!m_model) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_model->archive()->subfolderName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotExtractFiles()
|
||||||
|
{
|
||||||
|
if (!m_model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWeakPointer<Kerfuffle::ExtractionDialog> dialog = new Kerfuffle::ExtractionDialog;
|
||||||
|
|
||||||
|
if (m_view->selectionModel()->selectedRows().count() > 0) {
|
||||||
|
dialog.data()->setShowSelectedFiles(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.data()->setSingleFolderArchive(isSingleFolderArchive());
|
||||||
|
dialog.data()->setSubfolder(detectSubfolder());
|
||||||
|
|
||||||
|
dialog.data()->setCurrentUrl(QFileInfo(m_model->archive()->fileName()).path());
|
||||||
|
|
||||||
|
if (dialog.data()->exec()) {
|
||||||
|
//this is done to update the quick extract menu
|
||||||
|
updateActions();
|
||||||
|
|
||||||
|
QVariantList files;
|
||||||
|
|
||||||
|
//if the user has chosen to extract only selected entries, fetch these
|
||||||
|
//from the listview
|
||||||
|
if (!dialog.data()->extractAllFiles()) {
|
||||||
|
files = selectedFilesWithChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Selected " << files;
|
||||||
|
|
||||||
|
Kerfuffle::ExtractionOptions options;
|
||||||
|
|
||||||
|
if (dialog.data()->preservePaths()) {
|
||||||
|
options[QLatin1String("PreservePaths")] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
options[QLatin1String("FollowExtractionDialogSettings")] = true;
|
||||||
|
|
||||||
|
const QString destinationDirectory = dialog.data()->destinationDirectory().pathOrUrl();
|
||||||
|
ExtractJob *job = m_model->extractFiles(files, destinationDirectory, options);
|
||||||
|
registerJob(job);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotExtractionDone(KJob*)));
|
||||||
|
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete dialog.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QVariant> Part::selectedFilesWithChildren()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_model);
|
||||||
|
|
||||||
|
QModelIndexList toIterate = m_view->selectionModel()->selectedRows();
|
||||||
|
|
||||||
|
for (int i = 0; i < toIterate.size(); ++i) {
|
||||||
|
QModelIndex index = toIterate.at(i);
|
||||||
|
|
||||||
|
for (int j = 0; j < m_model->rowCount(index); ++j) {
|
||||||
|
QModelIndex child = m_model->index(j, 0, index);
|
||||||
|
if (!toIterate.contains(child)) {
|
||||||
|
toIterate << child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList ret;
|
||||||
|
foreach(const QModelIndex & index, toIterate) {
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
if (entry.contains(InternalID)) {
|
||||||
|
ret << entry[ InternalID ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QVariant> Part::selectedFiles()
|
||||||
|
{
|
||||||
|
QStringList toSort;
|
||||||
|
|
||||||
|
foreach(const QModelIndex & index, m_view->selectionModel()->selectedRows()) {
|
||||||
|
const ArchiveEntry& entry = m_model->entryForIndex(index);
|
||||||
|
toSort << entry[ InternalID ].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
toSort.sort();
|
||||||
|
QVariantList ret;
|
||||||
|
foreach(const QString &i, toSort) {
|
||||||
|
ret << i;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotExtractionDone(KJob* job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
if (job->error()) {
|
||||||
|
KMessageBox::error(widget(), job->errorString());
|
||||||
|
} else {
|
||||||
|
ExtractJob *extractJob = qobject_cast<ExtractJob*>(job);
|
||||||
|
Q_ASSERT(extractJob);
|
||||||
|
|
||||||
|
const bool followExtractionDialogSettings =
|
||||||
|
extractJob->extractionOptions().value(QLatin1String("FollowExtractionDialogSettings"), false).toBool();
|
||||||
|
if (!followExtractionDialogSettings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ArkSettings::openDestinationFolderAfterExtraction()) {
|
||||||
|
|
||||||
|
KUrl destinationDirectory(extractJob->destinationDirectory());
|
||||||
|
destinationDirectory.cleanPath();
|
||||||
|
|
||||||
|
KRun::runUrl(destinationDirectory, QLatin1String("inode/directory"), widget());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ArkSettings::closeAfterExtraction()) {
|
||||||
|
emit quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::adjustColumns()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
m_view->header()->setResizeMode(0, QHeaderView::ResizeToContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotAddFiles(const QStringList& filesToAdd, const QString& path)
|
||||||
|
{
|
||||||
|
if (filesToAdd.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kDebug() << "Adding " << filesToAdd << " to " << path;
|
||||||
|
kDebug() << "Warning, for now the path argument is not implemented";
|
||||||
|
|
||||||
|
QStringList cleanFilesToAdd(filesToAdd);
|
||||||
|
for (int i = 0; i < cleanFilesToAdd.size(); ++i) {
|
||||||
|
QString& file = cleanFilesToAdd[i];
|
||||||
|
if (QFileInfo(file).isDir()) {
|
||||||
|
if (!file.endsWith(QLatin1Char( '/' ))) {
|
||||||
|
file += QLatin1Char( '/' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionOptions options;
|
||||||
|
|
||||||
|
QString firstPath = cleanFilesToAdd.first();
|
||||||
|
if (firstPath.right(1) == QLatin1String( "/" )) {
|
||||||
|
firstPath.chop(1);
|
||||||
|
}
|
||||||
|
firstPath = QFileInfo(firstPath).dir().absolutePath();
|
||||||
|
|
||||||
|
kDebug() << "Detected relative path to be " << firstPath;
|
||||||
|
options[QLatin1String( "GlobalWorkDir" )] = firstPath;
|
||||||
|
|
||||||
|
AddJob *job = m_model->addFiles(cleanFilesToAdd, options);
|
||||||
|
if (!job) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotAddFilesDone(KJob*)));
|
||||||
|
registerJob(job);
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotAddFiles()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
// #264819: passing widget() as the parent will not work as expected.
|
||||||
|
// KFileDialog will create a KFileWidget, which runs an internal
|
||||||
|
// event loop to stat the given directory. This, in turn, leads to
|
||||||
|
// events being delivered to widget(), which is a QSplitter, which
|
||||||
|
// in turn reimplements childEvent() and will end up calling
|
||||||
|
// QWidget::show() on the KFileDialog (thus showing it in a
|
||||||
|
// non-modal state).
|
||||||
|
// When KFileDialog::exec() is called, the widget is already shown
|
||||||
|
// and nothing happens.
|
||||||
|
const QStringList filesToAdd =
|
||||||
|
KFileDialog::getOpenFileNames(KUrl("kfiledialog:///ArkAddFiles"),
|
||||||
|
QString(), widget()->parentWidget(),
|
||||||
|
i18nc("@title:window", "Add Files"));
|
||||||
|
|
||||||
|
slotAddFiles(filesToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotAddDir()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
const QString dirToAdd = KFileDialog::getExistingDirectory(KUrl("kfiledialog:///ArkAddFiles"), widget(), i18nc("@title:window", "Add Folder"));
|
||||||
|
|
||||||
|
if (!dirToAdd.isEmpty()) {
|
||||||
|
slotAddFiles(QStringList() << dirToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotAddFilesDone(KJob* job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
if (job->error()) {
|
||||||
|
KMessageBox::error(widget(), job->errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotDeleteFilesDone(KJob* job)
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
if (job->error()) {
|
||||||
|
KMessageBox::error(widget(), job->errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotDeleteFiles()
|
||||||
|
{
|
||||||
|
kDebug();
|
||||||
|
|
||||||
|
const int reallyDelete =
|
||||||
|
KMessageBox::questionYesNo(NULL,
|
||||||
|
i18n("Deleting these files is not undoable. Are you sure you want to do this?"),
|
||||||
|
i18nc("@title:window", "Delete files"),
|
||||||
|
KStandardGuiItem::del(),
|
||||||
|
KStandardGuiItem::cancel(),
|
||||||
|
QString(),
|
||||||
|
KMessageBox::Dangerous | KMessageBox::Notify);
|
||||||
|
|
||||||
|
if (reallyDelete == KMessageBox::No) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteJob *job = m_model->deleteFiles(selectedFilesWithChildren());
|
||||||
|
connect(job, SIGNAL(result(KJob*)),
|
||||||
|
this, SLOT(slotDeleteFilesDone(KJob*)));
|
||||||
|
registerJob(job);
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotToggleInfoPanel(bool visible)
|
||||||
|
{
|
||||||
|
QList<int> splitterSizes;
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
splitterSizes = ArkSettings::splitterSizesWithBothWidgets();
|
||||||
|
} else {
|
||||||
|
splitterSizes = m_splitter->sizes();
|
||||||
|
ArkSettings::setSplitterSizesWithBothWidgets(splitterSizes);
|
||||||
|
splitterSizes[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_splitter->setSizes(splitterSizes);
|
||||||
|
saveSplitterSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::saveSplitterSizes()
|
||||||
|
{
|
||||||
|
ArkSettings::setSplitterSizes(m_splitter->sizes());
|
||||||
|
ArkSettings::self()->writeConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::slotSaveAs()
|
||||||
|
{
|
||||||
|
KUrl saveUrl = KFileDialog::getSaveUrl(KUrl(QLatin1String( "kfiledialog:///ArkSaveAs/" ) + url().fileName()), QString(), widget());
|
||||||
|
|
||||||
|
if ((saveUrl.isValid()) && (!saveUrl.isEmpty())) {
|
||||||
|
if (KIO::NetAccess::exists(saveUrl, KIO::NetAccess::DestinationSide, widget())) {
|
||||||
|
int overwrite = KMessageBox::warningContinueCancel(widget(),
|
||||||
|
i18nc("@info", "An archive named <filename>%1</filename> already exists. Are you sure you want to overwrite it?", saveUrl.fileName()),
|
||||||
|
QString(),
|
||||||
|
KStandardGuiItem::overwrite());
|
||||||
|
|
||||||
|
if (overwrite != KMessageBox::Continue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KUrl srcUrl = KUrl::fromPath(localFilePath());
|
||||||
|
|
||||||
|
if (!QFile::exists(localFilePath())) {
|
||||||
|
if (url().isLocalFile()) {
|
||||||
|
KMessageBox::error(widget(),
|
||||||
|
i18nc("@info", "The archive <filename>%1</filename> cannot be copied to the specified location. The archive does not exist anymore.", localFilePath()));
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
srcUrl = url();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KIO::Job *copyJob = KIO::file_copy(srcUrl, saveUrl, -1, KIO::Overwrite);
|
||||||
|
|
||||||
|
if (!KIO::NetAccess::synchronousRun(copyJob, widget())) {
|
||||||
|
KMessageBox::error(widget(),
|
||||||
|
i18nc("@info", "The archive could not be saved as <filename>%1</filename>. Try saving it to another location.", saveUrl.pathOrUrl()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ark
|
126
ark/part/part.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* ark -- archiver for the KDE project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
|
||||||
|
* Copyright (C) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
|
||||||
|
* Copyright (C) 2009 Raphael Kubo da Costa <rakuco@FreeBSD.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 PART_H
|
||||||
|
#define PART_H
|
||||||
|
|
||||||
|
#include "interface.h"
|
||||||
|
|
||||||
|
#include <KParts/Part>
|
||||||
|
#include <KParts/StatusBarExtension>
|
||||||
|
#include <KTempDir>
|
||||||
|
|
||||||
|
#include <QModelIndex>
|
||||||
|
|
||||||
|
class ArchiveModel;
|
||||||
|
class InfoPanel;
|
||||||
|
|
||||||
|
class KAbstractWidgetJobTracker;
|
||||||
|
class KAboutData;
|
||||||
|
class KAction;
|
||||||
|
class KJob;
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QSplitter;
|
||||||
|
class QTreeView;
|
||||||
|
|
||||||
|
namespace Ark
|
||||||
|
{
|
||||||
|
|
||||||
|
class Part: public KParts::ReadWritePart, public Interface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(Interface)
|
||||||
|
public:
|
||||||
|
Part(QWidget *parentWidget, QObject *parent, const QVariantList &);
|
||||||
|
~Part();
|
||||||
|
static KAboutData* createAboutData();
|
||||||
|
|
||||||
|
virtual bool openFile();
|
||||||
|
virtual bool saveFile();
|
||||||
|
|
||||||
|
bool isBusy() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void extractSelectedFilesTo(const QString& localPath);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotLoadingStarted();
|
||||||
|
void slotLoadingFinished(KJob *job);
|
||||||
|
void slotPreview();
|
||||||
|
void slotPreview(const QModelIndex & index);
|
||||||
|
void slotPreviewExtracted(KJob*);
|
||||||
|
void slotError(const QString& errorMessage, const QString& details);
|
||||||
|
void slotExtractFiles();
|
||||||
|
void slotExtractionDone(KJob*);
|
||||||
|
void slotQuickExtractFiles(QAction*);
|
||||||
|
void slotAddFiles();
|
||||||
|
void slotAddFiles(const QStringList& files, const QString& path = QString());
|
||||||
|
void slotAddDir();
|
||||||
|
void slotAddFilesDone(KJob*);
|
||||||
|
void slotDeleteFiles();
|
||||||
|
void slotDeleteFilesDone(KJob*);
|
||||||
|
void saveSplitterSizes();
|
||||||
|
void slotToggleInfoPanel(bool);
|
||||||
|
void slotSaveAs();
|
||||||
|
void updateActions();
|
||||||
|
void selectionChanged();
|
||||||
|
void adjustColumns();
|
||||||
|
void setBusyGui();
|
||||||
|
void setReadyGui();
|
||||||
|
void setFileNameFromArchive();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void busy();
|
||||||
|
void ready();
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupView();
|
||||||
|
void setupActions();
|
||||||
|
bool isSingleFolderArchive() const;
|
||||||
|
QString detectSubfolder() const;
|
||||||
|
bool isPreviewable(const QModelIndex& index) const;
|
||||||
|
QList<QVariant> selectedFiles();
|
||||||
|
QList<QVariant> selectedFilesWithChildren();
|
||||||
|
void registerJob(KJob *job);
|
||||||
|
|
||||||
|
ArchiveModel *m_model;
|
||||||
|
QTreeView *m_view;
|
||||||
|
KAction *m_previewAction;
|
||||||
|
KAction *m_extractFilesAction;
|
||||||
|
KAction *m_addFilesAction;
|
||||||
|
KAction *m_addDirAction;
|
||||||
|
KAction *m_deleteFilesAction;
|
||||||
|
KAction *m_saveAsAction;
|
||||||
|
InfoPanel *m_infoPanel;
|
||||||
|
QSplitter *m_splitter;
|
||||||
|
KTempDir m_previewDir;
|
||||||
|
bool m_busy;
|
||||||
|
|
||||||
|
KAbstractWidgetJobTracker *m_jobTracker;
|
||||||
|
KParts::StatusBarExtension *m_statusBarExtension;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ark
|
||||||
|
|
||||||
|
#endif // PART_H
|
21
ark/plugins/CLI-README
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
In this folder is a general template of what one needs to implement
|
||||||
|
support for a plugin using the cli interface in ark.
|
||||||
|
|
||||||
|
Here are the steps.
|
||||||
|
|
||||||
|
1. First, create a copy of the cliplugin folder
|
||||||
|
2. Change plugins/CMakeLists.txt to include the new subfolder
|
||||||
|
3. Rename the kerfuffle_cli.desktop to a unique name, for example
|
||||||
|
kerfuffle_rar.desktop.
|
||||||
|
4. Fill in the parts in the desktop marked with TODO
|
||||||
|
5. Update the plugins/yourplugin/CMakeLists.txt file, replacing all
|
||||||
|
instances of kerfuffle_cli with kerfuffle_yourplugin (where yourplugin
|
||||||
|
must be a unique plugin name)
|
||||||
|
6. Implement/modify cliplugin.cpp to fit your archive type.
|
||||||
|
Refer to kerfuffle/cliinterface.h for explanations on the values that
|
||||||
|
needs to be implemented. The class name does not need to be changed
|
||||||
|
|
||||||
|
Then finally, email the plugin to the ark maintainer for a code review before
|
||||||
|
it is committed to trunk :D
|
||||||
|
|
||||||
|
Have fun
|