commit b2b0b6ccfaf6326c522d4acf774ec7f84a049845 Author: Andrew Lee (李健秋) Date: Thu Aug 13 06:44:06 2015 +0800 Adding upstream version 0.9.0. Signed-off-by: Andrew Lee (李健秋) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e0d423 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +.kdev4 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..c20cbb5 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,9 @@ +Upstream Authors: + LXQt team: http://lxqt.org + Hong Jen Yee (PCMan) + +Copyright: + Copyright (c) 2013-2014 LXQt team + +License: GPL-2 +The full text of the licenses can be found in the 'COPYING' file. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..170b9ce --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,98 @@ +cmake_minimum_required(VERSION 2.8.11) +project(pcmanfm-qt) + +set(PCMANFM_QT_VERSION "0.9.0") +set(LIBFM_QT_VERSION "0.9.0") +# We use the libtool versioning scheme for the internal so name, "current:revision:age" +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info +# https://www.sourceware.org/autobook/autobook/autobook_91.html +# http://pusling.com/blog/?p=352 +# Actually, libtool uses different ways on different operating systems. So there is no +# universal way to translate a libtool version-info to a cmake version. +# We use "(current-age).age.revision" as the cmake version. +# current: 2, revision: 0, age: 0 => version: 2.0.0 +set(LIBFM_QT_LIB_VERSION "2.0.0") +set(LIBFM_QT_LIB_SOVERSION "2") + +# Set default installation paths +set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "Installation path for libraries") +set(INCLUDE_INSTALL_DIR include CACHE PATH "Installation path for includes") + +find_package(Qt5Widgets 5.2 REQUIRED) +find_package(Qt5DBus 5.2 REQUIRED) +find_package(Qt5LinguistTools 5.2 REQUIRED) +find_package(Qt5X11Extras 5.2 REQUIRED) + +find_package(PkgConfig) +pkg_check_modules(SYSTEM_LIBS REQUIRED + glib-2.0 + gio-2.0 + gio-unix-2.0 + xcb +) + +pkg_check_modules(LIBFM REQUIRED libfm>=1.2.0) +pkg_check_modules(LIBMENUCACHE REQUIRED libmenu-cache>=0.4.0) + +include(GNUInstallDirs) + +add_definitions(-DQT_NO_KEYWORDS) + +if (CMAKE_COMPILER_IS_GNUCXX) + # set visibility to hidden to hide symbols, unless they're exported manually in the code + set(CMAKE_CXX_FLAGS "-fvisibility=hidden -fvisibility-inlines-hidden -fno-exceptions ${CMAKE_CXX_FLAGS}") +endif() + +set(CMAKE_AUTOMOC TRUE) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_subdirectory(libfm-qt) +add_subdirectory(pcmanfm) + +# update translations +add_custom_target(update_translations ALL DEPENDS + libfm_translations + pcmanfm_translations +) + +# manpage for pcmanfm-qt +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/pcmanfm-qt.1.in" + "${CMAKE_CURRENT_BINARY_DIR}/pcmanfm-qt.1" + @ONLY +) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/pcmanfm-qt.1" + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" +) + +# add Doxygen support to generate API docs +# References: +# http://majewsky.wordpress.com/2010/08/14/tip-of-the-day-cmake-and-doxygen/ +# http://www.bluequartz.net/projects/EIM_Segmentation/SoftwareDocumentation/html/usewithcmakeproject.html +option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" OFF) +if(BUILD_DOCUMENTATION) + find_package(Doxygen REQUIRED) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" @ONLY) + add_custom_target(doc ALL + ${DOXYGEN_EXECUTABLE} "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Generating API documentation with Doxygen" VERBATIM + ) + install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/docs" DESTINATION "${CMAKE_INSTALL_DOCDIR}") +endif() + +# building tarball with CPack ------------------------------------------------- +# To create a source distribution, type: +# make package_source +include(InstallRequiredSystemLibraries) +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") +set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README") +set(CPACK_PACKAGE_VENDOR "") +set(CPACK_PACKAGE_VERSION_MAJOR "0") +set(CPACK_PACKAGE_VERSION_MINOR "8") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_GENERATOR TBZ2) +set(CPACK_SOURCE_GENERATOR TBZ2) +set(CPACK_SOURCE_IGNORE_FILES /build/;.gitignore;.*~;.git;.kdev4;temp) +include(CPack) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d8cf7d4 --- /dev/null +++ b/COPYING @@ -0,0 +1,280 @@ + 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 Lesser 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 diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 0000000..8378572 --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,1890 @@ +# Doxyfile 1.8.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed +# in front of the TAG it is preceding . +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG + = value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "PCManFM-Qt" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, +# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, +# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name = value". +# For example adding "sideeffect = \par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name = value". For example adding +# "class = itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext = language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc = Fortran f = C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields or simple typedef fields will be shown +# inline in the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO (the default), structs, classes, and unions are shown on a separate +# page (for HTML and Man pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can +# be an expensive process and often the same symbol appear multiple times in +# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too +# small doxygen will become slower. If the cache is too large, memory is wasted. +# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid +# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 +# symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "@PROJECT_SOURCE_DIR@/libfm-qt" "@PROJECT_SOURCE_DIR@/pcmanfm" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */*_p.h + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = FakeTr _* LibFmQtData + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be ignored. +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern = filter (like *.cpp = my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext = (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript +# pieces of code that will be used on startup of the MathJax code. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search +# engine library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1 = loc1 id2 = loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4 will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images +# or other source files which should be copied to the LaTeX output directory. +# Note that the files will be copied as-is; there are no commands or markers +# available. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files +# that can be used to generate PDF. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. If left blank docbook will be used as the default path. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name = definition (no spaces). If the definition and the = are +# omitted = 1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the : = operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1 = loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed +# in the related pages index. If set to NO, only the current project's +# pages will be listed. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/README b/README new file mode 100644 index 0000000..b900c0c --- /dev/null +++ b/README @@ -0,0 +1,11 @@ +PCManFM-Qt is the Qt port of the LXDE file manager PCManFM. +Libfm-Qt is a companion library providing components to build desktop file managers. + +Issue tracker: + https://github.com/lxde/pcmanfm-qt/issues + +LXQt website: + http://lxqt.org + +LXDE website: + http://lxde.org diff --git a/libfm-qt/CMakeLists.txt b/libfm-qt/CMakeLists.txt new file mode 100644 index 0000000..163a2ef --- /dev/null +++ b/libfm-qt/CMakeLists.txt @@ -0,0 +1,148 @@ +project(fm-qt) + +set(LIBRARY_NAME "fm-qt5") +set(QTX_INCLUDE_DIRS "") +set(QTX_LIBRARIES Qt5::Widgets Qt5::X11Extras) + +include_directories( + ${QTX_INCLUDE_DIRS} + ${LIBFM_INCLUDE_DIRS} + "${LIBFM_INCLUDEDIR}/libfm" # to workaround incorrect #include in fm-actions. + ${LIBMENUCACHE_INCLUDE_DIRS} + ${SYSTEM_LIBS_INCLUDE_DIRS} + "${CMAKE_CURRENT_BINARY_DIR}" +) + +link_directories( + ${LIBFM_LIBRARY_DIRS} + ${LIBMENUCACHE_LIBRARY_DIRS} + ${SYSTEM_LIBS_LIBRARY_DIRS} +) + +set(libfm_SRCS + libfmqt.cpp + bookmarkaction.cpp + sidepane.cpp + icontheme.cpp + filelauncher.cpp + foldermodel.cpp + foldermodelitem.cpp + cachedfoldermodel.cpp + proxyfoldermodel.cpp + folderview.cpp + folderitemdelegate.cpp + filemenu.cpp + foldermenu.cpp + filepropsdialog.cpp + applaunchcontext.cpp + placesview.cpp + placesmodel.cpp + placesmodelitem.cpp + dirtreeview.cpp + dirtreemodel.cpp + dirtreemodelitem.cpp + dnddest.cpp + mountoperation.cpp + mountoperationpassworddialog.cpp + mountoperationquestiondialog.cpp + fileoperation.cpp + fileoperationdialog.cpp + renamedialog.cpp + pathedit.cpp + colorbutton.cpp + fontbutton.cpp + browsehistory.cpp + utilities.cpp + dndactionmenu.cpp + editbookmarksdialog.cpp + thumbnailloader.cpp + path.cpp + execfiledialog.cpp + appchoosercombobox.cpp + appmenuview.cpp + appchooserdialog.cpp +) + +set(libfm_UIS + file-props.ui + file-operation-dialog.ui + rename-dialog.ui + mount-operation-password.ui + edit-bookmarks.ui + exec-file.ui + app-chooser-dialog.ui +) + +qt5_wrap_ui(libfm_UIS_H ${libfm_UIS}) + +add_library(${LIBRARY_NAME} SHARED + ${libfm_SRCS} + ${libfm_UIS_H} +) + +set_property( + TARGET ${LIBRARY_NAME} APPEND + PROPERTY COMPILE_DEFINITIONS + LIBFM_QT_COMPILATION=1 + LIBFM_DATA_DIR="${CMAKE_INSTALL_FULL_DATADIR}/libfm-qt" +) + +# only turn on custom actions support if it is enabled in libfm. +if(EXISTS ${LIBFM_INCLUDEDIR}/libfm/fm-actions.h) + set_property(TARGET ${LIBRARY_NAME} APPEND PROPERTY COMPILE_DEFINITIONS CUSTOM_ACTIONS) +endif() + +target_link_libraries(${LIBRARY_NAME} + ${QTX_LIBRARIES} + ${LIBFM_LIBRARIES} + ${LIBMENUCACHE_LIBRARIES} + ${SYSTEM_LIBS_LIBRARIES} +) + +# set libtool soname +set_target_properties(${LIBRARY_NAME} PROPERTIES + VERSION ${LIBFM_QT_LIB_VERSION} + SOVERSION ${LIBFM_QT_LIB_SOVERSION} +) + +# install include header files (FIXME: can we make this cleaner? should dir name be versioned?) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" + PATTERN "*_p.h" EXCLUDE # exclude private headers +) + +# FIXME: add libtool version to the lib (soname) later. +# FIXME: only export public symbols + +install(TARGETS ${LIBRARY_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER +) + +# install a pkgconfig file for libfm-qt +set(REQUIRED_QT "Qt5Core >= 5.1 Qt5DBus >= 5.1") +configure_file(libfm-qt.pc.in lib${LIBRARY_NAME}.pc @ONLY) +# FreeBSD loves to install files to different locations +# http://www.freebsd.org/doc/handbook/dirstructure.html +if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${LIBRARY_NAME}.pc" DESTINATION libdata/pkgconfig) +else() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib${LIBRARY_NAME}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +endif() + +# add translation for pcmanfm-qt +# See http://www.cmake.org/Wiki/CMake:How_To_Build_Qt4_Software +option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts files") +file(GLOB TS_FILES translations/*.ts) +if(UPDATE_TRANSLATIONS) + qt5_create_translation(QM_FILES ${libfm_SRCS} ${libfm_UIS} ${TS_FILES}) +else() + qt5_add_translation(QM_FILES ${TS_FILES}) +endif() + +add_custom_target(libfm_translations DEPENDS ${QM_FILES}) +install(FILES ${QM_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/libfm-qt/translations") + +# prevent the generated files from being deleted during make cleaner +set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM true) diff --git a/libfm-qt/app-chooser-dialog.ui b/libfm-qt/app-chooser-dialog.ui new file mode 100644 index 0000000..ef1ebee --- /dev/null +++ b/libfm-qt/app-chooser-dialog.ui @@ -0,0 +1,183 @@ + + + AppChooserDialog + + + + 0 + 0 + 432 + 387 + + + + Choose an Application + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + + + + 0 + 1 + + + + 0 + + + + Installed Applications + + + + + + + + + + Custom Command + + + + + + Command line to execute: + + + + + + + + + + Application name: + + + + + + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + Qt::RichText + + + + + + + false + + + Keep terminal window open after command execution + + + + + + + Execute in terminal emulator + + + + + + + + + + + Set selected application as default action of this file type + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + Fm::AppMenuView + QTreeView +
appmenuview.h
+
+
+ + + + buttonBox + accepted() + AppChooserDialog + accept() + + + 227 + 359 + + + 157 + 274 + + + + + buttonBox + rejected() + AppChooserDialog + reject() + + + 295 + 365 + + + 286 + 274 + + + + + useTerminal + toggled(bool) + keepTermOpen + setEnabled(bool) + + + 72 + 260 + + + 79 + 282 + + + + +
diff --git a/libfm-qt/appchoosercombobox.cpp b/libfm-qt/appchoosercombobox.cpp new file mode 100644 index 0000000..aaf476f --- /dev/null +++ b/libfm-qt/appchoosercombobox.cpp @@ -0,0 +1,143 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "appchoosercombobox.h" +#include "icontheme.h" +#include "appchooserdialog.h" +#include "utilities.h" + +namespace Fm { + +AppChooserComboBox::AppChooserComboBox(QWidget* parent): + QComboBox(parent), + defaultApp_(NULL), + appInfos_(NULL), + defaultAppIndex_(0), + prevIndex_(0), + mimeType_(NULL) { + + // the new Qt5 signal/slot syntax cannot handle overloaded methods by default + // hence a type-casting is needed here. really ugly! + // reference: http://qt-project.org/forums/viewthread/21513 + connect((QComboBox*)this, static_cast(&QComboBox::currentIndexChanged), this, &AppChooserComboBox::onCurrentIndexChanged); +} + +AppChooserComboBox::~AppChooserComboBox() { + if(mimeType_) + fm_mime_type_unref(mimeType_); + if(defaultApp_) + g_object_unref(defaultApp_); + // delete GAppInfo objects stored for Combobox + if(appInfos_) { + g_list_foreach(appInfos_, (GFunc)g_object_unref, NULL); + g_list_free(appInfos_); + } +} + +void AppChooserComboBox::setMimeType(FmMimeType* mimeType) { + clear(); + if(mimeType_) + fm_mime_type_unref(mimeType_); + + mimeType_ = fm_mime_type_ref(mimeType); + if(mimeType_) { + const char* typeName = fm_mime_type_get_type(mimeType_); + defaultApp_ = g_app_info_get_default_for_type(typeName, FALSE); + appInfos_ = g_app_info_get_all_for_type(typeName); + int i = 0; + for(GList* l = appInfos_; l; l = l->next, ++i) { + GAppInfo* app = G_APP_INFO(l->data); + GIcon* gicon = g_app_info_get_icon(app); + QString name = QString::fromUtf8(g_app_info_get_name(app)); + // QVariant data = qVariantFromValue(app); + // addItem(IconTheme::icon(gicon), name, data); + addItem(IconTheme::icon(gicon), name); + if(app == defaultApp_) + defaultAppIndex_ = i; + } + setCurrentIndex(defaultAppIndex_); + } + // add "Other applications" item + insertSeparator(count()); + addItem(tr("Customize")); +} + +// returns the currently selected app. +GAppInfo* AppChooserComboBox::selectedApp() { + return G_APP_INFO(g_list_nth_data(appInfos_, currentIndex())); +} + +bool AppChooserComboBox::isChanged() { + return (defaultAppIndex_ != currentIndex()); +} + +void AppChooserComboBox::onCurrentIndexChanged(int index) { + if(index == -1 || index == prevIndex_) + return; + + // the last item is "Customize" + if(index == (count() - 1)) { + /* TODO: let the user choose an app or add custom actions here. */ + QWidget* toplevel = topLevelWidget(); + AppChooserDialog dlg(mimeType_, toplevel); + dlg.setWindowModality(Qt::WindowModal); + dlg.setCanSetDefault(false); + if(dlg.exec() == QDialog::Accepted) { + GAppInfo* app = dlg.selectedApp(); + if(app) { + /* see if it's already in the list to prevent duplication */ + GList* found = NULL; + for(found = appInfos_; found; found = found->next) { + if(g_app_info_equal(app, G_APP_INFO(found->data))) + break; + } + /* if it's already in the list, select it */ + if(found) { + setCurrentIndex(g_list_position(appInfos_, found)); + g_object_unref(app); + } + else { /* if it's not found, add it to the list */ + appInfos_ = g_list_prepend(appInfos_, app); + GIcon* gicon = g_app_info_get_icon(app); + QString name = QString::fromUtf8(g_app_info_get_name(app)); + insertItem(0, IconTheme::icon(gicon), name); + setCurrentIndex(0); + } + return; + } + } + // restore to previously selected item + setCurrentIndex(prevIndex_); + } + else { + prevIndex_ = index; + } +} + + +#if 0 +/* get a list of custom apps added with app-chooser. +* the returned GList is owned by the combo box and shouldn't be freed. */ +const GList* AppChooserComboBox::customApps() { + +} +#endif + +} // namespace Fm diff --git a/libfm-qt/appchoosercombobox.h b/libfm-qt/appchoosercombobox.h new file mode 100644 index 0000000..d231059 --- /dev/null +++ b/libfm-qt/appchoosercombobox.h @@ -0,0 +1,60 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_APPCHOOSERCOMBOBOX_H +#define FM_APPCHOOSERCOMBOBOX_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class LIBFM_QT_API AppChooserComboBox : public QComboBox { + Q_OBJECT +public: + ~AppChooserComboBox(); + AppChooserComboBox(QWidget* parent); + + void setMimeType(FmMimeType* mimeType); + + FmMimeType* mimeType() { + return mimeType_; + } + + GAppInfo* selectedApp(); + // const GList* customApps(); + + bool isChanged(); + +private Q_SLOTS: + void onCurrentIndexChanged(int index); + +private: + FmMimeType* mimeType_; + GList* appInfos_; // applications used to open the file type + GAppInfo* defaultApp_; // default application used to open the file type + int defaultAppIndex_; + int prevIndex_; +}; + +} + +#endif // FM_APPCHOOSERCOMBOBOX_H diff --git a/libfm-qt/appchooserdialog.cpp b/libfm-qt/appchooserdialog.cpp new file mode 100644 index 0000000..0a2b19d --- /dev/null +++ b/libfm-qt/appchooserdialog.cpp @@ -0,0 +1,286 @@ +/* + * Copyright 2010-2014 Hong Jen Yee (PCMan) + * Copyright 2012-2013 Andriy Grytsenko (LStranger) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "appchooserdialog.h" +#include "ui_app-chooser-dialog.h" +#include +#include + +namespace Fm { + +AppChooserDialog::AppChooserDialog(FmMimeType* mimeType, QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f), + mimeType_(NULL), + selectedApp_(NULL), + canSetDefault_(true), + ui(new Ui::AppChooserDialog()) { + ui->setupUi(this); + + connect(ui->appMenuView, &AppMenuView::selectionChanged, this, &AppChooserDialog::onSelectionChanged); + connect(ui->tabWidget, &QTabWidget::currentChanged, this, &AppChooserDialog::onTabChanged); + + if(!ui->appMenuView->isAppSelected()) + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); // disable OK button + + if(mimeType) + setMimeType(mimeType); +} + +AppChooserDialog::~AppChooserDialog() { + delete ui; + if(mimeType_) + fm_mime_type_unref(mimeType_); + if(selectedApp_) + g_object_unref(selectedApp_); +} + +bool AppChooserDialog::isSetDefault() { + return ui->setDefault->isChecked(); +} + + +static void on_temp_appinfo_destroy(gpointer data, GObject* objptr) { + char* filename = (char*)data; + if(g_unlink(filename) < 0) + g_critical("failed to remove %s", filename); + /* else + qDebug("temp file %s removed", filename); */ + g_free(filename); +} + +static GAppInfo* app_info_create_from_commandline(const char* commandline, + const char* application_name, + const char* bin_name, + const char* mime_type, + gboolean terminal, gboolean keep) { + GAppInfo* app = NULL; + char* dirname = g_build_filename(g_get_user_data_dir(), "applications", NULL); + const char* app_basename = strrchr(bin_name, '/'); + + if(app_basename) + app_basename++; + else + app_basename = bin_name; + if(g_mkdir_with_parents(dirname, 0700) == 0) { + char* filename = g_strdup_printf("%s/userapp-%s-XXXXXX.desktop", dirname, app_basename); + int fd = g_mkstemp(filename); + if(fd != -1) { + GString* content = g_string_sized_new(256); + g_string_printf(content, + "[" G_KEY_FILE_DESKTOP_GROUP "]\n" + G_KEY_FILE_DESKTOP_KEY_TYPE "=" G_KEY_FILE_DESKTOP_TYPE_APPLICATION "\n" + G_KEY_FILE_DESKTOP_KEY_NAME "=%s\n" + G_KEY_FILE_DESKTOP_KEY_EXEC "=%s\n" + G_KEY_FILE_DESKTOP_KEY_CATEGORIES "=Other;\n" + G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY "=true\n", + application_name, + commandline + ); + if(mime_type) + g_string_append_printf(content, + G_KEY_FILE_DESKTOP_KEY_MIME_TYPE "=%s\n", + mime_type); + g_string_append_printf(content, + G_KEY_FILE_DESKTOP_KEY_TERMINAL "=%s\n", + terminal ? "true" : "false"); + if(terminal) + g_string_append_printf(content, "X-KeepTerminal=%s\n", + keep ? "true" : "false"); + close(fd); /* g_file_set_contents() may fail creating duplicate */ + if(g_file_set_contents(filename, content->str, content->len, NULL)) { + char* fbname = g_path_get_basename(filename); + app = G_APP_INFO(g_desktop_app_info_new(fbname)); + g_free(fbname); + /* if there is mime_type set then created application will be + saved for the mime type (see fm_choose_app_for_mime_type() + below) but if not then we should remove this temp. file */ + if(!mime_type || !application_name[0]) + /* save the name so this file will be removed later */ + g_object_weak_ref(G_OBJECT(app), on_temp_appinfo_destroy, + g_strdup(filename)); + } + else + g_unlink(filename); + g_string_free(content, TRUE); + } + g_free(filename); + } + g_free(dirname); + return app; +} + +inline static char* get_binary(const char* cmdline, gboolean* arg_found) { + /* see if command line contains %f, %F, %u, or %U. */ + const char* p = strstr(cmdline, " %"); + if(p) { + if(!strchr("fFuU", *(p + 2))) + p = NULL; + } + if(arg_found) + *arg_found = (p != NULL); + if(p) + return g_strndup(cmdline, p - cmdline); + else + return g_strdup(cmdline); +} + +GAppInfo* AppChooserDialog::customCommandToApp() { + GAppInfo* app = NULL; + QByteArray cmdline = ui->cmdLine->text().toLocal8Bit(); + QByteArray app_name = ui->appName->text().toUtf8(); + if(!cmdline.isEmpty()) { + gboolean arg_found = FALSE; + char* bin1 = get_binary(cmdline.constData(), &arg_found); + qDebug("bin1 = %s", bin1); + /* see if command line contains %f, %F, %u, or %U. */ + if(!arg_found) { /* append %f if no %f, %F, %u, or %U was found. */ + cmdline += " %f"; + } + + /* FIXME: is there any better way to do this? */ + /* We need to ensure that no duplicated items are added */ + if(mimeType_) { + MenuCache* menu_cache; + /* see if the command is already in the list of known apps for this mime-type */ + GList* apps = g_app_info_get_all_for_type(fm_mime_type_get_type(mimeType_)); + GList* l; + for(l = apps; l; l = l->next) { + GAppInfo* app2 = G_APP_INFO(l->data); + const char* cmd = g_app_info_get_commandline(app2); + char* bin2 = get_binary(cmd, NULL); + if(g_strcmp0(bin1, bin2) == 0) { + app = G_APP_INFO(g_object_ref(app2)); + qDebug("found in app list"); + g_free(bin2); + break; + } + g_free(bin2); + } + g_list_foreach(apps, (GFunc)g_object_unref, NULL); + g_list_free(apps); + if(app) + goto _out; + + /* see if this command can be found in menu cache */ + menu_cache = menu_cache_lookup("applications.menu"); + if(menu_cache) { + MenuCacheDir* root_dir = menu_cache_dup_root_dir(menu_cache); + if(root_dir) { + GSList* all_apps = menu_cache_list_all_apps(menu_cache); + GSList* l; + for(l = all_apps; l; l = l->next) { + MenuCacheApp* ma = MENU_CACHE_APP(l->data); + const char* exec = menu_cache_app_get_exec(ma); + char* bin2; + if(exec == NULL) { + g_warning("application %s has no Exec statement", menu_cache_item_get_id(MENU_CACHE_ITEM(ma))); + continue; + } + bin2 = get_binary(exec, NULL); + if(g_strcmp0(bin1, bin2) == 0) { + app = G_APP_INFO(g_desktop_app_info_new(menu_cache_item_get_id(MENU_CACHE_ITEM(ma)))); + qDebug("found in menu cache"); + menu_cache_item_unref(MENU_CACHE_ITEM(ma)); + g_free(bin2); + break; + } + menu_cache_item_unref(MENU_CACHE_ITEM(ma)); + g_free(bin2); + } + g_slist_free(all_apps); + menu_cache_item_unref(MENU_CACHE_ITEM(root_dir)); + } + menu_cache_unref(menu_cache); + } + if(app) + goto _out; + } + + /* FIXME: g_app_info_create_from_commandline force the use of %f or %u, so this is not we need */ + app = app_info_create_from_commandline(cmdline.constData(), app_name.constData(), bin1, + mimeType_ ? fm_mime_type_get_type(mimeType_) : NULL, + ui->useTerminal->isChecked(), ui->keepTermOpen->isChecked()); + _out: + g_free(bin1); + } + return app; +} + +void AppChooserDialog::accept() { + QDialog::accept(); + + if(ui->tabWidget->currentIndex() == 0) { + selectedApp_ = ui->appMenuView->selectedApp(); + } + else { // custom command line + selectedApp_ = customCommandToApp(); + } + + if(selectedApp_) { + if(mimeType_ && fm_mime_type_get_type(mimeType_) && g_app_info_get_name(selectedApp_)[0]) { + /* add this app to the mime-type */ +#if GLIB_CHECK_VERSION(2, 27, 6) + g_app_info_set_as_last_used_for_type(selectedApp_, fm_mime_type_get_type(mimeType_), NULL); +#else + g_app_info_add_supports_type(selectedApp_, fm_mime_type_get_type(mimeType_), NULL); +#endif + /* if need to set default */ + if(ui->setDefault->isChecked()) + g_app_info_set_as_default_for_type(selectedApp_, fm_mime_type_get_type(mimeType_), NULL); + } + } +} + +void AppChooserDialog::onSelectionChanged() { + bool isAppSelected = ui->appMenuView->isAppSelected(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isAppSelected); +} + +void AppChooserDialog::setMimeType(FmMimeType* mimeType) { + if(mimeType_) + fm_mime_type_unref(mimeType_); + + mimeType_ = mimeType ? fm_mime_type_ref(mimeType) : NULL; + if(mimeType_) { + QString text = tr("Select an application to open \"%1\" files") + .arg(QString::fromUtf8(fm_mime_type_get_desc(mimeType_))); + ui->fileTypeHeader->setText(text); + } + else { + ui->fileTypeHeader->hide(); + ui->setDefault->hide(); + } +} + +void AppChooserDialog::setCanSetDefault(bool value) { + canSetDefault_ = value; + ui->setDefault->setVisible(value); +} + +void AppChooserDialog::onTabChanged(int index) { + if(index == 0) { // app menu view + onSelectionChanged(); + } + else if(index == 1) { // custom command + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } +} + +} // namespace Fm diff --git a/libfm-qt/appchooserdialog.h b/libfm-qt/appchooserdialog.h new file mode 100644 index 0000000..64a5464 --- /dev/null +++ b/libfm-qt/appchooserdialog.h @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2014 Hong Jen Yee (PCMan) + * Copyright 2012-2013 Andriy Grytsenko (LStranger) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_APPCHOOSERDIALOG_H +#define FM_APPCHOOSERDIALOG_H + +#include +#include "libfmqtglobals.h" +#include + +namespace Ui { + class AppChooserDialog; +} + +namespace Fm { + +class LIBFM_QT_API AppChooserDialog : public QDialog { + Q_OBJECT +public: + explicit AppChooserDialog(FmMimeType* mimeType, QWidget* parent = NULL, Qt::WindowFlags f = 0); + ~AppChooserDialog(); + + virtual void accept(); + + void setMimeType(FmMimeType* mimeType); + FmMimeType* mimeType() { + return mimeType_; + } + + void setCanSetDefault(bool value); + bool canSetDefault() { + return canSetDefault_; + } + + GAppInfo* selectedApp() { + return G_APP_INFO(g_object_ref(selectedApp_)); + } + + bool isSetDefault(); + +private: + GAppInfo* customCommandToApp(); + +private Q_SLOTS: + void onSelectionChanged(); + void onTabChanged(int index); + +private: + Ui::AppChooserDialog* ui; + FmMimeType* mimeType_; + bool canSetDefault_; + GAppInfo* selectedApp_; +}; + +} + +#endif // FM_APPCHOOSERDIALOG_H diff --git a/libfm-qt/applaunchcontext.cpp b/libfm-qt/applaunchcontext.cpp new file mode 100644 index 0000000..4132753 --- /dev/null +++ b/libfm-qt/applaunchcontext.cpp @@ -0,0 +1,61 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "applaunchcontext.h" +#include +#include + +typedef struct _FmAppLaunchContext { + GAppLaunchContext parent; +}FmAppLaunchContext; + +G_DEFINE_TYPE(FmAppLaunchContext, fm_app_launch_context, G_TYPE_APP_LAUNCH_CONTEXT) + +static char* fm_app_launch_context_get_display(GAppLaunchContext *context, GAppInfo *info, GList *files) { + Display* dpy = QX11Info::display(); + if(dpy) { + char* xstr = DisplayString(dpy); + return g_strdup(xstr); + } + return NULL; +} + +static char* fm_app_launch_context_get_startup_notify_id(GAppLaunchContext *context, GAppInfo *info, GList *files) { + return NULL; +} + +static void fm_app_launch_context_class_init(FmAppLaunchContextClass* klass) { + GAppLaunchContextClass* app_launch_class = G_APP_LAUNCH_CONTEXT_CLASS(klass); + app_launch_class->get_display = fm_app_launch_context_get_display; + app_launch_class->get_startup_notify_id = fm_app_launch_context_get_startup_notify_id; +} + +static void fm_app_launch_context_init(FmAppLaunchContext* context) { +} + +FmAppLaunchContext* fm_app_launch_context_new_for_widget(QWidget* widget) { + FmAppLaunchContext* context = (FmAppLaunchContext*)g_object_new(FM_TYPE_APP_LAUNCH_CONTEXT, NULL); + return context; +} + +FmAppLaunchContext* fm_app_launch_context_new() { + FmAppLaunchContext* context = (FmAppLaunchContext*)g_object_new(FM_TYPE_APP_LAUNCH_CONTEXT, NULL); + return context; +} diff --git a/libfm-qt/applaunchcontext.h b/libfm-qt/applaunchcontext.h new file mode 100644 index 0000000..828768a --- /dev/null +++ b/libfm-qt/applaunchcontext.h @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_APP_LAUNCHCONTEXT_H +#define FM_APP_LAUNCHCONTEXT_H + +#include "libfmqtglobals.h" +#include +#include + +#define FM_TYPE_APP_LAUNCH_CONTEXT (fm_app_launch_context_get_type()) +#define FM_APP_LAUNCH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ + FM_TYPE_APP_LAUNCH_CONTEXT, FmAppLaunchContext)) +#define FM_APP_LAUNCH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ + FM_TYPE_APP_LAUNCH_CONTEXT, FmAppLaunchContextClass)) +#define FM_IS_APP_LAUNCH_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ + FM_TYPE_APP_LAUNCH_CONTEXT)) +#define FM_IS_APP_LAUNCH_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ + FM_TYPE_APP_LAUNCH_CONTEXT)) +#define FM_APP_LAUNCH_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\ + FM_TYPE_APP_LAUNCH_CONTEXT, FmAppLaunchContextClass)) + +typedef struct _FmAppLaunchContext FmAppLaunchContext; + +typedef struct _FmAppLaunchContextClass { + GAppLaunchContextClass parent; +}FmAppLaunchContextClass; + +FmAppLaunchContext* fm_app_launch_context_new(); +FmAppLaunchContext* fm_app_launch_context_new_for_widget(QWidget* widget); +GType fm_app_launch_context_get_type(); + +#endif // FM_APPLAUNCHCONTEXT_H diff --git a/libfm-qt/appmenuview.cpp b/libfm-qt/appmenuview.cpp new file mode 100644 index 0000000..53102db --- /dev/null +++ b/libfm-qt/appmenuview.cpp @@ -0,0 +1,159 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "appmenuview.h" +#include +#include "icontheme.h" +#include "appmenuview_p.h" +#include + +namespace Fm { + +AppMenuView::AppMenuView(QWidget* parent): + model_(new QStandardItemModel()), + menu_cache(NULL), + menu_cache_reload_notify(NULL), + QTreeView(parent) { + + setHeaderHidden(true); + setSelectionMode(SingleSelection); + + // initialize model + // TODO: share one model among all app menu view widgets + // ensure that we're using lxmenu-data (FIXME: should we do this?) + QByteArray oldenv = qgetenv("XDG_MENU_PREFIX"); + qputenv("XDG_MENU_PREFIX", "lxde-"); + menu_cache = menu_cache_lookup("applications.menu"); + // if(!oldenv.isEmpty()) + qputenv("XDG_MENU_PREFIX", oldenv); // restore the original value if needed + + if(menu_cache) { + MenuCacheDir* dir = menu_cache_dup_root_dir(menu_cache); + menu_cache_reload_notify = menu_cache_add_reload_notify(menu_cache, _onMenuCacheReload, this); + if(dir) { /* content of menu is already loaded */ + addMenuItems(NULL, dir); + menu_cache_item_unref(MENU_CACHE_ITEM(dir)); + } + } + setModel(model_); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &AppMenuView::selectionChanged); + selectionModel()->select(model_->index(0, 0), QItemSelectionModel::SelectCurrent); +} + +AppMenuView::~AppMenuView() { + delete model_; + if(menu_cache) { + if(menu_cache_reload_notify) + menu_cache_remove_reload_notify(menu_cache, menu_cache_reload_notify); + menu_cache_unref(menu_cache); + } +} + +void AppMenuView::addMenuItems(QStandardItem* parentItem, MenuCacheDir* dir) { + GSList* l; + GSList* list; + /* Iterate over all menu items in this directory. */ + for(l = list = menu_cache_dir_list_children(dir); l != NULL; l = l->next) { + /* Get the menu item. */ + MenuCacheItem* menuItem = MENU_CACHE_ITEM(l->data); + switch(menu_cache_item_get_type(menuItem)) { + case MENU_CACHE_TYPE_NONE: + case MENU_CACHE_TYPE_SEP: + break; + case MENU_CACHE_TYPE_APP: + case MENU_CACHE_TYPE_DIR: { + AppMenuViewItem* newItem = new AppMenuViewItem(menuItem); + if(parentItem) + parentItem->insertRow(parentItem->rowCount(), newItem); + else + model_->insertRow(model_->rowCount(), newItem); + + if(menu_cache_item_get_type(menuItem) == MENU_CACHE_TYPE_DIR) + addMenuItems(newItem, MENU_CACHE_DIR(menuItem)); + break; + } + } + } + g_slist_free_full(list, (GDestroyNotify)menu_cache_item_unref); +} + +void AppMenuView::onMenuCacheReload(MenuCache* mc) { + MenuCacheDir* dir = menu_cache_dup_root_dir(mc); + model_->clear(); + /* FIXME: preserve original selection */ + if(dir) { + addMenuItems(NULL, dir); + menu_cache_item_unref(MENU_CACHE_ITEM(dir)); + selectionModel()->select(model_->index(0, 0), QItemSelectionModel::SelectCurrent); + } +} + +bool AppMenuView::isAppSelected() { + AppMenuViewItem* item = selectedItem(); + return (item && item->isApp()); +} + +AppMenuViewItem* AppMenuView::selectedItem() { + QModelIndexList selected = selectedIndexes(); + if(!selected.isEmpty()) { + AppMenuViewItem* item = static_cast(model_->itemFromIndex(selected.first() + )); + return item; + } + return NULL; +} + +GAppInfo* AppMenuView::selectedApp() { + const char* id = selectedAppDesktopId(); + return id ? G_APP_INFO(g_desktop_app_info_new(id)) : NULL; +} + +QByteArray AppMenuView::selectedAppDesktopFilePath() { + AppMenuViewItem* item = selectedItem(); + if(item && item->isApp()) { + char* path = menu_cache_item_get_file_path(item->item()); + QByteArray ret(path); + g_free(path); + return ret; + } + return QByteArray(); +} + +const char* AppMenuView::selectedAppDesktopId() { + AppMenuViewItem* item = selectedItem(); + if(item && item->isApp()) { + return menu_cache_item_get_id(item->item()); + } + return NULL; +} + +FmPath* AppMenuView::selectedAppDesktopPath() { + AppMenuViewItem* item = selectedItem(); + if(item && item->isApp()) { + char* mpath = menu_cache_dir_make_path(MENU_CACHE_DIR(item)); + FmPath* path = fm_path_new_relative(fm_path_get_apps_menu(), + mpath + 13 /* skip "/Applications" */); + g_free(mpath); + return path; + } + return NULL; +} + +} // namespace Fm diff --git a/libfm-qt/appmenuview.h b/libfm-qt/appmenuview.h new file mode 100644 index 0000000..72b837b --- /dev/null +++ b/libfm-qt/appmenuview.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_APPMENUVIEW_H +#define FM_APPMENUVIEW_H + +#include +#include "libfmqtglobals.h" +#include +#include + +class QStandardItemModel; +class QStandardItem; + +namespace Fm { + +class AppMenuViewItem; + +class LIBFM_QT_API AppMenuView : public QTreeView { + Q_OBJECT +public: + explicit AppMenuView(QWidget* parent = NULL); + ~AppMenuView(); + + GAppInfo* selectedApp(); + + const char* selectedAppDesktopId(); + + QByteArray selectedAppDesktopFilePath(); + + FmPath * selectedAppDesktopPath(); + + bool isAppSelected(); + +Q_SIGNALS: + void selectionChanged(); + +private: + void addMenuItems(QStandardItem* parentItem, MenuCacheDir* dir); + void onMenuCacheReload(MenuCache* mc); + static void _onMenuCacheReload(MenuCache* mc, gpointer user_data) { + static_cast(user_data)->onMenuCacheReload(mc); + } + + AppMenuViewItem* selectedItem(); + +private: + // gboolean fm_app_menu_view_is_item_app(, GtkTreeIter* it); + QStandardItemModel* model_; + MenuCache* menu_cache; + MenuCacheNotifyId menu_cache_reload_notify; +}; + +} + +#endif // FM_APPMENUVIEW_H diff --git a/libfm-qt/appmenuview_p.h b/libfm-qt/appmenuview_p.h new file mode 100644 index 0000000..a09ecc8 --- /dev/null +++ b/libfm-qt/appmenuview_p.h @@ -0,0 +1,74 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_APPMENUVIEW_P_H +#define FM_APPMENUVIEW_P_H + +#include +#include +#include "icontheme.h" + +namespace Fm { + +class AppMenuViewItem : public QStandardItem { +public: + explicit AppMenuViewItem(MenuCacheItem* item): + item_(menu_cache_item_ref(item)) { + FmIcon* fmicon; + if(menu_cache_item_get_icon(item)) + fmicon = fm_icon_from_name(menu_cache_item_get_icon(item)); + else + fmicon = NULL; + setText(QString::fromUtf8(menu_cache_item_get_name(item))); + setEditable(false); + setDragEnabled(false); + if(fmicon) { + setIcon(IconTheme::icon(fmicon)); + fm_icon_unref(fmicon); + } + } + + ~AppMenuViewItem() { + menu_cache_item_unref(item_); + } + + MenuCacheItem* item() { + return item_; + } + + MenuCacheType type() { + return menu_cache_item_get_type(item_); + } + + bool isApp() { + return type() == MENU_CACHE_TYPE_APP; + } + + bool isDir() { + return type() == MENU_CACHE_TYPE_DIR; + } + +private: + MenuCacheItem* item_; +}; + +} + +#endif // FM_APPMENUVIEW_P_H diff --git a/libfm-qt/bookmarkaction.cpp b/libfm-qt/bookmarkaction.cpp new file mode 100644 index 0000000..43b2ab4 --- /dev/null +++ b/libfm-qt/bookmarkaction.cpp @@ -0,0 +1,30 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "bookmarkaction.h" + +using namespace Fm; + +BookmarkAction::BookmarkAction(FmBookmarkItem* item, QObject* parent): + QAction(parent), + item_(fm_bookmark_item_ref(item)) { + + setText(QString::fromUtf8(item->name)); +} diff --git a/libfm-qt/bookmarkaction.h b/libfm-qt/bookmarkaction.h new file mode 100644 index 0000000..8bc55a1 --- /dev/null +++ b/libfm-qt/bookmarkaction.h @@ -0,0 +1,54 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 BOOKMARKACTION_H +#define BOOKMARKACTION_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +// action used to create bookmark menu items +class LIBFM_QT_API BookmarkAction : public QAction { +public: + explicit BookmarkAction(FmBookmarkItem* item, QObject* parent = 0); + + virtual ~BookmarkAction() { + if(item_) + fm_bookmark_item_unref(item_); + } + + FmBookmarkItem* bookmark() { + return item_; + } + + FmPath* path() { + return item_->path; + } + +private: + FmBookmarkItem* item_; +}; + +} + +#endif // BOOKMARKACTION_H diff --git a/libfm-qt/browsehistory.cpp b/libfm-qt/browsehistory.cpp new file mode 100644 index 0000000..18bd5af --- /dev/null +++ b/libfm-qt/browsehistory.cpp @@ -0,0 +1,87 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "browsehistory.h" + +using namespace Fm; + +BrowseHistory::BrowseHistory(): + currentIndex_(0), + maxCount_(10) { +} + +BrowseHistory::~BrowseHistory() { +} + +void BrowseHistory::add(FmPath* path, int scrollPos) { + int lastIndex = size() - 1; + if(currentIndex_ < lastIndex) { + // if we're not at the last item, remove items after the current one. + erase(begin() + currentIndex_ + 1, end()); + } + + if(size() + 1 > maxCount_) { + // if there are too many items, remove the oldest one. + // FIXME: what if currentIndex_ == 0? remove the last item instead? + if(currentIndex_ == 0) + remove(lastIndex); + else { + remove(0); + --currentIndex_; + } + } + // add a path and current scroll position to browse history + append(BrowseHistoryItem(path, scrollPos)); + currentIndex_ = size() - 1; +} + +void BrowseHistory::setCurrentIndex(int index) { + if(index >= 0 && index < size()) { + currentIndex_ = index; + // FIXME: should we emit a signal for the change? + } +} + +bool BrowseHistory::canBackward() const { + return (currentIndex_ > 0); +} + +int BrowseHistory::backward() { + if(canBackward()) + --currentIndex_; + return currentIndex_; +} + +bool BrowseHistory::canForward() const { + return (currentIndex_ + 1 < size()); +} + +int BrowseHistory::forward() { + if(canForward()) + ++currentIndex_; + return currentIndex_; +} + +void BrowseHistory::setMaxCount(int maxCount) { + maxCount_ = maxCount; + if(size() > maxCount) { + // TODO: remove some items + } +} diff --git a/libfm-qt/browsehistory.h b/libfm-qt/browsehistory.h new file mode 100644 index 0000000..28f0224 --- /dev/null +++ b/libfm-qt/browsehistory.h @@ -0,0 +1,131 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_BROWSEHISTORY_H +#define FM_BROWSEHISTORY_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +// class used to story browsing history of folder views +// We use this class to replace FmNavHistory provided by libfm since +// the original Libfm API is hard to use and confusing. + +class LIBFM_QT_API BrowseHistoryItem { +public: + + BrowseHistoryItem(): + path_(NULL), + scrollPos_(0) { + } + + BrowseHistoryItem(FmPath* path, int scrollPos = 0): + path_(fm_path_ref(path)), + scrollPos_(scrollPos) { + } + + BrowseHistoryItem(const BrowseHistoryItem& other): + path_(other.path_ ? fm_path_ref(other.path_) : NULL), + scrollPos_(other.scrollPos_) { + } + + ~BrowseHistoryItem() { + if(path_) + fm_path_unref(path_); + } + + BrowseHistoryItem& operator=(const BrowseHistoryItem& other) { + if(path_) + fm_path_unref(path_); + path_ = other.path_ ? fm_path_ref(other.path_) : NULL; + scrollPos_ = other.scrollPos_; + return *this; + } + + FmPath* path() const { + return path_; + } + + int scrollPos() const { + return scrollPos_; + } + + void setScrollPos(int pos) { + scrollPos_ = pos; + } + +private: + FmPath* path_; + int scrollPos_; + // TODO: we may need to store current selection as well. reserve room for furutre expansion. + // void* reserved1; + // void* reserved2; +}; + +class LIBFM_QT_API BrowseHistory : public QVector { + +public: + BrowseHistory(); + virtual ~BrowseHistory(); + + int currentIndex() const { + return currentIndex_; + } + void setCurrentIndex(int index); + + FmPath* currentPath() const { + return at(currentIndex_).path(); + } + + int currentScrollPos() const { + return at(currentIndex_).scrollPos(); + } + + BrowseHistoryItem& currentItem() { + return operator[](currentIndex_); + } + + void add(FmPath* path, int scrollPos = 0); + + bool canForward() const; + + bool canBackward() const; + + int backward(); + + int forward(); + + int maxCount() const { + return maxCount_; + } + + void setMaxCount(int maxCount); + +private: + int currentIndex_; + int maxCount_; +}; + +} + +#endif // FM_BROWSEHISTORY_H diff --git a/libfm-qt/cachedfoldermodel.cpp b/libfm-qt/cachedfoldermodel.cpp new file mode 100644 index 0000000..d46a559 --- /dev/null +++ b/libfm-qt/cachedfoldermodel.cpp @@ -0,0 +1,74 @@ +/* + + Copyright (C) 2013 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "cachedfoldermodel.h" + +using namespace Fm; + +static GQuark data_id = 0; + + +CachedFolderModel::CachedFolderModel(FmFolder* folder): + FolderModel(), + refCount(1) { + + FolderModel::setFolder(folder); +} + +CachedFolderModel::~CachedFolderModel() { + qDebug("delete CachedFolderModel"); +} + +CachedFolderModel* CachedFolderModel::modelFromFolder(FmFolder* folder) { + CachedFolderModel* model = NULL; + if(!data_id) + data_id = g_quark_from_static_string("CachedFolderModel"); + gpointer qdata = g_object_get_qdata(G_OBJECT(folder), data_id); + model = reinterpret_cast(qdata); + if(model) { + // qDebug("cache found!!"); + model->ref(); + } + else { + model = new CachedFolderModel(folder); + g_object_set_qdata(G_OBJECT(folder), data_id, model); + } + return model; +} + +CachedFolderModel* CachedFolderModel::modelFromPath(FmPath* path) { + FmFolder* folder = fm_folder_from_path(path); + if(folder) { + CachedFolderModel* model = modelFromFolder(folder); + g_object_unref(folder); + return model; + } + return NULL; +} + +void CachedFolderModel::unref() { + // qDebug("unref cache"); + --refCount; + if(refCount <= 0) { + g_object_set_qdata(G_OBJECT(folder()), data_id, NULL); + deleteLater(); + } +} + diff --git a/libfm-qt/cachedfoldermodel.h b/libfm-qt/cachedfoldermodel.h new file mode 100644 index 0000000..8cab66b --- /dev/null +++ b/libfm-qt/cachedfoldermodel.h @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2013 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_CACHEDFOLDERMODEL_H +#define FM_CACHEDFOLDERMODEL_H + +#include "libfmqtglobals.h" +#include "foldermodel.h" + +namespace Fm { + +class LIBFM_QT_API CachedFolderModel : public FolderModel { + Q_OBJECT +public: + CachedFolderModel(FmFolder* folder); + void ref() { + ++refCount; + } + void unref(); + + static CachedFolderModel* modelFromFolder(FmFolder* folder); + static CachedFolderModel* modelFromPath(FmPath* path); + +private: + virtual ~CachedFolderModel(); + void setFolder(FmFolder* folder); +private: + int refCount; +}; + + +} + +#endif // FM_CACHEDFOLDERMODEL_H diff --git a/libfm-qt/colorbutton.cpp b/libfm-qt/colorbutton.cpp new file mode 100644 index 0000000..348eab1 --- /dev/null +++ b/libfm-qt/colorbutton.cpp @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "colorbutton.h" +#include + +using namespace Fm; + +ColorButton::ColorButton(QWidget* parent): QPushButton(parent) { + connect(this, &QPushButton::clicked, this, &ColorButton::onClicked); +} + +ColorButton::~ColorButton() { + +} + +void ColorButton::onClicked() { + QColorDialog dlg(color_); + if(dlg.exec() == QDialog::Accepted) { + setColor(dlg.selectedColor()); + } +} + +void ColorButton::setColor(const QColor& color) { + if(color != color_) { + color_ = color; + // use qss instead of QPalette to set the background color + // otherwise, this won't work when using the gtk style. + QString style = QString("QPushButton{background-color:%1;}").arg(color.name()); + setStyleSheet(style); + Q_EMIT changed(); + } +} + diff --git a/libfm-qt/colorbutton.h b/libfm-qt/colorbutton.h new file mode 100644 index 0000000..bb04af5 --- /dev/null +++ b/libfm-qt/colorbutton.h @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_COLORBUTTON_H +#define FM_COLORBUTTON_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class LIBFM_QT_API ColorButton : public QPushButton { +Q_OBJECT + +public: + explicit ColorButton(QWidget* parent = 0); + virtual ~ColorButton(); + + void setColor(const QColor&); + + QColor color() const { + return color_; + } + +Q_SIGNALS: + void changed(); + +private Q_SLOTS: + void onClicked(); + +private: + QColor color_; +}; + +} + +#endif // FM_COLORBUTTON_H diff --git a/libfm-qt/dirtreemodel.cpp b/libfm-qt/dirtreemodel.cpp new file mode 100644 index 0000000..8d41e52 --- /dev/null +++ b/libfm-qt/dirtreemodel.cpp @@ -0,0 +1,205 @@ +/* + * Copyright 2014 Hong Jen Yee (PCMan) + * + * 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 "dirtreemodel.h" +#include "dirtreemodelitem.h" +#include + +namespace Fm { + +DirTreeModel::DirTreeModel(QObject* parent): + showHidden_(false) { +} + +DirTreeModel::~DirTreeModel() { +} + +// QAbstractItemModel implementation + +Qt::ItemFlags DirTreeModel::flags(const QModelIndex& index) const { + DirTreeModelItem* item = itemFromIndex(index); + if(item && item->isPlaceHolder()) + return Qt::ItemIsEnabled; + return QAbstractItemModel::flags(index); +} + +QVariant DirTreeModel::data(const QModelIndex& index, int role) const { + if(!index.isValid() || index.column() > 1) { + return QVariant(); + } + DirTreeModelItem* item = itemFromIndex(index); + if(item) { + FmFileInfo* info = item->fileInfo_; + switch(role) { + case Qt::ToolTipRole: + return QVariant(item->displayName_); + case Qt::DisplayRole: + return QVariant(item->displayName_); + case Qt::DecorationRole: + return QVariant(item->icon_); + case FileInfoRole: + return qVariantFromValue((void*)info); + } + } + return QVariant(); +} + +int DirTreeModel::columnCount(const QModelIndex& parent) const { + return 1; +} + +int DirTreeModel::rowCount(const QModelIndex& parent) const { + if(!parent.isValid()) + return rootItems_.count(); + DirTreeModelItem* item = itemFromIndex(parent); + if(item) + return item->children_.count(); + return 0; +} + +QModelIndex DirTreeModel::parent(const QModelIndex& child) const { + DirTreeModelItem* item = itemFromIndex(child); + if(item && item->parent_) { + item = item->parent_; // go to parent item + if(item) { + const QList& items = item->parent_ ? item->parent_->children_ : rootItems_; + int row = items.indexOf(item); // this is Q(n) and may be slow :-( + if(row >= 0) + return createIndex(row, 0, (void*)item); + } + } + return QModelIndex(); +} + +QModelIndex DirTreeModel::index(int row, int column, const QModelIndex& parent) const { + if(row >= 0 && column >= 0 && column == 0) { + if(!parent.isValid()) { // root items + if(row < rootItems_.count()) { + const DirTreeModelItem* item = rootItems_.at(row); + return createIndex(row, column, (void*)item); + } + } + else { // child items + DirTreeModelItem* parentItem = itemFromIndex(parent); + if(row < parentItem->children_.count()) { + const DirTreeModelItem* item = parentItem->children_.at(row); + return createIndex(row, column, (void*)item); + } + } + } + return QModelIndex(); // invalid index +} + +bool DirTreeModel::hasChildren(const QModelIndex& parent) const { + DirTreeModelItem* item = itemFromIndex(parent); + return item ? !item->isPlaceHolder() : true; +} + +QModelIndex DirTreeModel::indexFromItem(DirTreeModelItem* item) const { + Q_ASSERT(item); + const QList& items = item->parent_ ? item->parent_->children_ : rootItems_; + int row = items.indexOf(item); + if(row >= 0) + return createIndex(row, 0, (void*)item); + return QModelIndex(); +} + +// public APIs +QModelIndex DirTreeModel::addRoot(FmFileInfo* root) { + DirTreeModelItem* item = new DirTreeModelItem(root, this); + int row = rootItems_.count(); + beginInsertRows(QModelIndex(), row, row); + item->fileInfo_ = fm_file_info_ref(root); + rootItems_.append(item); + // add_place_holder_child_item(model, item_l, NULL, FALSE); + endInsertRows(); + return QModelIndex(); +} + +DirTreeModelItem* DirTreeModel::itemFromIndex(const QModelIndex& index) const { + return reinterpret_cast(index.internalPointer()); +} + +QModelIndex DirTreeModel::indexFromPath(FmPath* path) const { + DirTreeModelItem* item = itemFromPath(path); + return item ? item->index() : QModelIndex(); +} + +DirTreeModelItem* DirTreeModel::itemFromPath(FmPath* path) const { + Q_FOREACH(DirTreeModelItem* item, rootItems_) { + if(item->fileInfo_ && fm_path_equal(path, fm_file_info_get_path(item->fileInfo_))) { + return item; + } + else { + DirTreeModelItem* child = item->childFromPath(path, true); + if(child) + return child; + } + } + return NULL; +} + + +void DirTreeModel::loadRow(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + Q_ASSERT(item); + if(item && !item->isPlaceHolder()) + item->loadFolder(); +} + +void DirTreeModel::unloadRow(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + if(item && !item->isPlaceHolder()) + item->unloadFolder(); +} + +bool DirTreeModel::isLoaded(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + return item ? item->loaded_ : false; +} + +QIcon DirTreeModel::icon(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + return item ? item->icon_ : QIcon(); +} + +FmFileInfo* DirTreeModel::fileInfo(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + return item ? item->fileInfo_ : NULL; +} + +FmPath* DirTreeModel::filePath(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + return item && item->fileInfo_ ? fm_file_info_get_path(item->fileInfo_) : NULL; +} + +QString DirTreeModel::dispName(const QModelIndex& index) { + DirTreeModelItem* item = itemFromIndex(index); + return item ? item->displayName_ : QString(); +} + +void DirTreeModel::setShowHidden(bool show_hidden) { + showHidden_ = show_hidden; + Q_FOREACH(DirTreeModelItem* item, rootItems_) { + item->setShowHidden(show_hidden); + } +} + + +} // namespace Fm diff --git a/libfm-qt/dirtreemodel.h b/libfm-qt/dirtreemodel.h new file mode 100644 index 0000000..94a72e7 --- /dev/null +++ b/libfm-qt/dirtreemodel.h @@ -0,0 +1,90 @@ +/* + * + * Copyright (C) 2014 + * + * 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 FM_DIRTREEMODEL_H +#define FM_DIRTREEMODEL_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include +#include + +namespace Fm { + +class DirTreeModelItem; +class DirTreeView; + +class LIBFM_QT_API DirTreeModel : public QAbstractItemModel { + Q_OBJECT + +public: + friend class DirTreeModelItem; // allow direct access of private members in DirTreeModelItem + friend class DirTreeView; // allow direct access of private members in DirTreeView + + enum Role { + FileInfoRole = Qt::UserRole + }; + + explicit DirTreeModel(QObject* parent); + ~DirTreeModel(); + + QModelIndex addRoot(FmFileInfo* root); + void loadRow(const QModelIndex& index); + void unloadRow(const QModelIndex& index); + + bool isLoaded(const QModelIndex& index); + QIcon icon(const QModelIndex& index); + FmFileInfo* fileInfo(const QModelIndex& index); + FmPath* filePath(const QModelIndex& index); + QString dispName(const QModelIndex& index); + + void setShowHidden(bool show_hidden); + bool showHidden() const { + return showHidden_; + } + + QModelIndex indexFromPath(FmPath* path) const; + + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + virtual QVariant data(const QModelIndex& index, int role) const; + virtual int columnCount(const QModelIndex& parent) const; + virtual int rowCount(const QModelIndex& parent) const; + virtual QModelIndex parent(const QModelIndex& child) const; + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const; + virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; + +private: + DirTreeModelItem* itemFromPath(FmPath* path) const; + DirTreeModelItem* itemFromIndex(const QModelIndex& index) const; + QModelIndex indexFromItem(DirTreeModelItem* item) const; + +Q_SIGNALS: + void rowLoaded(const QModelIndex& index); + +private: + bool showHidden_; + QList rootItems_; +}; +} + +#endif // FM_DIRTREEMODEL_H diff --git a/libfm-qt/dirtreemodelitem.cpp b/libfm-qt/dirtreemodelitem.cpp new file mode 100644 index 0000000..8ab9c33 --- /dev/null +++ b/libfm-qt/dirtreemodelitem.cpp @@ -0,0 +1,340 @@ +/* + * + * Copyright (C) 2014 + * + * 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 "dirtreemodelitem.h" +#include "dirtreemodel.h" +#include "icontheme.h" +#include + +namespace Fm { + +DirTreeModelItem::DirTreeModelItem(): + model_(NULL), + folder_(NULL), + expanded_(false), + loaded_(false), + fileInfo_(NULL), + placeHolderChild_(NULL), + parent_(NULL) { +} + +DirTreeModelItem::DirTreeModelItem(FmFileInfo* info, DirTreeModel* model, DirTreeModelItem* parent): + model_(model), + folder_(NULL), + expanded_(false), + loaded_(false), + fileInfo_(fm_file_info_ref(info)), + displayName_(QString::fromUtf8(fm_file_info_get_disp_name(info))), + icon_(IconTheme::icon(fm_file_info_get_icon(info))), + placeHolderChild_(NULL), + parent_(parent) { + + if(info) + addPlaceHolderChild(); +} + +DirTreeModelItem::~DirTreeModelItem() { + if(fileInfo_) + fm_file_info_unref(fileInfo_); + + if(folder_) + freeFolder(); + + // delete child items if needed + if(!children_.isEmpty()) { + Q_FOREACH(DirTreeModelItem* item, children_) { + delete item; + } + } + if(!hiddenChildren_.isEmpty()) { + Q_FOREACH(DirTreeModelItem* item, hiddenChildren_) { + delete item; + } + } +} + +void DirTreeModelItem::addPlaceHolderChild() { + placeHolderChild_ = new DirTreeModelItem(); + placeHolderChild_->parent_ = this; + placeHolderChild_->model_ = model_; + placeHolderChild_->displayName_ = DirTreeModel::tr("Loading..."); + children_.append(placeHolderChild_); +} + +void DirTreeModelItem::freeFolder() { + if(folder_) { + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFolderFinishLoading), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFolderFilesAdded), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFolderFilesRemoved), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFolderFilesChanged), this); + g_object_unref(folder_); + folder_ = NULL; + } +} + +void DirTreeModelItem::loadFolder() { + if(!expanded_) { + /* dynamically load content of the folder. */ + folder_ = fm_folder_from_path(fm_file_info_get_path(fileInfo_)); + /* g_debug("fm_dir_tree_model_load_row()"); */ + /* associate the data with loaded handler */ + g_signal_connect(folder_, "finish-loading", G_CALLBACK(onFolderFinishLoading), this); + g_signal_connect(folder_, "files-added", G_CALLBACK(onFolderFilesAdded), this); + g_signal_connect(folder_, "files-removed", G_CALLBACK(onFolderFilesRemoved), this); + g_signal_connect(folder_, "files-changed", G_CALLBACK(onFolderFilesChanged), this); + + /* set 'expanded' flag beforehand as callback may check it */ + expanded_ = true; + /* if the folder is already loaded, call "loaded" handler ourselves */ + if(fm_folder_is_loaded(folder_)) { // already loaded + GList* file_l; + FmFileInfoList* files = fm_folder_get_files(folder_); + for(file_l = fm_file_info_list_peek_head_link(files); file_l; file_l = file_l->next) { + FmFileInfo* fi = FM_FILE_INFO(file_l->data); + if(fm_file_info_is_dir(fi)) { + insertFileInfo(fi); + } + } + onFolderFinishLoading(folder_, this); + } + } +} + +void DirTreeModelItem::unloadFolder() { + if(expanded_) { /* do some cleanup */ + /* remove all children, and replace them with a dummy child + * item to keep expander in the tree view around. */ + + // delete all visible child items + model_->beginRemoveRows(index(), 0, children_.count() - 1); + if(!children_.isEmpty()) { + Q_FOREACH(DirTreeModelItem* item, children_) { + delete item; + } + children_.clear(); + } + model_->endRemoveRows(); + + // remove hidden children + if(!hiddenChildren_.isEmpty()) { + Q_FOREACH(DirTreeModelItem* item, hiddenChildren_) { + delete item; + } + hiddenChildren_.clear(); + } + + /* now, we have no child since all child items are removed. + * So we add a place holder child item to keep the expander around. */ + addPlaceHolderChild(); + /* deactivate folder since it will be reactivated on expand */ + freeFolder(); + expanded_ = false; + loaded_ = false; + } +} + +QModelIndex DirTreeModelItem::index() { + Q_ASSERT(model_); + return model_->indexFromItem(this); +} + +/* Add file info to parent node to proper position. + * GtkTreePath tp is the tree path of parent node. */ +DirTreeModelItem* DirTreeModelItem::insertFileInfo(FmFileInfo* fi) { + // qDebug() << "insertFileInfo: " << fm_file_info_get_disp_name(fi); + DirTreeModelItem* item = new DirTreeModelItem(fi, model_); + insertItem(item); + return item; +} + +// find a good position to insert the new item +int DirTreeModelItem::insertItem(DirTreeModelItem* newItem) { + if(model_->showHidden() || !newItem->fileInfo_ || !fm_file_info_is_hidden(newItem->fileInfo_)) { + const char* new_key = fm_file_info_get_collate_key(newItem->fileInfo_); + int pos = 0; + QList::iterator it; + for(it = children_.begin(); it != children_.end(); ++it) { + DirTreeModelItem* child = *it; + if(G_UNLIKELY(!child->fileInfo_)) + continue; + const char* key = fm_file_info_get_collate_key(child->fileInfo_); + if(strcmp(new_key, key) <= 0) + break; + ++pos; + } + // inform the world that we're about to insert the item + model_->beginInsertRows(index(), pos, pos); + newItem->parent_ = this; + children_.insert(it, newItem); + model_->endInsertRows(); + return pos; + } + else { // hidden folder + hiddenChildren_.append(newItem); + } + return -1; +} + + +// FmFolder signal handlers + +// static +void DirTreeModelItem::onFolderFinishLoading(FmFolder* folder, gpointer user_data) { + DirTreeModelItem* _this = (DirTreeModelItem*)user_data; + DirTreeModel* model = _this->model_; + /* set 'loaded' flag beforehand as callback may check it */ + _this->loaded_ = true; + QModelIndex index = _this->index(); +qDebug() << "folder loaded"; + // remove the placeholder child if needed + if(_this->children_.count() == 1) { // we have no other child other than the place holder item, leave it + _this->placeHolderChild_->displayName_ = DirTreeModel::tr(""); + QModelIndex placeHolderIndex = _this->placeHolderChild_->index(); + // qDebug() << "placeHolderIndex: "<dataChanged(placeHolderIndex, placeHolderIndex); + } + else { + int pos = _this->children_.indexOf(_this->placeHolderChild_); + model->beginRemoveRows(index, pos, pos); + _this->children_.removeAt(pos); + delete _this->placeHolderChild_; + model->endRemoveRows(); + _this->placeHolderChild_ = NULL; + } + + Q_EMIT model->rowLoaded(index); +} + +// static +void DirTreeModelItem::onFolderFilesAdded(FmFolder* folder, GSList* files, gpointer user_data) { + GSList* l; + DirTreeModelItem* _this = (DirTreeModelItem*)user_data; + DirTreeModel* model = _this->model_; + for(l = files; l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + if(fm_file_info_is_dir(fi)) { /* FIXME: maybe adding files can be allowed later */ + /* Ideally FmFolder should not emit files-added signals for files that + * already exists. So there is no need to check for duplication here. */ + _this->insertFileInfo(fi); + } + } +} + +// static +void DirTreeModelItem::onFolderFilesRemoved(FmFolder* folder, GSList* files, gpointer user_data) { + DirTreeModelItem* _this = (DirTreeModelItem*)user_data; + DirTreeModel* model = _this->model_; + + for(GSList* l = files; l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + int pos; + DirTreeModelItem* child = _this->childFromName(fm_file_info_get_name(fi), &pos); + if(child) { + model->beginRemoveRows(_this->index(), pos, pos); + _this->children_.removeAt(pos); + delete child; + model->endRemoveRows(); + } + } +} + +// static +void DirTreeModelItem::onFolderFilesChanged(FmFolder* folder, GSList* files, gpointer user_data) { + DirTreeModelItem* _this = (DirTreeModelItem*)user_data; + DirTreeModel* model = _this->model_; + + for(GSList* l = files; l; l = l->next) { + FmFileInfo* changedFile = FM_FILE_INFO(l->data); + int pos; + DirTreeModelItem* child = _this->childFromName(fm_file_info_get_name(changedFile), &pos); + if(child) { + QModelIndex childIndex = child->index(); + Q_EMIT model->dataChanged(childIndex, childIndex); + } + } +} + +DirTreeModelItem* DirTreeModelItem::childFromName(const char* utf8_name, int* pos) { + int i = 0; + Q_FOREACH(DirTreeModelItem* item, children_) { + if(item->fileInfo_ && strcmp(fm_file_info_get_name(item->fileInfo_), utf8_name) == 0) { + if(pos) + *pos = i; + return item; + } + ++i; + } + return NULL; +} + +DirTreeModelItem* DirTreeModelItem::childFromPath(FmPath* path, bool recursive) const { + Q_ASSERT(path != NULL); + + Q_FOREACH(DirTreeModelItem* item, children_) { + // if(item->fileInfo_) + // qDebug() << "child: " << QString::fromUtf8(fm_file_info_get_disp_name(item->fileInfo_)); + if(item->fileInfo_ && fm_path_equal(fm_file_info_get_path(item->fileInfo_), path)) { + return item; + } + else if(recursive) { + DirTreeModelItem* child = item->childFromPath(path, true); + if(child) + return child; + } + } + return NULL; +} + +void DirTreeModelItem::setShowHidden(bool show) { + if(show) { + // move all hidden children to visible list + Q_FOREACH(DirTreeModelItem* item, hiddenChildren_) { + insertItem(item); + } + hiddenChildren_.clear(); + } + else { // hide hidden folders + QModelIndex _index = index(); + QList::iterator it, next; + int pos = 0; + for(it = children_.begin(); it != children_.end(); ++pos) { + DirTreeModelItem* item = *it; + next = it + 1; + if(item->fileInfo_) { + if(fm_file_info_is_hidden(item->fileInfo_)) { // hidden folder + // remove from the model and add to the hiddenChildren_ list + model_->beginRemoveRows(_index, pos, pos); + children_.erase(it); + hiddenChildren_.append(item); + model_->endRemoveRows(); + } + else { // visible folder, recursively filter its children + item->setShowHidden(show); + } + } + it = next; + } + } +} + + + +} // namespace Fm + diff --git a/libfm-qt/dirtreemodelitem.h b/libfm-qt/dirtreemodelitem.h new file mode 100644 index 0000000..dc11132 --- /dev/null +++ b/libfm-qt/dirtreemodelitem.h @@ -0,0 +1,84 @@ +/* + * + * Copyright (C) 2014 + * + * 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 FM_DIRTREEMODELITEM_H +#define FM_DIRTREEMODELITEM_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include + +namespace Fm { + +class DirTreeModel; +class DirTreeView; + +class LIBFM_QT_API DirTreeModelItem { +public: + friend class DirTreeModel; // allow direct access of private members in DirTreeModel + friend class DirTreeView; // allow direct access of private members in DirTreeView + + explicit DirTreeModelItem(); + explicit DirTreeModelItem(FmFileInfo* info, DirTreeModel* model, DirTreeModelItem* parent = NULL); + ~DirTreeModelItem(); + + void loadFolder(); + void unloadFolder(); + + bool isPlaceHolder() { + return (fileInfo_ == NULL); + } + + void setShowHidden(bool show); + +private: + void freeFolder(); + void addPlaceHolderChild(); + DirTreeModelItem* childFromName(const char* utf8_name, int* pos); + DirTreeModelItem* childFromPath(FmPath* path, bool recursive) const; + + DirTreeModelItem* insertFileInfo(FmFileInfo* fi); + int insertItem(Fm::DirTreeModelItem* newItem); + QModelIndex index(); + + static void onFolderFinishLoading(FmFolder* folder, gpointer user_data); + static void onFolderFilesAdded(FmFolder* folder, GSList* files, gpointer user_data); + static void onFolderFilesRemoved(FmFolder* folder, GSList* files, gpointer user_data); + static void onFolderFilesChanged(FmFolder* folder, GSList* files, gpointer user_data); + +private: + FmFileInfo* fileInfo_; + FmFolder* folder_; + QString displayName_ ; + QIcon icon_; + bool expanded_; + bool loaded_; + DirTreeModelItem* parent_; + DirTreeModelItem* placeHolderChild_; + QList children_; + QList hiddenChildren_; + DirTreeModel* model_; +}; + +} + +#endif // FM_DIRTREEMODELITEM_H diff --git a/libfm-qt/dirtreeview.cpp b/libfm-qt/dirtreeview.cpp new file mode 100644 index 0000000..d4f398f --- /dev/null +++ b/libfm-qt/dirtreeview.cpp @@ -0,0 +1,214 @@ +/* + * + * Copyright (C) 2014 + * + * 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 "dirtreeview.h" +#include +#include +#include +#include +#include "dirtreemodel.h" +#include "dirtreemodelitem.h" + +using namespace Fm; + +DirTreeView::DirTreeView(QWidget* parent): + currentExpandingItem_(NULL), + currentPath_(NULL) { + + setSelectionMode(QAbstractItemView::SingleSelection); + setHeaderHidden(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + header()->setStretchLastSection(false); + + connect(this, &DirTreeView::collapsed, this, &DirTreeView::onCollapsed); + connect(this, &DirTreeView::expanded, this, &DirTreeView::onExpanded); +} + +DirTreeView::~DirTreeView() { + if(currentPath_) + fm_path_unref(currentPath_); +} + +void DirTreeView::cancelPendingChdir() { + if(!pathsToExpand_.isEmpty()) { + pathsToExpand_.clear(); + if(!currentExpandingItem_) + return; + DirTreeModel* _model = static_cast(model()); + disconnect(_model, &DirTreeModel::rowLoaded, this, &DirTreeView::onRowLoaded); + currentExpandingItem_ = NULL; + } +} + +void DirTreeView::expandPendingPath() { + if(pathsToExpand_.isEmpty()) + return; + + FmPath* path = pathsToExpand_.first().data(); + // qDebug() << "expanding: " << Path(path).displayBasename(); + DirTreeModel* _model = static_cast(model()); + DirTreeModelItem* item = _model->itemFromPath(path); + // qDebug() << "findItem: " << item; + if(item) { + currentExpandingItem_ = item; + connect(_model, &DirTreeModel::rowLoaded, this, &DirTreeView::onRowLoaded); + if(item->loaded_) { // the node is already loaded + onRowLoaded(item->index()); + } + else { + // _model->loadRow(item->index()); + item->loadFolder(); + } + } + else { + selectionModel()->clear(); + /* since we never get it loaded we need to update cwd here */ + if(currentPath_) + fm_path_unref(currentPath_); + currentPath_ = fm_path_ref(path); + + cancelPendingChdir(); // FIXME: is this correct? this is not done in the gtk+ version of libfm. + } +} + +void DirTreeView::onRowLoaded(const QModelIndex& index) { + DirTreeModel* _model = static_cast(model()); + if(!currentExpandingItem_) + return; + if(currentExpandingItem_ != _model->itemFromIndex(index)) { + return; + } + /* disconnect the handler since we only need it once */ + disconnect(_model, &DirTreeModel::rowLoaded, this, &DirTreeView::onRowLoaded); + + DirTreeModelItem* item = _model->itemFromIndex(index); + // qDebug() << "row loaded: " << item->displayName_; + /* after the folder is loaded, the files should have been added to + * the tree model */ + expand(index); + + /* remove the expanded path from pending list */ + pathsToExpand_.removeFirst(); + if(pathsToExpand_.isEmpty()) { /* this is the last one and we're done, select the item */ + // qDebug() << "Done!"; + selectionModel()->select(index, QItemSelectionModel::SelectCurrent|QItemSelectionModel::Clear); + scrollTo(index, QAbstractItemView::EnsureVisible); + } + else { /* continue expanding next pending path */ + expandPendingPath(); + } +} + + +void DirTreeView::setCurrentPath(FmPath* path) { + DirTreeModel* _model = static_cast(model()); + if(!_model) + return; + int rowCount = _model->rowCount(QModelIndex()); + if(rowCount == 0 || fm_path_equal(currentPath_, path)) + return; + + if(currentPath_) + fm_path_unref(currentPath_); + currentPath_ = fm_path_ref(path); + + // NOTE: The content of each node is loaded on demand dynamically. + // So, when we ask for a chdir operation, some nodes do not exists yet. + // We have to wait for the loading of child nodes and continue the + // pending chdir operation after the child nodes become available. + + // cancel previous pending tree expansion + cancelPendingChdir(); + + /* find a root item containing this path */ + FmPath* root; + for(int row = 0; row < rowCount; ++row) { + QModelIndex index = _model->index(row, 0, QModelIndex()); + root = _model->filePath(index); + if(fm_path_has_prefix(path, root)) + break; + root = NULL; + } + + if(root) { /* root item is found */ + do { /* add path elements one by one to a list */ + pathsToExpand_.prepend(path); + // qDebug() << "prepend path: " << Path(path).displayBasename(); + if(fm_path_equal(path, root)) + break; + path = fm_path_get_parent(path); + } + while(path); + + expandPendingPath(); + } +} + +void DirTreeView::setModel(QAbstractItemModel* model) { + Q_ASSERT(model->inherits("Fm::DirTreeModel")); + + if(!pathsToExpand_.isEmpty()) // if a chdir request is in progress, cancel it + cancelPendingChdir(); + + QTreeView::setModel(model); + header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &DirTreeView::onSelectionChanged); +} + + +void DirTreeView::contextMenuEvent(QContextMenuEvent* event) { + QAbstractScrollArea::contextMenuEvent(event); +} + +void DirTreeView::onCollapsed(const QModelIndex& index) { + DirTreeModel* treeModel = static_cast(model()); + if(treeModel) { + treeModel->unloadRow(index); + } +} + +void DirTreeView::onExpanded(const QModelIndex& index) { + DirTreeModel* treeModel = static_cast(model()); + if(treeModel) { + treeModel->loadRow(index); + } +} + +void DirTreeView::onSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected) { + if(!selected.isEmpty()) { + QModelIndex index = selected.first().topLeft(); + DirTreeModel* _model = static_cast(model()); + FmPath* path = _model->filePath(index); + if(path && currentPath_ && fm_path_equal(path, currentPath_)) + return; + cancelPendingChdir(); + if(!path) + return; + if(currentPath_) + fm_path_unref(currentPath_); + currentPath_ = fm_path_ref(path); + + // FIXME: use enums for type rather than hard-coded values 0 or 1 + int type = 0; + if(QGuiApplication::mouseButtons() & Qt::MiddleButton) + type = 1; + Q_EMIT chdirRequested(type, path); + } +} diff --git a/libfm-qt/dirtreeview.h b/libfm-qt/dirtreeview.h new file mode 100644 index 0000000..297a895 --- /dev/null +++ b/libfm-qt/dirtreeview.h @@ -0,0 +1,83 @@ +/* + * + * Copyright (C) 2014 + * + * 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 FM_DIRTREEVIEW_H +#define FM_DIRTREEVIEW_H + +#include "libfmqtglobals.h" +#include +#include +#include "path.h" + +class QItemSelection; + +namespace Fm { + +class DirTreeModelItem; + +class LIBFM_QT_API DirTreeView : public QTreeView { + Q_OBJECT + +public: + DirTreeView(QWidget* parent); + ~DirTreeView(); + + FmPath* currentPath() { + return currentPath_; + } + + void setCurrentPath(FmPath* path); + + // libfm-gtk compatible alias + FmPath* getCwd() { + return currentPath(); + } + + void chdir(FmPath* path) { + setCurrentPath(path); + } + + virtual void setModel(QAbstractItemModel* model); + +protected: + virtual void contextMenuEvent(QContextMenuEvent* event); + +private: + void cancelPendingChdir(); + void expandPendingPath(); + +Q_SIGNALS: + void chdirRequested(int type, FmPath* path); + +protected Q_SLOTS: + void onCollapsed(const QModelIndex & index); + void onExpanded(const QModelIndex & index); + void onRowLoaded(const QModelIndex& index); + void onSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + +private: + FmPath* currentPath_; + QList pathsToExpand_; + DirTreeModelItem* currentExpandingItem_; +}; + +} + +#endif // FM_DIRTREEVIEW_H diff --git a/libfm-qt/dndactionmenu.cpp b/libfm-qt/dndactionmenu.cpp new file mode 100644 index 0000000..62625ea --- /dev/null +++ b/libfm-qt/dndactionmenu.cpp @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "dndactionmenu.h" + +using namespace Fm; + +DndActionMenu::DndActionMenu(QWidget* parent): QMenu(parent) { + copyAction = addAction(QIcon::fromTheme("edit-copy"), tr("Copy here")); + moveAction = addAction(tr("Move here")); + linkAction = addAction(tr("Create symlink here")); + addSeparator(); + cancelAction = addAction(tr("Cancel")); +} + +DndActionMenu::~DndActionMenu() { + +} + +Qt::DropAction DndActionMenu::askUser(QPoint pos) { + Qt::DropAction result; + DndActionMenu menu; + QAction* action = menu.exec(pos); + if(action == menu.copyAction) + result = Qt::CopyAction; + else if(action == menu.moveAction) + result = Qt::MoveAction; + else if(action == menu.linkAction) + result = Qt::LinkAction; + else + result = Qt::IgnoreAction; + return result; +} diff --git a/libfm-qt/dndactionmenu.h b/libfm-qt/dndactionmenu.h new file mode 100644 index 0000000..365acd9 --- /dev/null +++ b/libfm-qt/dndactionmenu.h @@ -0,0 +1,47 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_DNDACTIONMENU_H +#define FM_DNDACTIONMENU_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class DndActionMenu : public QMenu { +Q_OBJECT +public: + explicit DndActionMenu(QWidget* parent = 0); + virtual ~DndActionMenu(); + + static Qt::DropAction askUser(QPoint pos); + +private: + QAction* copyAction; + QAction* moveAction; + QAction* linkAction; + QAction* cancelAction; +}; + +} + +#endif // FM_DNDACTIONMENU_H diff --git a/libfm-qt/dnddest.cpp b/libfm-qt/dnddest.cpp new file mode 100644 index 0000000..ec7a0bd --- /dev/null +++ b/libfm-qt/dnddest.cpp @@ -0,0 +1,71 @@ +/* + * + * Copyright (C) 2014 + * + * 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 "dnddest.h" +#include "fileoperation.h" +#include "utilities.h" + +using namespace Fm; + +const char* supportedMimeTypes[] = { + "text/uri-list" + "XdndDirectSave0"/* X direct save */ + /* TODO: add more targets to support: text types, _NETSCAPE_URL, property/bgimage ... */ +}; + +DndDest::DndDest() { + +} + +DndDest::~DndDest() { + +} + +bool DndDest::dropMimeData(const QMimeData* data, Qt::DropAction action) { + // FIXME: should we put this in dropEvent handler of FolderView instead? + if(data->hasUrls()) { + qDebug("drop action: %d", action); + FmPathList* srcPaths = pathListFromQUrls(data->urls()); + switch(action) { + case Qt::CopyAction: + FileOperation::copyFiles(srcPaths, destPath_.data()); + break; + case Qt::MoveAction: + FileOperation::moveFiles(srcPaths, destPath_.data()); + break; + case Qt::LinkAction: + FileOperation::symlinkFiles(srcPaths, destPath_.data()); + default: + fm_path_list_unref(srcPaths); + return false; + } + fm_path_list_unref(srcPaths); + return true; + } + return false; +} + +bool DndDest::isSupported(const QMimeData* data) { + return false; +} + +bool DndDest::isSupported(QString mimeType) { + return false; +} diff --git a/libfm-qt/dnddest.h b/libfm-qt/dnddest.h new file mode 100644 index 0000000..2084ad5 --- /dev/null +++ b/libfm-qt/dnddest.h @@ -0,0 +1,53 @@ +/* + * + * Copyright (C) 2014 + * + * 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 FM_DNDDEST_H +#define FM_DNDDEST_H + +#include +#include "path.h" + +namespace Fm { + +class DndDest { +public: + DndDest(); + ~DndDest(); + + void setDestPath(FmPath* dest) { + destPath_ = dest; + } + + const Path& destPath() { + return destPath_; + } + + bool isSupported(const QMimeData* data); + bool isSupported(QString mimeType); + + bool dropMimeData(const QMimeData* data, Qt::DropAction action); + +private: + Path destPath_; +}; + +} + +#endif // FM_DNDDEST_H diff --git a/libfm-qt/edit-bookmarks.ui b/libfm-qt/edit-bookmarks.ui new file mode 100644 index 0000000..8d989e6 --- /dev/null +++ b/libfm-qt/edit-bookmarks.ui @@ -0,0 +1,143 @@ + + + EditBookmarksDialog + + + + 0 + 0 + 480 + 320 + + + + Edit Bookmarks + + + + + + true + + + true + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + false + + + false + + + 100 + + + + Name + + + + + Location + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + &Add Item + + + + + + + + + + &Remove Item + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Use drag and drop to reorder the items + + + + + + + + + buttonBox + accepted() + EditBookmarksDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditBookmarksDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/libfm-qt/editbookmarksdialog.cpp b/libfm-qt/editbookmarksdialog.cpp new file mode 100644 index 0000000..7547762 --- /dev/null +++ b/libfm-qt/editbookmarksdialog.cpp @@ -0,0 +1,108 @@ +/* + + Copyright (C) 2013 PCMan + + 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 "editbookmarksdialog.h" +#include "ui_edit-bookmarks.h" +#include +#include +#include +#include +#include + +using namespace Fm; + +EditBookmarksDialog::EditBookmarksDialog(FmBookmarks* bookmarks, QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f), + ui(new Ui::EditBookmarksDialog()), + bookmarks_(FM_BOOKMARKS(g_object_ref(bookmarks))) { + + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); // auto delete on close + + // load bookmarks + GList* l = fm_bookmarks_get_all(bookmarks_); + for(; l; l = l->next) { + FmBookmarkItem* bookmark = reinterpret_cast(l->data); + QTreeWidgetItem* item = new QTreeWidgetItem(); + char* path_str = fm_path_display_name(bookmark->path, false); + item->setData(0, Qt::DisplayRole, QString::fromUtf8(bookmark->name)); + item->setData(1, Qt::DisplayRole, QString::fromUtf8(path_str)); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsDragEnabled|Qt::ItemIsEnabled); + g_free(path_str); + ui->treeWidget->addTopLevelItem(item); + } + + connect(ui->addItem, &QPushButton::clicked, this, &EditBookmarksDialog::onAddItem); + connect(ui->removeItem, &QPushButton::clicked, this, &EditBookmarksDialog::onRemoveItem); +} + +EditBookmarksDialog::~EditBookmarksDialog() { + g_object_unref(bookmarks_); + delete ui; +} + +void EditBookmarksDialog::accept() { + // save bookmarks + // it's easier to recreate the whole bookmark file than + // to manipulate FmBookmarks object. So here we generate the file directly. + // FIXME: maybe in the future we should add a libfm API to easily replace all FmBookmarks. + // Here we use gtk+ 3.0 bookmarks rather than the gtk+ 2.0 one. + // Since gtk+ 2.24.12, gtk+2 reads gtk+3 bookmarks file if it exists. + // So it's safe to only save gtk+3 bookmarks file. + QString path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); + path += QLatin1String("/gtk-3.0"); + if(!QDir().mkpath(path)) + return; // fail to create ~/.config/gtk-3.0 dir + path += QLatin1String("/bookmarks"); + QSaveFile file(path); // use QSaveFile for atomic file operation + if(file.open(QIODevice::WriteOnly)){ + for(int row = 0; ; ++row) { + QTreeWidgetItem* item = ui->treeWidget->topLevelItem(row); + if(!item) + break; + QString name = item->data(0, Qt::DisplayRole).toString(); + QUrl url = QUrl::fromUserInput(item->data(1, Qt::DisplayRole).toString()); + file.write(url.toEncoded()); + file.write(" "); + file.write(name.toUtf8()); + file.write("\n"); + } + // FIXME: should we support Qt or KDE specific bookmarks in the future? + file.commit(); + } + QDialog::accept(); +} + +void EditBookmarksDialog::onAddItem() { + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setData(0, Qt::DisplayRole, tr("New bookmark")); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsDragEnabled|Qt::ItemIsEnabled); + ui->treeWidget->addTopLevelItem(item); + ui->treeWidget->editItem(item); +} + +void EditBookmarksDialog::onRemoveItem() { + QList sels = ui->treeWidget->selectedItems(); + Q_FOREACH(QTreeWidgetItem* item, sels) { + delete item; + } +} + + diff --git a/libfm-qt/editbookmarksdialog.h b/libfm-qt/editbookmarksdialog.h new file mode 100644 index 0000000..95bbdf0 --- /dev/null +++ b/libfm-qt/editbookmarksdialog.h @@ -0,0 +1,53 @@ +/* + + Copyright (C) 2013 PCMan + + 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 FM_EDITBOOKMARKSDIALOG_H +#define FM_EDITBOOKMARKSDIALOG_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Ui { +class EditBookmarksDialog; +}; + +namespace Fm { + +class LIBFM_QT_API EditBookmarksDialog : public QDialog { +Q_OBJECT +public: + explicit EditBookmarksDialog(FmBookmarks* bookmarks, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~EditBookmarksDialog(); + + virtual void accept(); + +private Q_SLOTS: + void onAddItem(); + void onRemoveItem(); + +private: + Ui::EditBookmarksDialog* ui; + FmBookmarks* bookmarks_; +}; + +} + +#endif // FM_EDITBOOKMARKSDIALOG_H diff --git a/libfm-qt/exec-file.ui b/libfm-qt/exec-file.ui new file mode 100644 index 0000000..c5a9ea3 --- /dev/null +++ b/libfm-qt/exec-file.ui @@ -0,0 +1,163 @@ + + + ExecFileDialog + + + + 0 + 0 + 487 + 58 + + + + Execute file + + + + + + + + + + + + + + true + + + + + + + + + + + &Open + + + + + + true + + + + + + + E&xecute + + + + + + + + + + Execute in &Terminal + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + + + + + + + + cancel + clicked() + ExecFileDialog + reject() + + + 341 + 39 + + + 196 + 28 + + + + + exec + clicked() + ExecFileDialog + accept() + + + 56 + 39 + + + 196 + 28 + + + + + execTerm + clicked() + ExecFileDialog + accept() + + + 201 + 39 + + + 196 + 28 + + + + + open + clicked() + ExecFileDialog + accept() + + + 346 + 39 + + + 250 + 28 + + + + + diff --git a/libfm-qt/execfiledialog.cpp b/libfm-qt/execfiledialog.cpp new file mode 100644 index 0000000..9bd3b3b --- /dev/null +++ b/libfm-qt/execfiledialog.cpp @@ -0,0 +1,70 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "execfiledialog_p.h" +#include "ui_exec-file.h" +#include "icontheme.h" + +namespace Fm { + +ExecFileDialog::ExecFileDialog(FmFileInfo* file, QWidget* parent, Qt::WindowFlags f): + QDialog (parent, f), + fileInfo_(fm_file_info_ref(file)), + result_(FM_FILE_LAUNCHER_EXEC_CANCEL), + ui(new Ui::ExecFileDialog()) { + + ui->setupUi(this); + // show file icon + FmIcon* icon = fm_file_info_get_icon(fileInfo_); + ui->icon->setPixmap(IconTheme::icon(icon).pixmap(QSize(48, 48))); + + QString msg; + if(fm_file_info_is_text(file)) { + msg = tr("This text file '%1' seems to be an executable script.\nWhat do you want to do with it?") + .arg(QString::fromUtf8(fm_file_info_get_disp_name(file))); + ui->execTerm->setDefault(true); + } + else { + msg= tr("This file '%1' is executable. Do you want to execute it?") + .arg(QString::fromUtf8(fm_file_info_get_disp_name(file))); + ui->exec->setDefault(true); + ui->open->hide(); + } + ui->msg->setText(msg); +} + +ExecFileDialog::~ExecFileDialog() { + delete ui; + if(fileInfo_) + fm_file_info_unref(fileInfo_); +} + +void ExecFileDialog::accept() { + QObject* _sender = sender(); + if(_sender == ui->exec) + result_ = FM_FILE_LAUNCHER_EXEC; + else if(_sender == ui->execTerm) + result_ = FM_FILE_LAUNCHER_EXEC_IN_TERMINAL; + else if(_sender == ui->open) + result_ = FM_FILE_LAUNCHER_EXEC_OPEN; + QDialog::accept(); +} + +} // namespace Fm diff --git a/libfm-qt/execfiledialog_p.h b/libfm-qt/execfiledialog_p.h new file mode 100644 index 0000000..6c62da5 --- /dev/null +++ b/libfm-qt/execfiledialog_p.h @@ -0,0 +1,54 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_EXECFILEDIALOG_H +#define FM_EXECFILEDIALOG_H + +#include +#include + +namespace Ui { + class ExecFileDialog; +} + +namespace Fm { + +class ExecFileDialog : public QDialog { + Q_OBJECT +public: + ~ExecFileDialog(); + ExecFileDialog(FmFileInfo* fileInfo, QWidget* parent = 0, Qt::WindowFlags f = 0); + + FmFileLauncherExecAction result() { + return result_; + } + +protected: + virtual void accept(); + +private: + Ui::ExecFileDialog* ui; + FmFileInfo* fileInfo_; + FmFileLauncherExecAction result_; +}; + +} + +#endif // FM_EXECFILEDIALOG_H diff --git a/libfm-qt/file-operation-dialog.ui b/libfm-qt/file-operation-dialog.ui new file mode 100644 index 0000000..f81018e --- /dev/null +++ b/libfm-qt/file-operation-dialog.ui @@ -0,0 +1,171 @@ + + + FileOperationDialog + + + + 0 + 0 + 450 + 246 + + + + + + + + + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Destination: + + + + + + + + 0 + 0 + + + + + + + true + + + + + + + Processing: + + + + + + + + 0 + 0 + + + + Preparing... + + + + + + + Progress + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Time remaining: + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + buttonBox + accepted() + FileOperationDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FileOperationDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/libfm-qt/file-props.ui b/libfm-qt/file-props.ui new file mode 100644 index 0000000..3c1ccab --- /dev/null +++ b/libfm-qt/file-props.ui @@ -0,0 +1,700 @@ + + + FilePropsDialog + + + + 0 + 0 + 407 + 396 + + + + File Properties + + + + + + + + + 10 + + + + + 0 + + + + General + + + + 12 + + + 6 + + + + + + 0 + 0 + + + + + + + + + + + + + 32 + 32 + + + + + + + + + + + Location: + + + + + + + + 0 + 0 + + + + + + + true + + + + + + + File type: + + + + + + + + 0 + 0 + + + + + + + + + + + Mime type: + + + + + + + + 0 + 0 + + + + + + + + + + + File size: + + + + + + + + 0 + 0 + + + + + + + + + + + On-disk size: + + + + + + + + 0 + 0 + + + + + + + + + + + Last modified: + + + + + + + + 0 + 0 + + + + + + + + + + + Link target: + + + + + + + + 0 + 0 + + + + + + + true + + + + + + + Open With: + + + + + + + + 0 + 0 + + + + + + + + Last accessed: + + + + + + + + + + + + + + + Permissions + + + + 6 + + + + + + 0 + 0 + + + + Ownership + + + + 12 + + + 6 + + + + + + + + + + + + 0 + 0 + + + + Group: + + + + + + + + 0 + 0 + + + + Owner: + + + + + + + + + + + 0 + 0 + + + + Access Control + + + + + + + 0 + 0 + + + + 0 + + + + + + + Owner: + + + + + + + + 0 + 0 + + + + + + + + Group: + + + + + + + + 0 + 0 + + + + + + + + Other: + + + + + + + + 0 + 0 + + + + + + + + Make the file executable + + + true + + + + + + + + + + + 0 + + + 6 + + + + + + 0 + 0 + + + + Owner: + + + + + + + + 0 + 0 + + + + Read + + + + + + + + 0 + 0 + + + + Write + + + + + + + + 0 + 0 + + + + Execute + + + + + + + + 0 + 0 + + + + Group: + + + + + + + + 0 + 0 + + + + Read + + + + + + + + 0 + 0 + + + + Write + + + + + + + + 0 + 0 + + + + Execute + + + + + + + + 0 + 0 + + + + Other: + + + + + + + + 0 + 0 + + + + Read + + + + + + + + 0 + 0 + + + + Write + + + + + + + + 0 + 0 + + + + Execute + + + + + + + + + Sticky + + + + + + + SetUID + + + + + + + SetGID + + + + + + + Qt::Vertical + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Advanced Mode + + + true + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + Fm::AppChooserComboBox + QComboBox +
appchoosercombobox.h
+
+
+ + + + buttonBox + accepted() + FilePropsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FilePropsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/libfm-qt/filelauncher.cpp b/libfm-qt/filelauncher.cpp new file mode 100644 index 0000000..95c8a4f --- /dev/null +++ b/libfm-qt/filelauncher.cpp @@ -0,0 +1,113 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "filelauncher.h" +#include "applaunchcontext.h" +#include +#include +#include "execfiledialog_p.h" +#include "appchooserdialog.h" +#include "utilities.h" + +using namespace Fm; + +FmFileLauncher FileLauncher::funcs = { + FileLauncher::_getApp, + /* gboolean (*before_open)(GAppLaunchContext* ctx, GList* folder_infos, gpointer user_data); */ + (FmLaunchFolderFunc)FileLauncher::_openFolder, + FileLauncher::_execFile, + FileLauncher::_error, + FileLauncher::_ask +}; + +FileLauncher::FileLauncher() { + +} + +FileLauncher::~FileLauncher() { + +} + +//static +bool FileLauncher::launchFiles(QWidget* parent, GList* file_infos) { + FmAppLaunchContext* context = fm_app_launch_context_new_for_widget(parent); + bool ret = fm_launch_files(G_APP_LAUNCH_CONTEXT(context), file_infos, &funcs, this); + g_object_unref(context); + return ret; +} + +bool FileLauncher::launchPaths(QWidget* parent, GList* paths) { + FmAppLaunchContext* context = fm_app_launch_context_new_for_widget(parent); + bool ret = fm_launch_paths(G_APP_LAUNCH_CONTEXT(context), paths, &funcs, this); + g_object_unref(context); + return ret; +} + +GAppInfo* FileLauncher::getApp(GList* file_infos, FmMimeType* mime_type, GError** err) { + AppChooserDialog dlg(NULL); + if(mime_type) + dlg.setMimeType(mime_type); + else + dlg.setCanSetDefault(false); + // FIXME: show error properly? + if(execModelessDialog(&dlg) == QDialog::Accepted) { + return dlg.selectedApp(); + } + return NULL; +} + +bool FileLauncher::openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err) { + for(GList* l = folder_infos; l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + qDebug() << " folder:" << QString::fromUtf8(fm_file_info_get_disp_name(fi)); + } + return false; +} + +FmFileLauncherExecAction FileLauncher::execFile(FmFileInfo* file) { + FmFileLauncherExecAction res = FM_FILE_LAUNCHER_EXEC_CANCEL; + ExecFileDialog dlg(file); + if(execModelessDialog(&dlg) == QDialog::Accepted) { + res = dlg.result(); + } + return res; +} + +int FileLauncher::ask(const char* msg, char* const* btn_labels, int default_btn) { + /* FIXME: set default button properly */ + // return fm_askv(data->parent, NULL, msg, btn_labels); + return -1; +} + +bool FileLauncher::error(GAppLaunchContext* ctx, GError* err, FmPath* path) { + /* ask for mount if trying to launch unmounted path */ + if(err->domain == G_IO_ERROR) { + if(path && err->code == G_IO_ERROR_NOT_MOUNTED) { + //if(fm_mount_path(data->parent, path, TRUE)) + // return FALSE; /* ask to retry */ + } + else if(err->code == G_IO_ERROR_FAILED_HANDLED) + return true; /* don't show error message */ + } + QMessageBox dlg(QMessageBox::Critical, QObject::tr("Error"), QString::fromUtf8(err->message), QMessageBox::Ok); + execModelessDialog(&dlg); + return true; +} + diff --git a/libfm-qt/filelauncher.h b/libfm-qt/filelauncher.h new file mode 100644 index 0000000..bd02ee0 --- /dev/null +++ b/libfm-qt/filelauncher.h @@ -0,0 +1,78 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_FILELAUNCHER_H +#define FM_FILELAUNCHER_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class LIBFM_QT_API FileLauncher { +public: + FileLauncher(); + virtual ~FileLauncher(); + + bool launchFiles(QWidget* parent, FmFileInfoList* file_infos) { + GList* fileList = fm_file_info_list_peek_head_link(file_infos); + return Fm::FileLauncher::launchFiles(parent, fileList); + } + bool launchPaths(QWidget* parent, FmPathList* paths) { + GList* pathList = fm_path_list_peek_head_link(paths); + return Fm::FileLauncher::launchPaths(parent, pathList); + } + + bool launchFiles(QWidget* parent, GList* file_infos); + bool launchPaths(QWidget* parent, GList* paths); + +protected: + + virtual GAppInfo* getApp(GList* file_infos, FmMimeType* mime_type, GError** err); + virtual bool openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err); + virtual FmFileLauncherExecAction execFile(FmFileInfo* file); + virtual bool error(GAppLaunchContext* ctx, GError* err, FmPath* path); + virtual int ask(const char* msg, char* const* btn_labels, int default_btn); + +private: + static GAppInfo* _getApp(GList* file_infos, FmMimeType* mime_type, gpointer user_data, GError** err) { + return reinterpret_cast(user_data)->getApp(file_infos, mime_type, err); + } + static gboolean _openFolder(GAppLaunchContext* ctx, GList* folder_infos, gpointer user_data, GError** err) { + return reinterpret_cast(user_data)->openFolder(ctx, folder_infos, err); + } + static FmFileLauncherExecAction _execFile(FmFileInfo* file, gpointer user_data) { + return reinterpret_cast(user_data)->execFile(file); + } + static gboolean _error(GAppLaunchContext* ctx, GError* err, FmPath* file, gpointer user_data) { + return reinterpret_cast(user_data)->error(ctx, err, file); + } + static int _ask(const char* msg, char* const* btn_labels, int default_btn, gpointer user_data) { + return reinterpret_cast(user_data)->ask(msg, btn_labels, default_btn); + } + +private: + static FmFileLauncher funcs; +}; + +} + +#endif // FM_FILELAUNCHER_H diff --git a/libfm-qt/filemenu.cpp b/libfm-qt/filemenu.cpp new file mode 100644 index 0000000..9c8f5a5 --- /dev/null +++ b/libfm-qt/filemenu.cpp @@ -0,0 +1,370 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "filemenu.h" +#include "icontheme.h" +#include "filepropsdialog.h" +#include "utilities.h" +#include "fileoperation.h" +#include "filelauncher.h" +#include "appchooserdialog.h" +#ifdef CUSTOM_ACTIONS +#include +#endif +#include +#include +#include "filemenu_p.h" + +namespace Fm { + +FileMenu::FileMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd, QWidget* parent): + QMenu(parent), + fileLauncher_(NULL) { + createMenu(files, info, cwd); +} + +FileMenu::FileMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd, const QString& title, QWidget* parent): + QMenu(title, parent), + fileLauncher_(NULL), + unTrashAction_(NULL) { + createMenu(files, info, cwd); +} + +FileMenu::~FileMenu() { + if(files_) + fm_file_info_list_unref(files_); + if(info_) + fm_file_info_unref(info_); + if(cwd_) + fm_path_unref(cwd_); +} + +void FileMenu::createMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd) { + useTrash_ = true; + confirmDelete_ = true; + files_ = fm_file_info_list_ref(files); + info_ = info ? fm_file_info_ref(info) : NULL; + cwd_ = cwd ? fm_path_ref(cwd) : NULL; + + FmFileInfo* first = fm_file_info_list_peek_head(files); + FmMimeType* mime_type = fm_file_info_get_mime_type(first); + FmPath* path = fm_file_info_get_path(first); + // check if the files are of the same type + sameType_ = fm_file_info_list_is_same_type(files); + // check if the files are on the same filesystem + sameFilesystem_ = fm_file_info_list_is_same_fs(files); + // check if the files are all virtual + allVirtual_ = sameFilesystem_ && fm_path_is_virtual(path); + // check if the files are all in the trash can + allTrash_ = sameFilesystem_ && fm_path_is_trash(path); + + openAction_ = new QAction(QIcon::fromTheme("document-open"), tr("Open"), this); + connect(openAction_ , &QAction::triggered, this, &FileMenu::onOpenTriggered); + addAction(openAction_); + + openWithMenuAction_ = new QAction(tr("Open With..."), this); + addAction(openWithMenuAction_); + // create the "Open with..." sub menu + QMenu* menu = new QMenu(); + openWithMenuAction_->setMenu(menu); + + if(sameType_) { /* add specific menu items for this mime type */ + if(mime_type && !allVirtual_) { /* the file has a valid mime-type and its not virtual */ + GList* apps = g_app_info_get_all_for_type(fm_mime_type_get_type(mime_type)); + GList* l; + for(l=apps;l;l=l->next) { + GAppInfo* app = G_APP_INFO(l->data); + + // check if the command really exists + gchar * program_path = g_find_program_in_path(g_app_info_get_executable(app)); + if (!program_path) + continue; + g_free(program_path); + + // create a QAction for the application. + AppInfoAction* action = new AppInfoAction(app); + connect(action, &QAction::triggered, this, &FileMenu::onApplicationTriggered); + menu->addAction(action); + } + g_list_free(apps); /* don't unref GAppInfos now */ + } + } + menu->addSeparator(); + openWithAction_ = new QAction(tr("Other Applications"), this); + connect(openWithAction_ , &QAction::triggered, this, &FileMenu::onOpenWithTriggered); + menu->addAction(openWithAction_); + + separator1_ = addSeparator(); + + if(allTrash_) { // all selected files are in trash:/// + bool can_restore = true; + /* only immediate children of trash:/// can be restored. */ + for(GList* l = fm_file_info_list_peek_head_link(files_); l; l=l->next) { + FmPath *trash_path = fm_file_info_get_path(FM_FILE_INFO(l->data)); + if(!fm_path_get_parent(trash_path) || + !fm_path_is_trash_root(fm_path_get_parent(trash_path))) { + can_restore = false; + break; + } + } + if(can_restore) { + unTrashAction_ = new QAction(tr("&Restore"), this); + connect(unTrashAction_, &QAction::triggered, this, &FileMenu::onUnTrashTriggered); + addAction(unTrashAction_); + } + } + else { // ordinary files + cutAction_ = new QAction(QIcon::fromTheme("edit-cut"), tr("Cut"), this); + connect(cutAction_, &QAction::triggered, this, &FileMenu::onCutTriggered); + addAction(cutAction_); + + copyAction_ = new QAction(QIcon::fromTheme("edit-copy"), tr("Copy"), this); + connect(copyAction_, &QAction::triggered, this, &FileMenu::onCopyTriggered); + addAction(copyAction_); + + pasteAction_ = new QAction(QIcon::fromTheme("edit-paste"), tr("Paste"), this); + connect(pasteAction_, &QAction::triggered, this, &FileMenu::onPasteTriggered); + addAction(pasteAction_); + + deleteAction_ = new QAction(QIcon::fromTheme("edit-delete"), tr("&Move to Trash"), this); + connect(deleteAction_, &QAction::triggered, this, &FileMenu::onDeleteTriggered); + addAction(deleteAction_); + + renameAction_ = new QAction(tr("Rename"), this); + connect(renameAction_, &QAction::triggered, this, &FileMenu::onRenameTriggered); + addAction(renameAction_); + } + +#ifdef CUSTOM_ACTIONS + // DES-EMA custom actions integration + GList* files_list = fm_file_info_list_peek_head_link(files); + GList* items = fm_get_actions_for_files(files_list); + if(items) { + GList* l; + for(l=items; l; l=l->next) { + FmFileActionItem* item = FM_FILE_ACTION_ITEM(l->data); + addCustomActionItem(this, item); + } + } + g_list_foreach(items, (GFunc)fm_file_action_item_unref, NULL); + g_list_free(items); +#endif + // archiver integration + // FIXME: we need to modify upstream libfm to include some Qt-based archiver programs. + if(!allVirtual_) { + if(sameType_) { + FmArchiver* archiver = fm_archiver_get_default(); + if(archiver) { + if(fm_archiver_is_mime_type_supported(archiver, fm_mime_type_get_type(mime_type))) { + if(cwd_ && archiver->extract_to_cmd) { + QAction* action = new QAction(tr("Extract to..."), this); + connect(action, &QAction::triggered, this, &FileMenu::onExtract); + addAction(action); + } + if(archiver->extract_cmd) { + QAction* action = new QAction(tr("Extract Here"), this); + connect(action, &QAction::triggered, this, &FileMenu::onExtractHere); + addAction(action); + } + } + else { + QAction* action = new QAction(tr("Compress"), this); + connect(action, &QAction::triggered, this, &FileMenu::onCompress); + addAction(action); + } + } + } + } + + separator2_ = addSeparator(); + + propertiesAction_ = new QAction(QIcon::fromTheme("document-properties"), tr("Properties"), this); + connect(propertiesAction_, &QAction::triggered, this, &FileMenu::onFilePropertiesTriggered); + addAction(propertiesAction_); +} + +#ifdef CUSTOM_ACTIONS +void FileMenu::addCustomActionItem(QMenu* menu, FmFileActionItem* item) { + if(!item) { // separator + addSeparator(); + return; + } + + // this action is not for context menu + if(fm_file_action_item_is_action(item) && !(fm_file_action_item_get_target(item) & FM_FILE_ACTION_TARGET_CONTEXT)) + return; + + CustomAction* action = new CustomAction(item, menu); + menu->addAction(action); + if(fm_file_action_item_is_menu(item)) { + GList* subitems = fm_file_action_item_get_sub_items(item); + for(GList* l = subitems; l; l = l->next) { + FmFileActionItem* subitem = FM_FILE_ACTION_ITEM(l->data); + QMenu* submenu = new QMenu(menu); + addCustomActionItem(submenu, subitem); + action->setMenu(submenu); + } + } + else if(fm_file_action_item_is_action(item)) { + connect(action, &QAction::triggered, this, &FileMenu::onCustomActionTrigerred); + } +} +#endif + +void FileMenu::onOpenTriggered() { + if(fileLauncher_) { + fileLauncher_->launchFiles(NULL, files_); + } + else { // use the default launcher + Fm::FileLauncher launcher; + launcher.launchFiles(NULL, files_); + } +} + +void FileMenu::onOpenWithTriggered() { + AppChooserDialog dlg(NULL); + if(sameType_) { + dlg.setMimeType(fm_file_info_get_mime_type(info_)); + } + else { // we can only set the selected app as default if all files are of the same type + dlg.setCanSetDefault(false); + } + + if(execModelessDialog(&dlg) == QDialog::Accepted) { + GAppInfo* app = dlg.selectedApp(); + if(app) { + openFilesWithApp(app); + g_object_unref(app); + } + } +} + +void FileMenu::openFilesWithApp(GAppInfo* app) { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + GList* uris = NULL; + for(GList* l = fm_path_list_peek_head_link(paths); l; l = l->next) { + FmPath* path = FM_PATH(l->data); + char* uri = fm_path_to_uri(path); + uris = g_list_prepend(uris, uri); + } + fm_path_list_unref(paths); + fm_app_info_launch_uris(app, uris, NULL, NULL); + g_list_foreach(uris, (GFunc)g_free, NULL); + g_list_free(uris); +} + +void FileMenu::onApplicationTriggered() { + AppInfoAction* action = static_cast(sender()); + openFilesWithApp(action->appInfo()); +} + +#ifdef CUSTOM_ACTIONS +void FileMenu::onCustomActionTrigerred() { + CustomAction* action = static_cast(sender()); + FmFileActionItem* item = action->item(); + + GList* files = fm_file_info_list_peek_head_link(files_); + char* output = NULL; + /* g_debug("item: %s is activated, id:%s", fm_file_action_item_get_name(item), + fm_file_action_item_get_id(item)); */ + fm_file_action_item_launch(item, NULL, files, &output); + if(output) { + QMessageBox::information(this, tr("Output"), QString::fromUtf8(output)); + g_free(output); + } +} +#endif + +void FileMenu::onFilePropertiesTriggered() { + FilePropsDialog::showForFiles(files_); +} + +void FileMenu::onCopyTriggered() { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + Fm::copyFilesToClipboard(paths); + fm_path_list_unref(paths); +} + +void FileMenu::onCutTriggered() { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + Fm::cutFilesToClipboard(paths); + fm_path_list_unref(paths); +} + +void FileMenu::onDeleteTriggered() { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + if(useTrash_) + FileOperation::trashFiles(paths, confirmDelete_); + else + FileOperation::deleteFiles(paths, confirmDelete_); + fm_path_list_unref(paths); +} + +void FileMenu::onUnTrashTriggered() { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + FileOperation::unTrashFiles(paths); +} + +void FileMenu::onPasteTriggered() { + Fm::pasteFilesFromClipboard(cwd_); +} + +void FileMenu::onRenameTriggered() { + for(GList* l = fm_file_info_list_peek_head_link(files_); l; l = l->next) { + FmFileInfo* info = FM_FILE_INFO(l->data); + Fm::renameFile(info, NULL); + } +} + +void FileMenu::setUseTrash(bool trash) { + if(useTrash_ != trash) { + useTrash_ = trash; + deleteAction_->setText(useTrash_ ? tr("&Move to Trash") : tr("&Delete")); + } +} + +void FileMenu::onCompress() { + FmArchiver* archiver = fm_archiver_get_default(); + if(archiver) { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + fm_archiver_create_archive(archiver, NULL, paths); + fm_path_list_unref(paths); + } +} + +void FileMenu::onExtract() { + FmArchiver* archiver = fm_archiver_get_default(); + if(archiver) { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + fm_archiver_extract_archives(archiver, NULL, paths); + fm_path_list_unref(paths); + } +} + +void FileMenu::onExtractHere() { + FmArchiver* archiver = fm_archiver_get_default(); + if(archiver) { + FmPathList* paths = fm_path_list_new_from_file_info_list(files_); + fm_archiver_extract_archives_to(archiver, NULL, paths, cwd_); + fm_path_list_unref(paths); + } +} + +} // namespace Fm diff --git a/libfm-qt/filemenu.h b/libfm-qt/filemenu.h new file mode 100644 index 0000000..c8ec6d7 --- /dev/null +++ b/libfm-qt/filemenu.h @@ -0,0 +1,198 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_FILEMENU_H +#define FM_FILEMENU_H + +#include "libfmqtglobals.h" +#include +#include +#include + +class QAction; + +struct _FmFileActionItem; + +namespace Fm { + +class FileLauncher; + +class LIBFM_QT_API FileMenu : public QMenu { +Q_OBJECT + +public: + explicit FileMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd, QWidget* parent = 0); + explicit FileMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd, const QString& title, QWidget* parent = 0); + ~FileMenu(); + + bool useTrash() { + return useTrash_; + } + + void setUseTrash(bool trash); + + bool confirmDelete() { + return confirmDelete_; + } + + void setConfirmDelete(bool confirm) { + confirmDelete_ = confirm; + } + + QAction* openAction() { + return openAction_; + } + + QAction* openWithMenuAction() { + return openWithMenuAction_; + } + + QAction* openWithAction() { + return openWithAction_; + } + + QAction* separator1() { + return separator1_; + } + + QAction* cutAction() { + return cutAction_; + } + + QAction* copyAction() { + return copyAction_; + } + + QAction* pasteAction() { + return pasteAction_; + } + + QAction* deleteAction() { + return deleteAction_; + } + + QAction* unTrashAction() { + return unTrashAction_; + } + + QAction* renameAction() { + return renameAction_; + } + + QAction* separator2() { + return separator2_; + } + + QAction* propertiesAction() { + return propertiesAction_; + } + + FmFileInfoList* files() { + return files_; + } + + FmFileInfo* firstFile() { + return info_; + } + + FmPath* cwd() { + return cwd_; + } + + void setFileLauncher(FileLauncher* launcher) { + fileLauncher_ = launcher; + } + + FileLauncher* fileLauncher() { + return fileLauncher_; + } + + bool sameType() const { + return sameType_; + } + + bool sameFilesystem() const { + return sameFilesystem_; + } + + bool allVirtual() const { + return allVirtual_; + } + + bool allTrash() const { + return allTrash_; + } + +protected: + void createMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd); +#ifdef CUSTOM_ACTIONS + void addCustomActionItem(QMenu* menu, struct _FmFileActionItem* item); +#endif + void openFilesWithApp(GAppInfo* app); + +protected Q_SLOTS: + void onOpenTriggered(); + void onOpenWithTriggered(); + void onFilePropertiesTriggered(); + void onApplicationTriggered(); +#ifdef CUSTOM_ACTIONS + void onCustomActionTrigerred(); +#endif + void onCompress(); + void onExtract(); + void onExtractHere(); + + void onCutTriggered(); + void onCopyTriggered(); + void onPasteTriggered(); + void onRenameTriggered(); + void onDeleteTriggered(); + void onUnTrashTriggered(); + +private: + FmFileInfoList* files_; + FmFileInfo* info_; + FmPath* cwd_; + bool useTrash_; + bool confirmDelete_; + bool sameType_; + bool sameFilesystem_; + bool allVirtual_; + bool allTrash_; + + QAction* openAction_; + QAction* openWithMenuAction_; + QAction* openWithAction_; + QAction* separator1_; + QAction* cutAction_; + QAction* copyAction_; + QAction* pasteAction_; + QAction* deleteAction_; + QAction* unTrashAction_; + QAction* renameAction_; + QAction* separator2_; + QAction* propertiesAction_; + + FileLauncher* fileLauncher_; +}; + +} + +#endif // FM_FILEMENU_H diff --git a/libfm-qt/filemenu_p.h b/libfm-qt/filemenu_p.h new file mode 100644 index 0000000..17e0524 --- /dev/null +++ b/libfm-qt/filemenu_p.h @@ -0,0 +1,84 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef FM_FILEMENU_P_H +#define FM_FILEMENU_P_H + +#include "icontheme.h" +#ifdef CUSTOM_ACTIONS +#include +#endif +#include + +namespace Fm { + +class AppInfoAction : public QAction { + Q_OBJECT +public: + explicit AppInfoAction(GAppInfo* app, QObject* parent = 0): + QAction(QString::fromUtf8(g_app_info_get_name(app)), parent), + appInfo_(G_APP_INFO(g_object_ref(app))) { + setToolTip(QString::fromUtf8(g_app_info_get_description(app))); + GIcon* gicon = g_app_info_get_icon(app); + QIcon icon = IconTheme::icon(gicon); + setIcon(icon); + } + + virtual ~AppInfoAction() { + if(appInfo_) + g_object_unref(appInfo_); + } + + GAppInfo* appInfo() const { + return appInfo_; + } + +private: + GAppInfo* appInfo_; +}; + +#ifdef CUSTOM_ACTIONS +class CustomAction : public QAction { + Q_OBJECT +public: + explicit CustomAction(FmFileActionItem* item, QObject* parent = NULL): + QAction(QString::fromUtf8(fm_file_action_item_get_name(item)), parent), + item_(reinterpret_cast(fm_file_action_item_ref(item))) { + const char* icon_name = fm_file_action_item_get_icon(item); + if(icon_name) + setIcon(QIcon::fromTheme(icon_name)); + } + + virtual ~CustomAction() { + fm_file_action_item_unref(item_); + } + + FmFileActionItem* item() { + return item_; + } + +private: + FmFileActionItem* item_; +}; + +#endif + +} // namespace Fm + +#endif diff --git a/libfm-qt/fileoperation.cpp b/libfm-qt/fileoperation.cpp new file mode 100644 index 0000000..101a5dd --- /dev/null +++ b/libfm-qt/fileoperation.cpp @@ -0,0 +1,303 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "fileoperation.h" +#include "fileoperationdialog.h" +#include +#include +#include +#include + +using namespace Fm; + +#define SHOW_DLG_DELAY 1000 + +FileOperation::FileOperation(Type type, FmPathList* srcFiles, QObject* parent): + QObject(parent), + dlg(NULL), + destPath(NULL), + srcPaths(fm_path_list_ref(srcFiles)), + uiTimer(NULL), + elapsedTimer_(NULL), + lastElapsed_(0), + updateRemainingTime_(true), + autoDestroy_(true), + job_(fm_file_ops_job_new((FmFileOpType)type, srcFiles)) { + + g_signal_connect(job_, "ask", G_CALLBACK(onFileOpsJobAsk), this); + g_signal_connect(job_, "ask-rename", G_CALLBACK(onFileOpsJobAskRename), this); + g_signal_connect(job_, "error", G_CALLBACK(onFileOpsJobError), this); + g_signal_connect(job_, "prepared", G_CALLBACK(onFileOpsJobPrepared), this); + g_signal_connect(job_, "cur-file", G_CALLBACK(onFileOpsJobCurFile), this); + g_signal_connect(job_, "percent", G_CALLBACK(onFileOpsJobPercent), this); + g_signal_connect(job_, "finished", G_CALLBACK(onFileOpsJobFinished), this); + g_signal_connect(job_, "cancelled", G_CALLBACK(onFileOpsJobCancelled), this); +} + +void FileOperation::disconnectJob() { + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobAsk), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobAskRename), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobError), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobPrepared), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobCurFile), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobPercent), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobFinished), this); + g_signal_handlers_disconnect_by_func(job_, (gpointer)G_CALLBACK(onFileOpsJobCancelled), this); +} + +FileOperation::~FileOperation() { + if(uiTimer) { + uiTimer->stop(); + delete uiTimer; + uiTimer = NULL; + } + if(elapsedTimer_) { + delete elapsedTimer_; + elapsedTimer_ = NULL; + } + + if(job_) { + disconnectJob(); + g_object_unref(job_); + } + + if(srcPaths) + fm_path_list_unref(srcPaths); + + if(destPath) + fm_path_unref(destPath); +} + +bool FileOperation::run() { + // run the job + uiTimer = new QTimer(); + uiTimer->start(SHOW_DLG_DELAY); + connect(uiTimer, &QTimer::timeout, this, &FileOperation::onUiTimeout); + + return fm_job_run_async(FM_JOB(job_)); +} + +void FileOperation::onUiTimeout() { + if(dlg) { + dlg->setCurFile(curFile); + // estimate remaining time based on past history + // FIXME: avoid directly access data member of FmFileOpsJob + if(Q_LIKELY(job_->percent > 0 && updateRemainingTime_)) { + gint64 remaining = elapsedTime() * ((double(100 - job_->percent) / job_->percent) / 1000); + dlg->setRemainingTime(remaining); + } + // this timeout slot is called every 0.5 second. + // by adding this flag, we can update remaining time every 1 second. + updateRemainingTime_ = !updateRemainingTime_; + } + else{ + showDialog(); + } +} + +void FileOperation::showDialog() { + if(!dlg) { + dlg = new FileOperationDialog(this); + dlg->setSourceFiles(srcPaths); + + if(destPath) + dlg->setDestPath(destPath); + + if(curFile.isEmpty()) { + dlg->setPrepared(); + dlg->setCurFile(curFile); + } + uiTimer->setInterval(500); // change the interval of the timer + // now the timer is used to update current file display + dlg->show(); + } +} + +gint FileOperation::onFileOpsJobAsk(FmFileOpsJob* job, const char* question, char*const* options, FileOperation* pThis) { + pThis->pauseElapsedTimer(); + pThis->showDialog(); + int ret = pThis->dlg->ask(QString::fromUtf8(question), options); + pThis->resumeElapsedTimer(); + return ret; +} + +gint FileOperation::onFileOpsJobAskRename(FmFileOpsJob* job, FmFileInfo* src, FmFileInfo* dest, char** new_name, FileOperation* pThis) { + pThis->pauseElapsedTimer(); + pThis->showDialog(); + QString newName; + int ret = pThis->dlg->askRename(src, dest, newName); + if(!newName.isEmpty()) { + *new_name = g_strdup(newName.toUtf8().constData()); + } + pThis->resumeElapsedTimer(); + return ret; +} + +void FileOperation::onFileOpsJobCancelled(FmFileOpsJob* job, FileOperation* pThis) { + qDebug("file operation is cancelled!"); +} + +void FileOperation::onFileOpsJobCurFile(FmFileOpsJob* job, const char* cur_file, FileOperation* pThis) { + pThis->curFile = QString::fromUtf8(cur_file); + + // We update the current file name in a timeout slot because drawing a string + // in the UI is expansive. Updating the label text too often cause + // significant impact on performance. + // if(pThis->dlg) + // pThis->dlg->setCurFile(pThis->curFile); +} + +FmJobErrorAction FileOperation::onFileOpsJobError(FmFileOpsJob* job, GError* err, FmJobErrorSeverity severity, FileOperation* pThis) { + pThis->pauseElapsedTimer(); + pThis->showDialog(); + FmJobErrorAction act = pThis->dlg->error(err, severity); + pThis->resumeElapsedTimer(); + return act; +} + +void FileOperation::onFileOpsJobFinished(FmFileOpsJob* job, FileOperation* pThis) { + pThis->handleFinish(); +} + +void FileOperation::onFileOpsJobPercent(FmFileOpsJob* job, guint percent, FileOperation* pThis) { + if(pThis->dlg) { + pThis->dlg->setPercent(percent); + } +} + +void FileOperation::onFileOpsJobPrepared(FmFileOpsJob* job, FileOperation* pThis) { + if(!pThis->elapsedTimer_) { + pThis->elapsedTimer_ = new QElapsedTimer(); + pThis->elapsedTimer_->start(); + } + if(pThis->dlg) { + pThis->dlg->setPrepared(); + } +} + +void FileOperation::handleFinish() { + disconnectJob(); + + if(uiTimer) { + uiTimer->stop(); + delete uiTimer; + uiTimer = NULL; + } + + if(dlg) { + dlg->done(QDialog::Accepted); + delete dlg; + dlg = NULL; + } + Q_EMIT finished(); + + /* sepcial handling for trash + * FIXME: need to refactor this to use a more elegant way later. */ + if(job_->type == FM_FILE_OP_TRASH) { /* FIXME: direct access to job struct! */ + FmPathList* unable_to_trash = static_cast(g_object_get_data(G_OBJECT(job_), "trash-unsupported")); + /* some files cannot be trashed because underlying filesystems don't support it. */ + if(unable_to_trash) { /* delete them instead */ + /* FIXME: parent window might be already destroyed! */ + QWidget* parent = NULL; // FIXME: currently, parent window is not set + if(QMessageBox::question(parent, tr("Error"), + tr("Some files cannot be moved to trash can because " + "the underlying file systems don't support this operation.\n" + "Do you want to delete them instead?")) == QMessageBox::Yes) { + deleteFiles(unable_to_trash, false); + } + } + } + g_object_unref(job_); + job_ = NULL; + + if(autoDestroy_) + delete this; +} + +// static +FileOperation* FileOperation::copyFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent) { + FileOperation* op = new FileOperation(FileOperation::Copy, srcFiles); + op->setDestination(dest); + op->run(); + return op; +} + +// static +FileOperation* FileOperation::moveFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent) { + FileOperation* op = new FileOperation(FileOperation::Move, srcFiles); + op->setDestination(dest); + op->run(); + return op; +} + +//static +FileOperation* FileOperation::symlinkFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent) { + FileOperation* op = new FileOperation(FileOperation::Link, srcFiles); + op->setDestination(dest); + op->run(); + return op; +} + +//static +FileOperation* FileOperation::deleteFiles(FmPathList* srcFiles, bool prompt, QWidget* parent) { + if(prompt) { + int result = QMessageBox::warning(parent, tr("Confirm"), + tr("Do you want to delete the selected files?"), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if(result != QMessageBox::Yes) + return NULL; + } + + FileOperation* op = new FileOperation(FileOperation::Delete, srcFiles); + op->run(); + return op; +} + +//static +FileOperation* FileOperation::trashFiles(FmPathList* srcFiles, bool prompt, QWidget* parent) { + if(prompt) { + int result = QMessageBox::warning(parent, tr("Confirm"), + tr("Do you want to move the selected files to trash can?"), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if(result != QMessageBox::Yes) + return NULL; + } + + FileOperation* op = new FileOperation(FileOperation::Trash, srcFiles); + op->run(); + return op; +} + +//static +FileOperation* FileOperation::unTrashFiles(FmPathList* srcFiles, QWidget* parent) { + FileOperation* op = new FileOperation(FileOperation::UnTrash, srcFiles); + op->run(); + return op; +} + +// static +FileOperation* FileOperation::changeAttrFiles(FmPathList* srcFiles, QWidget* parent) { + //TODO + FileOperation* op = new FileOperation(FileOperation::ChangeAttr, srcFiles); + op->run(); + return op; +} diff --git a/libfm-qt/fileoperation.h b/libfm-qt/fileoperation.h new file mode 100644 index 0000000..9d5c912 --- /dev/null +++ b/libfm-qt/fileoperation.h @@ -0,0 +1,164 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FILEOPERATION_H +#define FM_FILEOPERATION_H + +#include "libfmqtglobals.h" +#include +#include +#include + +class QTimer; + +namespace Fm { + +class FileOperationDialog; + +class LIBFM_QT_API FileOperation : public QObject { +Q_OBJECT +public: + enum Type { + Copy = FM_FILE_OP_COPY, + Move = FM_FILE_OP_MOVE, + Link = FM_FILE_OP_LINK, + Delete = FM_FILE_OP_DELETE, + Trash = FM_FILE_OP_TRASH, + UnTrash = FM_FILE_OP_UNTRASH, + ChangeAttr = FM_FILE_OP_CHANGE_ATTR + }; + +public: + explicit FileOperation(Type type, FmPathList* srcFiles, QObject* parent = 0); + virtual ~FileOperation(); + + void setDestination(FmPath* dest) { + destPath = fm_path_ref(dest); + fm_file_ops_job_set_dest(job_, dest); + } + + void setChmod(mode_t newMode, mode_t newModeMask) { + fm_file_ops_job_set_chmod(job_, newMode, newModeMask); + } + + void setChown(gint uid, gint gid) { + fm_file_ops_job_set_chown(job_, uid, gid); + } + + // This only work for change attr jobs. + void setRecursiveChattr(bool recursive) { + fm_file_ops_job_set_recursive(job_, (gboolean)recursive); + } + + bool run(); + + void cancel() { + if(job_) + fm_job_cancel(FM_JOB(job_)); + } + + bool isRunning() const { + return job_ ? fm_job_is_running(FM_JOB(job_)) : false; + } + + bool isCancelled() const { + return job_ ? fm_job_is_cancelled(FM_JOB(job_)) : false; + } + + FmFileOpsJob* job() { + return job_; + } + + bool autoDestroy() { + return autoDestroy_; + } + void setAutoDestroy(bool destroy = true) { + autoDestroy_ = destroy; + } + + Type type() { + return (Type)job_->type; + } + + // convinient static functions + static FileOperation* copyFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent = 0); + static FileOperation* moveFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent = 0); + static FileOperation* symlinkFiles(FmPathList* srcFiles, FmPath* dest, QWidget* parent = 0); + static FileOperation* deleteFiles(FmPathList* srcFiles, bool promp = true, QWidget* parent = 0); + static FileOperation* trashFiles(FmPathList* srcFiles, bool promp = true, QWidget* parent = 0); + static FileOperation* unTrashFiles(FmPathList* srcFiles, QWidget* parent = 0); + static FileOperation* changeAttrFiles(FmPathList* srcFiles, QWidget* parent = 0); + +Q_SIGNALS: + void finished(); + +private: + static gint onFileOpsJobAsk(FmFileOpsJob* job, const char* question, char* const* options, FileOperation* pThis); + static gint onFileOpsJobAskRename(FmFileOpsJob* job, FmFileInfo* src, FmFileInfo* dest, char** new_name, FileOperation* pThis); + static FmJobErrorAction onFileOpsJobError(FmFileOpsJob* job, GError* err, FmJobErrorSeverity severity, FileOperation* pThis); + static void onFileOpsJobPrepared(FmFileOpsJob* job, FileOperation* pThis); + static void onFileOpsJobCurFile(FmFileOpsJob* job, const char* cur_file, FileOperation* pThis); + static void onFileOpsJobPercent(FmFileOpsJob* job, guint percent, FileOperation* pThis); + static void onFileOpsJobFinished(FmFileOpsJob* job, FileOperation* pThis); + static void onFileOpsJobCancelled(FmFileOpsJob* job, FileOperation* pThis); + + void handleFinish(); + void disconnectJob(); + void showDialog(); + + void pauseElapsedTimer() { + if(Q_LIKELY(elapsedTimer_ != NULL)) { + lastElapsed_ += elapsedTimer_->elapsed(); + elapsedTimer_->invalidate(); + } + } + + void resumeElapsedTimer() { + if(Q_LIKELY(elapsedTimer_ != NULL)) { + elapsedTimer_->start(); + } + } + + qint64 elapsedTime() { + if(Q_LIKELY(elapsedTimer_ != NULL)) { + return lastElapsed_ + elapsedTimer_->elapsed(); + } + return 0; + } + +private Q_SLOTS: + void onUiTimeout(); + +private: + FmFileOpsJob* job_; + FileOperationDialog* dlg; + FmPath* destPath; + FmPathList* srcPaths; + QTimer* uiTimer; + QElapsedTimer* elapsedTimer_; + qint64 lastElapsed_; + bool updateRemainingTime_; + QString curFile; + bool autoDestroy_; +}; + +} + +#endif // FM_FILEOPERATION_H diff --git a/libfm-qt/fileoperationdialog.cpp b/libfm-qt/fileoperationdialog.cpp new file mode 100644 index 0000000..6511916 --- /dev/null +++ b/libfm-qt/fileoperationdialog.cpp @@ -0,0 +1,176 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "fileoperationdialog.h" +#include "fileoperation.h" +#include "renamedialog.h" +#include +#include "ui_file-operation-dialog.h" + +using namespace Fm; + +FileOperationDialog::FileOperationDialog(FileOperation* _operation): + QDialog(NULL), + operation(_operation), + defaultOption(-1) { + + ui = new Ui::FileOperationDialog(); + ui->setupUi(this); + + QString title; + QString message; + switch(_operation->type()) { + case FM_FILE_OP_MOVE: + title = tr("Move files"); + message = tr("Moving the following files to destination folder:"); + break; + case FM_FILE_OP_COPY: + title = tr("Copy Files"); + message = tr("Copying the following files to destination folder:"); + break; + case FM_FILE_OP_TRASH: + title = tr("Trash Files"); + message = tr("Moving the following files to trash can:"); + break; + case FM_FILE_OP_DELETE: + title = tr("Delete Files"); + message = tr("Deleting the following files"); + ui->dest->hide(); + ui->destLabel->hide(); + break; + case FM_FILE_OP_LINK: + title = tr("Create Symlinks"); + message = tr("Creating symlinks for the following files:"); + break; + case FM_FILE_OP_CHANGE_ATTR: + title = tr("Change Attributes"); + message = tr("Changing attributes of the following files:"); + ui->dest->hide(); + ui->destLabel->hide(); + break; + case FM_FILE_OP_UNTRASH: + title = tr("Restore Trashed Files"); + message = tr("Restoring the following files from trash can:"); + ui->dest->hide(); + ui->destLabel->hide(); + break; + } + ui->message->setText(message); + setWindowTitle(title); +} + + +FileOperationDialog::~FileOperationDialog() { + delete ui; +} + +void FileOperationDialog::setDestPath(FmPath* dest) { + char* pathStr = fm_path_display_name(dest, false); + ui->dest->setText(QString::fromUtf8(pathStr)); + g_free(pathStr); +} + +void FileOperationDialog::setSourceFiles(FmPathList* srcFiles) { + GList* l; + for(l = fm_path_list_peek_head_link(srcFiles); l; l = l->next) { + FmPath* path = FM_PATH(l->data); + char* pathStr = fm_path_display_name(path, false); + ui->sourceFiles->addItem(QString::fromUtf8(pathStr)); + g_free(pathStr); + } +} + +int FileOperationDialog::ask(QString question, char*const* options) { + // TODO: implement FileOperationDialog::ask() + return 0; +} + +int FileOperationDialog::askRename(FmFileInfo* src, FmFileInfo* dest, QString& new_name) { + int ret; + if(defaultOption == -1) { // default action is not set, ask the user + RenameDialog dlg(src, dest, this); + dlg.exec(); + switch(dlg.action()) { + case RenameDialog::ActionOverwrite: + ret = FM_FILE_OP_OVERWRITE; + if(dlg.applyToAll()) + defaultOption = ret; + break; + case RenameDialog::ActionRename: + ret = FM_FILE_OP_RENAME; + new_name = dlg.newName(); + break; + case RenameDialog::ActionIgnore: + ret = FM_FILE_OP_SKIP; + if(dlg.applyToAll()) + defaultOption = ret; + break; + default: + ret = FM_FILE_OP_CANCEL; + break; + } + } + else + ret = defaultOption; + return ret; +} + +FmJobErrorAction FileOperationDialog::error(GError* err, FmJobErrorSeverity severity) { + if(severity >= FM_JOB_ERROR_MODERATE) { + QMessageBox::critical(this, tr("Error"), QString::fromUtf8(err->message)); + if(severity == FM_JOB_ERROR_CRITICAL) + return FM_JOB_ABORT; + } + return FM_JOB_CONTINUE; +} + +void FileOperationDialog::setCurFile(QString cur_file) { + ui->curFile->setText(cur_file); +} + +void FileOperationDialog::setPercent(unsigned int percent) { + ui->progressBar->setValue(percent); +} + +void FileOperationDialog::setRemainingTime(unsigned int sec) { + unsigned int min = 0; + unsigned int hr = 0; + if(sec > 60) { + min = sec / 60; + sec %= 60; + if(min > 60) { + hr = min / 60; + min %= 60; + } + } + ui->timeRemaining->setText(QString("%1:%2:%3") + .arg(hr, 2, 10, QChar('0')) + .arg(min, 2, 10, QChar('0')) + .arg(sec, 2, 10, QChar('0'))); +} + +void FileOperationDialog::setPrepared() { +} + +void FileOperationDialog::reject() { + operation->cancel(); + QDialog::reject(); +} + diff --git a/libfm-qt/fileoperationdialog.h b/libfm-qt/fileoperationdialog.h new file mode 100644 index 0000000..a31af23 --- /dev/null +++ b/libfm-qt/fileoperationdialog.h @@ -0,0 +1,63 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FILEOPERATIONDIALOG_H +#define FM_FILEOPERATIONDIALOG_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Ui { + class FileOperationDialog; +}; + +namespace Fm { + +class FileOperation; + +class LIBFM_QT_API FileOperationDialog : public QDialog { +Q_OBJECT +public: + explicit FileOperationDialog(FileOperation* _operation); + virtual ~FileOperationDialog(); + + void setSourceFiles(FmPathList* srcFiles); + void setDestPath(FmPath* dest); + + int ask(QString question, char* const* options); + int askRename(FmFileInfo* src, FmFileInfo* dest, QString& new_name); + FmJobErrorAction error(GError* err, FmJobErrorSeverity severity); + void setPrepared(); + void setCurFile(QString cur_file); + void setPercent(unsigned int percent); + void setRemainingTime(unsigned int sec); + + virtual void reject(); + +private: + Ui::FileOperationDialog* ui; + FileOperation* operation; + int defaultOption; +}; + +} + +#endif // FM_FILEOPERATIONDIALOG_H diff --git a/libfm-qt/filepropsdialog.cpp b/libfm-qt/filepropsdialog.cpp new file mode 100644 index 0000000..273e3e5 --- /dev/null +++ b/libfm-qt/filepropsdialog.cpp @@ -0,0 +1,441 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "filepropsdialog.h" +#include "ui_file-props.h" +#include "icontheme.h" +#include "utilities.h" +#include "fileoperation.h" +#include +#include +#include +#include +#include +#include + +#define DIFFERENT_UIDS ((uid)-1) +#define DIFFERENT_GIDS ((gid)-1) +#define DIFFERENT_PERMS ((mode_t)-1) + +using namespace Fm; + +enum { + ACCESS_NO_CHANGE = 0, + ACCESS_READ_ONLY, + ACCESS_READ_WRITE, + ACCESS_FORBID +}; + +FilePropsDialog::FilePropsDialog(FmFileInfoList* files, QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f), + fileInfos_(fm_file_info_list_ref(files)), + singleType(fm_file_info_list_is_same_type(files)), + singleFile(fm_file_info_list_get_length(files) == 1 ? true:false), + fileInfo(fm_file_info_list_peek_head(files)), + mimeType(NULL) { + + setAttribute(Qt::WA_DeleteOnClose); + + ui = new Ui::FilePropsDialog(); + ui->setupUi(this); + + if(singleType) { + mimeType = fm_mime_type_ref(fm_file_info_get_mime_type(fileInfo)); + } + + FmPathList* paths = fm_path_list_new_from_file_info_list(files); + deepCountJob = fm_deep_count_job_new(paths, FM_DC_JOB_DEFAULT); + fm_path_list_unref(paths); + + initGeneralPage(); + initPermissionsPage(); +} + +FilePropsDialog::~FilePropsDialog() { + delete ui; + + if(fileInfos_) + fm_file_info_list_unref(fileInfos_); + if(deepCountJob) + g_object_unref(deepCountJob); + if(fileSizeTimer) { + fileSizeTimer->stop(); + delete fileSizeTimer; + fileSizeTimer = NULL; + } +} + +void FilePropsDialog::initApplications() { + if(singleType && mimeType && !fm_file_info_is_dir(fileInfo)) { + ui->openWith->setMimeType(mimeType); + } + else { + ui->openWith->hide(); + ui->openWithLabel->hide(); + } +} + +void FilePropsDialog::initPermissionsPage() { + // ownership handling + // get owner/group and mode of the first file in the list + uid = fm_file_info_get_uid(fileInfo); + gid = fm_file_info_get_gid(fileInfo); + mode_t mode = fm_file_info_get_mode(fileInfo); + ownerPerm = (mode & (S_IRUSR|S_IWUSR|S_IXUSR)); + groupPerm = (mode & (S_IRGRP|S_IWGRP|S_IXGRP)); + otherPerm = (mode & (S_IROTH|S_IWOTH|S_IXOTH)); + execPerm = (mode & (S_IXUSR|S_IXGRP|S_IXOTH)); + allNative = fm_file_info_is_native(fileInfo); + hasDir = S_ISDIR(mode); + + // check if all selected files belongs to the same owner/group or have the same mode + // at the same time, check if all files are on native unix filesystems + GList* l; + for(l = fm_file_info_list_peek_head_link(fileInfos_)->next; l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + if(allNative && !fm_file_info_is_native(fi)) + allNative = false; // not all of the files are native + + mode_t fi_mode = fm_file_info_get_mode(fi); + if(S_ISDIR(fi_mode)) + hasDir = true; // the files list contains dir(s) + + if(uid != DIFFERENT_UIDS && uid != fm_file_info_get_uid(fi)) + uid = DIFFERENT_UIDS; // not all files have the same owner + if(gid != DIFFERENT_GIDS && gid != fm_file_info_get_gid(fi)) + gid = DIFFERENT_GIDS; // not all files have the same owner group + + if(ownerPerm != DIFFERENT_PERMS && ownerPerm != (fi_mode & (S_IRUSR|S_IWUSR|S_IXUSR))) + ownerPerm = DIFFERENT_PERMS; // not all files have the same permission for owner + if(groupPerm != DIFFERENT_PERMS && groupPerm != (fi_mode & (S_IRGRP|S_IWGRP|S_IXGRP))) + groupPerm = DIFFERENT_PERMS; // not all files have the same permission for grop + if(otherPerm != DIFFERENT_PERMS && otherPerm != (fi_mode & (S_IROTH|S_IWOTH|S_IXOTH))) + otherPerm = DIFFERENT_PERMS; // not all files have the same permission for other + if(execPerm != DIFFERENT_PERMS && execPerm != (fi_mode & (S_IXUSR|S_IXGRP|S_IXOTH))) + execPerm = DIFFERENT_PERMS; // not all files have the same executable permission + } + + // init owner/group + initOwner(); + + // if all files are of the same type, and some of them are dirs => all of the items are dirs + // rwx values have different meanings for dirs + // Let's make it clear for the users + // init combo boxes for file permissions here + QStringList comboItems; + comboItems.append("---"); // no change + if(singleType && hasDir) { // all files are dirs + comboItems.append(tr("View folder content")); + comboItems.append(tr("View and modify folder content")); + ui->executable->hide(); + } + else { //not all of the files are dirs + comboItems.append(tr("Read")); + comboItems.append(tr("Read and write")); + } + comboItems.append(tr("Forbidden")); + QStringListModel* comboModel = new QStringListModel(comboItems, this); + ui->ownerPerm->setModel(comboModel); + ui->groupPerm->setModel(comboModel); + ui->otherPerm->setModel(comboModel); + + // owner + ownerPermSel = ACCESS_NO_CHANGE; + if(ownerPerm != DIFFERENT_PERMS) { // permissions for owner are the same among all files + if(ownerPerm & S_IRUSR) { // can read + if(ownerPerm & S_IWUSR) // can write + ownerPermSel = ACCESS_READ_WRITE; + else + ownerPermSel = ACCESS_READ_ONLY; + } + else { + if((ownerPerm & S_IWUSR) == 0) // cannot read or write + ownerPermSel = ACCESS_FORBID; + } + } + ui->ownerPerm->setCurrentIndex(ownerPermSel); + + // owner and group + groupPermSel = ACCESS_NO_CHANGE; + if(groupPerm != DIFFERENT_PERMS) { // permissions for owner are the same among all files + if(groupPerm & S_IRGRP) { // can read + if(groupPerm & S_IWGRP) // can write + groupPermSel = ACCESS_READ_WRITE; + else + groupPermSel = ACCESS_READ_ONLY; + } + else { + if((groupPerm & S_IWGRP) == 0) // cannot read or write + groupPermSel = ACCESS_FORBID; + } + } + ui->groupPerm->setCurrentIndex(groupPermSel); + + // other + otherPermSel = ACCESS_NO_CHANGE; + if(otherPerm != DIFFERENT_PERMS) { // permissions for owner are the same among all files + if(otherPerm & S_IROTH) { // can read + if(otherPerm & S_IWOTH) // can write + otherPermSel = ACCESS_READ_WRITE; + else + otherPermSel = ACCESS_READ_ONLY; + } + else { + if((otherPerm & S_IWOTH) == 0) // cannot read or write + otherPermSel = ACCESS_FORBID; + } + + } + ui->otherPerm->setCurrentIndex(otherPermSel); + + // set the checkbox to partially checked state + // when owner, group, and other have different executable flags set. + // some of them have exec, and others do not have. + execCheckState = Qt::PartiallyChecked; + if(execPerm != DIFFERENT_PERMS) { // if all files have the same executable permission + // check if the files are all executable + if((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == (S_IXUSR|S_IXGRP|S_IXOTH)) { + // owner, group, and other all have exec permission. + ui->executable->setTristate(false); + execCheckState = Qt::Checked; + } + else if((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { + // owner, group, and other all have no exec permission + ui->executable->setTristate(false); + execCheckState = Qt::Unchecked; + } + } + ui->executable->setCheckState(execCheckState); +} + +void FilePropsDialog::initGeneralPage() { + // update UI + if(singleType) { // all files are of the same mime-type + FmIcon* icon = NULL; + // FIXME: handle custom icons for some files + // FIXME: display special property pages for special files or + // some specified mime-types. + if(singleFile) { // only one file is selected. + icon = fm_file_info_get_icon(fileInfo); + } + if(mimeType) { + if(!icon) // get an icon from mime type if needed + icon = fm_mime_type_get_icon(mimeType); + ui->fileType->setText(QString::fromUtf8(fm_mime_type_get_desc(mimeType))); + ui->mimeType->setText(QString::fromUtf8(fm_mime_type_get_type(mimeType))); + } + if(icon) { + ui->iconButton->setIcon(IconTheme::icon(icon)); + } + + if(singleFile && fm_file_info_is_symlink(fileInfo)) { + ui->target->setText(QString::fromUtf8(fm_file_info_get_target(fileInfo))); + } + else { + ui->target->hide(); + ui->targetLabel->hide(); + } + } // end if(singleType) + else { // not singleType, multiple files are selected at the same time + ui->fileType->setText(tr("Files of different types")); + ui->target->hide(); + ui->targetLabel->hide(); + } + + // FIXME: check if all files has the same parent dir, mtime, or atime + if(singleFile) { // only one file is selected + FmPath* parent_path = fm_path_get_parent(fm_file_info_get_path(fileInfo)); + char* parent_str = parent_path ? fm_path_display_name(parent_path, true) : NULL; + + ui->fileName->setText(QString::fromUtf8(fm_file_info_get_disp_name(fileInfo))); + if(parent_str) { + ui->location->setText(QString::fromUtf8(parent_str)); + g_free(parent_str); + } + else + ui->location->clear(); + + ui->lastModified->setText(QString::fromUtf8(fm_file_info_get_disp_mtime(fileInfo))); + + // FIXME: need to encapsulate this in an libfm API. + time_t atime; + struct tm tm; + atime = fm_file_info_get_atime(fileInfo); + localtime_r(&atime, &tm); + char buf[128]; + strftime(buf, sizeof(buf), "%x %R", &tm); + ui->lastAccessed->setText(QString::fromUtf8(buf)); + } + else { + ui->fileName->setText(tr("Multiple Files")); + ui->fileName->setEnabled(false); + } + + initApplications(); // init applications combo box + + // calculate total file sizes + fileSizeTimer = new QTimer(this); + connect(fileSizeTimer, &QTimer::timeout, this, &FilePropsDialog::onFileSizeTimerTimeout); + fileSizeTimer->start(600); + g_signal_connect(deepCountJob, "finished", G_CALLBACK(onDeepCountJobFinished), this); + fm_job_run_async(FM_JOB(deepCountJob)); +} + +/*static */ void FilePropsDialog::onDeepCountJobFinished(FmDeepCountJob* job, FilePropsDialog* pThis) { + + pThis->onFileSizeTimerTimeout(); // update file size display + + // free the job + g_object_unref(pThis->deepCountJob); + pThis->deepCountJob = NULL; + + // stop the timer + if(pThis->fileSizeTimer) { + pThis->fileSizeTimer->stop(); + delete pThis->fileSizeTimer; + pThis->fileSizeTimer = NULL; + } +} + +void FilePropsDialog::onFileSizeTimerTimeout() { + if(deepCountJob && !fm_job_is_cancelled(FM_JOB(deepCountJob))) { + char size_str[128]; + fm_file_size_to_str(size_str, sizeof(size_str), deepCountJob->total_size, + fm_config->si_unit); + // FIXME: + // OMG! It's really unbelievable that Qt developers only implement + // QObject::tr(... int n). GNU gettext developers are smarter and + // they use unsigned long instead of int. + // We cannot use Qt here to handle plural forms. So sad. :-( + QString str = QString::fromUtf8(size_str) % + QString(" (%1 B)").arg(deepCountJob->total_size); + // tr(" (%n) byte(s)", "", deepCountJob->total_size); + ui->fileSize->setText(str); + + fm_file_size_to_str(size_str, sizeof(size_str), deepCountJob->total_ondisk_size, + fm_config->si_unit); + str = QString::fromUtf8(size_str) % + QString(" (%1 B)").arg(deepCountJob->total_ondisk_size); + // tr(" (%n) byte(s)", "", deepCountJob->total_ondisk_size); + ui->onDiskSize->setText(str); + } +} + +void FilePropsDialog::accept() { + + // applications + if(mimeType && ui->openWith->isChanged()) { + GAppInfo* currentApp = ui->openWith->selectedApp(); + g_app_info_set_as_default_for_type(currentApp, fm_mime_type_get_type(mimeType), NULL); + } + + // check if chown or chmod is needed + guint32 newUid = uidFromName(ui->owner->text()); + guint32 newGid = gidFromName(ui->ownerGroup->text()); + bool needChown = (newUid != uid || newGid != gid); + + int newOwnerPermSel = ui->ownerPerm->currentIndex(); + int newGroupPermSel = ui->groupPerm->currentIndex(); + int newOtherPermSel = ui->otherPerm->currentIndex(); + Qt::CheckState newExecCheckState = ui->executable->checkState(); + bool needChmod = ((newOwnerPermSel != ownerPermSel) || + (newGroupPermSel != groupPermSel) || + (newOtherPermSel != otherPermSel) || + (newExecCheckState != execCheckState)); + + if(needChmod || needChown) { + FmPathList* paths = fm_path_list_new_from_file_info_list(fileInfos_); + FileOperation* op = new FileOperation(FileOperation::ChangeAttr, paths); + fm_path_list_unref(paths); + if(needChown) { + // don't do chown if new uid/gid and the original ones are actually the same. + if(newUid == uid) + newUid = -1; + if(newGid == gid) + newGid = -1; + op->setChown(newUid, newGid); + } + if(needChmod) { + mode_t newMode = 0; + mode_t newModeMask = 0; + // FIXME: we need to make sure that folders with "r" permission also have "x" + // at the same time. Otherwise, it's not able to browse the folder later. + if(newOwnerPermSel != ownerPermSel && newOwnerPermSel != ACCESS_NO_CHANGE) { + // owner permission changed + newModeMask |= (S_IRUSR|S_IWUSR); // affect user bits + if(newOwnerPermSel == ACCESS_READ_ONLY) + newMode |= S_IRUSR; + else if(newOwnerPermSel == ACCESS_READ_WRITE) + newMode |= (S_IRUSR|S_IWUSR); + } + if(newGroupPermSel != groupPermSel && newGroupPermSel != ACCESS_NO_CHANGE) { + qDebug("newGroupPermSel: %d", newGroupPermSel); + // group permission changed + newModeMask |= (S_IRGRP|S_IWGRP); // affect group bits + if(newGroupPermSel == ACCESS_READ_ONLY) + newMode |= S_IRGRP; + else if(newGroupPermSel == ACCESS_READ_WRITE) + newMode |= (S_IRGRP|S_IWGRP); + } + if(newOtherPermSel != otherPermSel && newOtherPermSel != ACCESS_NO_CHANGE) { + // other permission changed + newModeMask |= (S_IROTH|S_IWOTH); // affect other bits + if(newOtherPermSel == ACCESS_READ_ONLY) + newMode |= S_IROTH; + else if(newOtherPermSel == ACCESS_READ_WRITE) + newMode |= (S_IROTH|S_IWOTH); + } + if(newExecCheckState != execCheckState && newExecCheckState != Qt::PartiallyChecked) { + // executable state changed + newModeMask |= (S_IXUSR|S_IXGRP|S_IXOTH); + if(newExecCheckState == Qt::Checked) + newMode |= (S_IXUSR|S_IXGRP|S_IXOTH); + } + op->setChmod(newMode, newModeMask); + + if(hasDir) { // if there are some dirs in our selected files + QMessageBox::StandardButton r = QMessageBox::question(this, + tr("Apply changes"), + tr("Do you want to recursively apply these changes to all files and sub-folders?"), + QMessageBox::Yes|QMessageBox::No); + if(r == QMessageBox::Yes) + op->setRecursiveChattr(true); + } + } + op->setAutoDestroy(true); + op->run(); + } + + QDialog::accept(); +} + +void FilePropsDialog::initOwner() { + if(allNative) { + if(uid != DIFFERENT_UIDS) + ui->owner->setText(uidToName(uid)); + if(gid != DIFFERENT_GIDS) + ui->ownerGroup->setText(gidToName(gid)); + + if(geteuid() != 0) { // on local filesystems, only root can do chown. + ui->owner->setEnabled(false); + ui->ownerGroup->setEnabled(false); + } + } +} diff --git a/libfm-qt/filepropsdialog.h b/libfm-qt/filepropsdialog.h new file mode 100644 index 0000000..162fea5 --- /dev/null +++ b/libfm-qt/filepropsdialog.h @@ -0,0 +1,97 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FILEPROPSDIALOG_H +#define FM_FILEPROPSDIALOG_H + +#include "libfmqtglobals.h" +#include +#include +#include + +namespace Ui { + class FilePropsDialog; +}; + +namespace Fm { + +class LIBFM_QT_API FilePropsDialog : public QDialog { +Q_OBJECT + +public: + explicit FilePropsDialog(FmFileInfoList* files, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~FilePropsDialog(); + + virtual void accept(); + + static FilePropsDialog* showForFile(FmFileInfo* file, QWidget* parent = 0) { + FmFileInfoList* files = fm_file_info_list_new(); + fm_file_info_list_push_tail(files, file); + FilePropsDialog* dlg = showForFiles(files, parent); + fm_file_info_list_unref(files); + return dlg; + } + + static FilePropsDialog* showForFiles(FmFileInfoList* files, QWidget* parent = 0) { + FilePropsDialog* dlg = new FilePropsDialog(files, parent); + dlg->show(); + return dlg; + } + +private: + void initGeneralPage(); + void initApplications(); + void initPermissionsPage(); + void initOwner(); + + static void onDeepCountJobFinished(FmDeepCountJob* job, FilePropsDialog* pThis); + +private Q_SLOTS: + void onFileSizeTimerTimeout(); + +private: + Ui::FilePropsDialog* ui; + FmFileInfoList* fileInfos_; // list of all file infos + FmFileInfo* fileInfo; // file info of the first file in the list + bool singleType; // all files are of the same type? + bool singleFile; // only one file is selected? + bool hasDir; // is there any dir in the files? + bool allNative; // all files are on native UNIX filesystems (not virtual or remote) + + FmMimeType* mimeType; // mime type of the files + + gint32 uid; // owner uid of the files, -1 means all files do not have the same uid + gint32 gid; // owner gid of the files, -1 means all files do not have the same uid + mode_t ownerPerm; // read permission of the files, -1 means not all files have the same value + int ownerPermSel; + mode_t groupPerm; // read permission of the files, -1 means not all files have the same value + int groupPermSel; + mode_t otherPerm; // read permission of the files, -1 means not all files have the same value + int otherPermSel; + mode_t execPerm; // exec permission of the files + Qt::CheckState execCheckState; + + FmDeepCountJob* deepCountJob; // job used to count total size + QTimer* fileSizeTimer; +}; + +} + +#endif // FM_FILEPROPSDIALOG_H diff --git a/libfm-qt/folderitemdelegate.cpp b/libfm-qt/folderitemdelegate.cpp new file mode 100644 index 0000000..ad2a60f --- /dev/null +++ b/libfm-qt/folderitemdelegate.cpp @@ -0,0 +1,218 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "folderitemdelegate.h" +#include "foldermodel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Fm { + +FolderItemDelegate::FolderItemDelegate(QAbstractItemView* view, QObject* parent): + QStyledItemDelegate(parent ? parent : view), + symlinkIcon_(QIcon::fromTheme("emblem-symbolic-link")), + view_(view) { +} + +FolderItemDelegate::~FolderItemDelegate() { + +} + +QSize FolderItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { + QVariant value = index.data(Qt::SizeHintRole); + if(value.isValid()) + return qvariant_cast(value); + if(option.decorationPosition == QStyleOptionViewItem::Top || + option.decorationPosition == QStyleOptionViewItem::Bottom) { + + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + opt.decorationAlignment = Qt::AlignHCenter|Qt::AlignTop; + opt.displayAlignment = Qt::AlignTop|Qt::AlignHCenter; + const QWidget* widget = opt.widget; + QStyle* style = widget ? widget->style() : QApplication::style(); + + // FIXME: there're some problems in this size hint calculation. + Q_ASSERT(gridSize_ != QSize()); + QRectF textRect(0, 0, gridSize_.width() - 4, gridSize_.height() - opt.decorationSize.height() - 4); + drawText(NULL, opt, textRect); // passing NULL for painter will calculate the bounding rect only. + int width = qMax((int)textRect.width(), opt.decorationSize.width()) + 4; + int height = opt.decorationSize.height() + textRect.height() + 4; + return QSize(width, height); + } + return QStyledItemDelegate::sizeHint(option, index); +} + +QIcon::Mode FolderItemDelegate::iconModeFromState(QStyle::State state) { + QIcon::Mode iconMode; + if(state & QStyle::State_Enabled) { + if(state & QStyle::State_Selected) + iconMode = QIcon::Selected; + else { + iconMode = QIcon::Normal; + } + } + else + iconMode = QIcon::Disabled; + return iconMode; +} + +// special thanks to Razor-qt developer Alec Moskvin(amoskvin) for providing the fix! +void FolderItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { + Q_ASSERT(index.isValid()); + FmFileInfo* file = static_cast(index.data(FolderModel::FileInfoRole).value()); + bool isSymlink = file && fm_file_info_is_symlink(file); + + if(option.decorationPosition == QStyleOptionViewItem::Top || + option.decorationPosition == QStyleOptionViewItem::Bottom) { + painter->save(); + painter->setClipRect(option.rect); + + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + opt.decorationAlignment = Qt::AlignHCenter|Qt::AlignTop; + opt.displayAlignment = Qt::AlignTop|Qt::AlignHCenter; + + // draw the icon + QIcon::Mode iconMode = iconModeFromState(opt.state); + QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y()); + QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode); + painter->drawPixmap(iconPos, pixmap); + + // draw some emblems for the item if needed + // we only support symlink emblem at the moment + if(isSymlink) + painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode)); + + // draw the text + QRectF textRect(opt.rect.x(), opt.rect.y() + opt.decorationSize.height(), opt.rect.width(), opt.rect.height() - opt.decorationSize.height()); + drawText(painter, opt, textRect); + painter->restore(); + } + else { + // let QStyledItemDelegate does its default painting + QStyledItemDelegate::paint(painter, option, index); + + // draw emblems if needed + if(isSymlink) { + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + QIcon::Mode iconMode = iconModeFromState(opt.state); + QPoint iconPos(opt.rect.x(), opt.rect.y() + (opt.rect.height() - opt.decorationSize.height()) / 2); + // draw some emblems for the item if needed + // we only support symlink emblem at the moment + painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode)); + } + } +} + +// if painter is NULL, the method calculate the bounding rectangle of the text and save it to textRect +void FolderItemDelegate::drawText(QPainter* painter, QStyleOptionViewItemV4& opt, QRectF& textRect) const { + const QWidget* widget = opt.widget; + QStyle* style = widget->style() ? widget->style() : qApp->style(); + const int focusMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, widget); + QTextLayout layout(opt.text, opt.font); + QTextOption textOption; + textOption.setAlignment(opt.displayAlignment); + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + textOption.setTextDirection(opt.direction); + layout.setTextOption(textOption); + qreal height = 0; + qreal width = 0; + int visibleLines = 0; + layout.beginLayout(); + QString elidedText; + for(;;) { + QTextLine line = layout.createLine(); + if(!line.isValid()) + break; + line.setLineWidth(textRect.width()); + height += opt.fontMetrics.leading(); + line.setPosition(QPointF(0, height)); + if((height + line.height() + textRect.y()) > textRect.bottom()) { + // if part of this line falls outside the textRect, ignore it and quit. + QTextLine lastLine = layout.lineAt(visibleLines - 1); + elidedText = opt.text.mid(lastLine.textStart()); + elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); + if(visibleLines == 1) // this is the only visible line + width = textRect.width(); + break; + } + height += line.height(); + width = qMax(width, line.naturalTextWidth()); + ++ visibleLines; + } + layout.endLayout(); + + // draw background for selected item + QRectF boundRect = layout.boundingRect(); + //qDebug() << "bound rect: " << boundRect << "width: " << width; + boundRect.setWidth(width); + boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); + + if(!painter) { // no painter, calculate the bounding rect only + textRect = boundRect; + return; + } + + QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + if(opt.state & QStyle::State_Selected) { + painter->fillRect(boundRect, opt.palette.highlight()); + painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); + } + else + painter->setPen(opt.palette.color(cg, QPalette::Text)); + + // draw text + for(int i = 0; i < visibleLines; ++i) { + QTextLine line = layout.lineAt(i); + if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text + QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); + painter->drawText(pos, elidedText); + } + else { + line.draw(painter, textRect.topLeft()); + } + } + + if(opt.state & QStyle::State_HasFocus) { + // draw focus rect + QStyleOptionFocusRect o; + o.QStyleOption::operator=(opt); + o.rect = boundRect.toRect(); // subElementRect(SE_ItemViewItemFocusRect, vopt, widget); + o.state |= QStyle::State_KeyboardFocusChange; + o.state |= QStyle::State_Item; + QPalette::ColorGroup cg = (opt.state & QStyle::State_Enabled) + ? QPalette::Normal : QPalette::Disabled; + o.backgroundColor = opt.palette.color(cg, (opt.state & QStyle::State_Selected) + ? QPalette::Highlight : QPalette::Window); + style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget); + } +} + + +} // namespace Fm diff --git a/libfm-qt/folderitemdelegate.h b/libfm-qt/folderitemdelegate.h new file mode 100644 index 0000000..f181f6a --- /dev/null +++ b/libfm-qt/folderitemdelegate.h @@ -0,0 +1,59 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FOLDERITEMDELEGATE_H +#define FM_FOLDERITEMDELEGATE_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class LIBFM_QT_API FolderItemDelegate : public QStyledItemDelegate { + Q_OBJECT +public: + explicit FolderItemDelegate(QAbstractItemView* view, QObject* parent = 0); + virtual ~FolderItemDelegate(); + + void setGridSize(QSize size) { + gridSize_ = size; + } + + QSize gridSize() { + return gridSize_; + } + + virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const; + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + +private: + void drawText(QPainter* painter, QStyleOptionViewItemV4& opt, QRectF& textRect) const; + static QIcon::Mode iconModeFromState(QStyle::State state); + +private: + QAbstractItemView* view_; + QIcon symlinkIcon_; + QSize gridSize_; +}; + +} + +#endif // FM_FOLDERITEMDELEGATE_H diff --git a/libfm-qt/foldermenu.cpp b/libfm-qt/foldermenu.cpp new file mode 100644 index 0000000..692f114 --- /dev/null +++ b/libfm-qt/foldermenu.cpp @@ -0,0 +1,300 @@ +/* + + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + Copyright (C) 2012-2014 Andriy Grytsenko (LStranger) + + 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 "foldermenu.h" +#include "filepropsdialog.h" +#include "folderview.h" +#include "utilities.h" +#include // for memset + +namespace Fm { + +FolderMenu::FolderMenu(FolderView* view, QWidget* parent): + QMenu(parent), + view_(view) { + + ProxyFolderModel* model = view_->model(); + + createAction_ = new QAction(tr("Create &New"), this); + addAction(createAction_); + + createCreateNewMenu(); + createAction_->setMenu(createNewMenu_); + + separator1_ = addSeparator(); + + pasteAction_ = new QAction(QIcon::fromTheme("edit-paste"), tr("&Paste"), this); + addAction(pasteAction_); + connect(pasteAction_, &QAction::triggered, this, &FolderMenu::onPasteActionTriggered); + + separator2_ = addSeparator(); + + selectAllAction_ = new QAction(tr("Select &All"), this); + addAction(selectAllAction_); + connect(selectAllAction_, &QAction::triggered, this, &FolderMenu::onSelectAllActionTriggered); + + invertSelectionAction_ = new QAction(tr("Invert Selection"), this); + addAction(invertSelectionAction_); + connect(invertSelectionAction_, &QAction::triggered, this, &FolderMenu::onInvertSelectionActionTriggered); + + separator3_ = addSeparator(); + + sortAction_ = new QAction(tr("Sorting"), this); + addAction(sortAction_); + createSortMenu(); + sortAction_->setMenu(sortMenu_); + + showHiddenAction_ = new QAction(tr("Show Hidden"), this); + addAction(showHiddenAction_); + showHiddenAction_->setCheckable(true); + showHiddenAction_->setChecked(model->showHidden()); + connect(showHiddenAction_, &QAction::triggered, this, &FolderMenu::onShowHiddenActionTriggered); + + separator4_ = addSeparator(); + + propertiesAction_ = new QAction(tr("Folder Pr&operties"), this); + addAction(propertiesAction_); + connect(propertiesAction_, &QAction::triggered, this, &FolderMenu::onPropertiesActionTriggered); +} + +FolderMenu::~FolderMenu() { +} + +void FolderMenu::createCreateNewMenu() { + QMenu* createMenu = new QMenu(this); + createNewMenu_ = createMenu; + + QAction* action = new QAction(tr("Folder"), this); + connect(action, &QAction::triggered, this, &FolderMenu::onCreateNewFolder); + createMenu->addAction(action); + + action = new QAction(tr("Blank File"), this); + connect(action, &QAction::triggered, this, &FolderMenu::onCreateNewFile); + createMenu->addAction(action); + + // add more items to "Create New" menu from templates + GList* templates = fm_template_list_all(fm_config->only_user_templates); + if(templates) { + createMenu->addSeparator(); + for(GList* l = templates; l; l = l->next) { + FmTemplate* templ = (FmTemplate*)l->data; + /* we support directories differently */ + if(fm_template_is_directory(templ)) + continue; + FmMimeType* mime_type = fm_template_get_mime_type(templ); + const char* label = fm_template_get_label(templ); + QString text = QString("%1 (%2)").arg(QString::fromUtf8(label)).arg(QString::fromUtf8(fm_mime_type_get_desc(mime_type))); + FmIcon* icon = fm_template_get_icon(templ); + if(!icon) + icon = fm_mime_type_get_icon(mime_type); + QAction* action = createMenu->addAction(IconTheme::icon(icon), text); + action->setObjectName(QString::fromUtf8(fm_template_get_name(templ, NULL))); + connect(action, &QAction::triggered, this, &FolderMenu::onCreateNew); + } + } +} + +void FolderMenu::addSortMenuItem(QString title, int id) { + QAction* action = new QAction(title, this); + sortMenu_->addAction(action); + action->setCheckable(true); + sortActionGroup_->addAction(action); + connect(action, &QAction::triggered, this, &FolderMenu::onSortActionTriggered); + sortActions_[id] = action; +} + +void FolderMenu::createSortMenu() { + ProxyFolderModel* model = view_->model(); + + sortMenu_ = new QMenu(this); + sortActionGroup_ = new QActionGroup(sortMenu_); + sortActionGroup_->setExclusive(true); + + std::memset(sortActions_, 0, sizeof(sortActions_)); + + addSortMenuItem(tr("By File Name"), FolderModel::ColumnFileName); + addSortMenuItem(tr("By Modification Time"), FolderModel::ColumnFileMTime); + addSortMenuItem(tr("By File Size"), FolderModel::ColumnFileSize); + addSortMenuItem(tr("By File Type"), FolderModel::ColumnFileType); + addSortMenuItem(tr("By File Owner"), FolderModel::ColumnFileOwner); + + int col = model->sortColumn(); + + if(col >= 0 && col < FolderModel::NumOfColumns) { + sortActions_[col]->setChecked(true);; + } + + sortMenu_->addSeparator(); + + QActionGroup* group = new QActionGroup(this); + group->setExclusive(true); + actionAscending_ = new QAction(tr("Ascending"), this); + actionAscending_->setCheckable(true); + sortMenu_->addAction(actionAscending_); + group->addAction(actionAscending_); + + actionDescending_ = new QAction(tr("Descending"), this); + actionDescending_->setCheckable(true); + sortMenu_->addAction(actionDescending_); + group->addAction(actionDescending_); + + if(model->sortOrder() == Qt::AscendingOrder) + actionAscending_->setChecked(true); + else + actionDescending_->setChecked(true); + + connect(actionAscending_, &QAction::triggered, this, &FolderMenu::onSortOrderActionTriggered); + connect(actionDescending_, &QAction::triggered, this, &FolderMenu::onSortOrderActionTriggered); + + sortMenu_->addSeparator(); + + QAction* actionFolderFirst = new QAction(tr("Folder First"), this); + sortMenu_->addAction(actionFolderFirst); + actionFolderFirst->setCheckable(true); + + if(model->folderFirst()) + actionFolderFirst->setChecked(true); + + connect(actionFolderFirst, &QAction::triggered, this, &FolderMenu::onFolderFirstActionTriggered); + + QAction* actionCaseSensitive = new QAction(tr("Case Sensitive"), this); + sortMenu_->addAction(actionCaseSensitive); + actionCaseSensitive->setCheckable(true); + + if(model->sortCaseSensitivity() == Qt::CaseSensitive) + actionCaseSensitive->setChecked(true); + + connect(actionCaseSensitive, &QAction::triggered, this, &FolderMenu::onCaseSensitiveActionTriggered); +} + +void FolderMenu::onPasteActionTriggered() { + FmPath* folderPath = view_->path(); + + if(folderPath) + pasteFilesFromClipboard(folderPath); +} + +void FolderMenu::onSelectAllActionTriggered() { + view_->selectAll(); +} + +void FolderMenu::onInvertSelectionActionTriggered() { + view_->invertSelection(); +} + +void FolderMenu::onSortActionTriggered(bool checked) { + ProxyFolderModel* model = view_->model(); + + if(model) { + QAction* action = static_cast(sender()); + + for(int col = 0; col < FolderModel::NumOfColumns; ++col) { + if(action == sortActions_[col]) { + model->sort(col, model->sortOrder()); + break; + } + } + } +} + +void FolderMenu::onSortOrderActionTriggered(bool checked) { + ProxyFolderModel* model = view_->model(); + + if(model) { + QAction* action = static_cast(sender()); + Qt::SortOrder order; + + if(action == actionAscending_) + order = Qt::AscendingOrder; + else + order = Qt::DescendingOrder; + + model->sort(model->sortColumn(), order); + } +} + +void FolderMenu::onShowHiddenActionTriggered(bool checked) { + ProxyFolderModel* model = view_->model(); + + if(model) { + qDebug("show hidden: %d", checked); + model->setShowHidden(checked); + } +} + +void FolderMenu::onCaseSensitiveActionTriggered(bool checked) { + ProxyFolderModel* model = view_->model(); + + if(model) { + model->setSortCaseSensitivity(checked ? Qt::CaseSensitive : Qt::CaseInsensitive); + } +} + +void FolderMenu::onFolderFirstActionTriggered(bool checked) { + ProxyFolderModel* model = view_->model(); + + if(model) { + model->setFolderFirst(checked); + } +} + +void FolderMenu::onPropertiesActionTriggered() { + FmFileInfo* folderInfo = view_->folderInfo(); + + if(folderInfo) + FilePropsDialog::showForFile(folderInfo); +} + +void FolderMenu::onCreateNewFile() { + FmPath* dirPath = view_->path(); + + if(dirPath) + createFile(CreateNewTextFile, dirPath); +} + +void FolderMenu::onCreateNewFolder() { + FmPath* dirPath = view_->path(); + + if(dirPath) + createFile(CreateNewFolder, dirPath); +} + +void FolderMenu::onCreateNew() { + QAction* action = static_cast(sender()); + QByteArray name = action->objectName().toUtf8(); + GList* templates = fm_template_list_all(fm_config->only_user_templates); + FmTemplate* templ = NULL; + for(GList* l = templates; l; l = l->next) { + FmTemplate* t = (FmTemplate*)l->data; + if(name == fm_template_get_name(t, NULL)) { + templ = t; + break; + } + } + if(templ) { // template found + FmPath* dirPath = view_->path(); + if(dirPath) + createFile(CreateWithTemplate, dirPath, templ, view_); + } +} + + +} // namespace Fm diff --git a/libfm-qt/foldermenu.h b/libfm-qt/foldermenu.h new file mode 100644 index 0000000..56b3dec --- /dev/null +++ b/libfm-qt/foldermenu.h @@ -0,0 +1,134 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FOLDERMENU_H +#define FM_FOLDERMENU_H + +#include "libfmqtglobals.h" +#include +#include +#include "foldermodel.h" + +class QAction; + +namespace Fm { + +class FolderView; + +class LIBFM_QT_API FolderMenu : public QMenu { +Q_OBJECT + +public: + explicit FolderMenu(FolderView* view, QWidget* parent = 0); + virtual ~FolderMenu(); + + QAction* createAction() { + return createAction_; + } + + QAction* separator1() { + return separator1_; + } + + QAction* pasteAction() { + return pasteAction_; + } + + QAction* separator2() { + return separator2_; + } + + QAction* selectAllAction() { + return selectAllAction_; + } + + QAction* invertSelectionAction() { + return invertSelectionAction_; + } + + QAction* separator3() { + return separator3_; + } + + QAction* sortAction() { + return sortAction_; + } + + QAction* showHiddenAction() { + return showHiddenAction_; + } + + QAction* separator4() { + return separator4_; + } + + QAction* propertiesAction() { + return propertiesAction_; + } + + FolderView* view() { + return view_; + } + +protected Q_SLOTS: + + void onCreateNewFolder(); + void onCreateNewFile(); + void onCreateNew(); + + void onPasteActionTriggered(); + void onSelectAllActionTriggered(); + void onInvertSelectionActionTriggered(); + void onSortActionTriggered(bool checked); + void onSortOrderActionTriggered(bool checked); + void onShowHiddenActionTriggered(bool checked); + void onCaseSensitiveActionTriggered(bool checked); + void onFolderFirstActionTriggered(bool checked); + void onPropertiesActionTriggered(); + +private: + void createCreateNewMenu(); + void createSortMenu(); + void addSortMenuItem(QString title, int id); + +private: + FolderView* view_; + QAction* createAction_; + QMenu* createNewMenu_; + QAction* separator1_; + QAction* pasteAction_; + QAction* separator2_; + QAction* selectAllAction_; + QAction* invertSelectionAction_; + QAction* separator3_; + QAction* sortAction_; + QActionGroup* sortActionGroup_; + QMenu* sortMenu_; + QAction* sortActions_[FolderModel::NumOfColumns]; + QAction* actionAscending_; + QAction* actionDescending_; + QAction* showHiddenAction_; + QAction* separator4_; + QAction* propertiesAction_; +}; + +} + +#endif // FM_FOLDERMENU_H diff --git a/libfm-qt/foldermodel.cpp b/libfm-qt/foldermodel.cpp new file mode 100644 index 0000000..de473eb --- /dev/null +++ b/libfm-qt/foldermodel.cpp @@ -0,0 +1,557 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "foldermodel.h" +#include "icontheme.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "utilities.h" +#include "fileoperation.h" +#include "thumbnailloader.h" + +using namespace Fm; + +FolderModel::FolderModel() : + folder_(NULL) { +/* + ColumnIcon, + ColumnName, + ColumnFileType, + ColumnMTime, + NumOfColumns +*/ + thumbnailRefCounts.reserve(4); + + // reload all icons when the icon theme is changed + connect(IconTheme::instance(), &IconTheme::changed, this, &FolderModel::updateIcons); +} + +FolderModel::~FolderModel() { + qDebug("delete FolderModel"); + + if(folder_) + setFolder(NULL); + + // if the thumbnail requests list is not empty, cancel them + if(!thumbnailResults.empty()) { + Q_FOREACH(FmThumbnailLoader* res, thumbnailResults) { + ThumbnailLoader::cancel(res); + } + } +} + +void FolderModel::setFolder(FmFolder* new_folder) { + if(folder_) { + removeAll(); // remove old items + g_signal_handlers_disconnect_by_func(folder_, gpointer(onStartLoading), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFinishLoading), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesAdded), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesChanged), this); + g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesRemoved), this); + g_object_unref(folder_); + } + if(new_folder) { + folder_ = FM_FOLDER(g_object_ref(new_folder)); + g_signal_connect(folder_, "start-loading", G_CALLBACK(onStartLoading), this); + g_signal_connect(folder_, "finish-loading", G_CALLBACK(onFinishLoading), this); + g_signal_connect(folder_, "files-added", G_CALLBACK(onFilesAdded), this); + g_signal_connect(folder_, "files-changed", G_CALLBACK(onFilesChanged), this); + g_signal_connect(folder_, "files-removed", G_CALLBACK(onFilesRemoved), this); + // handle the case if the folder is already loaded + if(fm_folder_is_loaded(folder_)) + insertFiles(0, fm_folder_get_files(folder_)); + } + else + folder_ = NULL; +} + +void FolderModel::onStartLoading(FmFolder* folder, gpointer user_data) { + FolderModel* model = static_cast(user_data); + // remove all items + model->removeAll(); +} + +void FolderModel::onFinishLoading(FmFolder* folder, gpointer user_data) { + FolderModel* model = static_cast(user_data); +} + +void FolderModel::onFilesAdded(FmFolder* folder, GSList* files, gpointer user_data) { + FolderModel* model = static_cast(user_data); + int n_files = g_slist_length(files); + model->beginInsertRows(QModelIndex(), model->items.count(), model->items.count() + n_files - 1); + for(GSList* l = files; l; l = l->next) { + FmFileInfo* info = FM_FILE_INFO(l->data); + FolderModelItem item(info); +/* + if(fm_file_info_is_hidden(info)) { + model->hiddenItems.append(item); + continue; + } +*/ + model->items.append(item); + } + model->endInsertRows(); +} + +//static +void FolderModel::onFilesChanged(FmFolder* folder, GSList* files, gpointer user_data) { + FolderModel* model = static_cast(user_data); + int n_files = g_slist_length(files); + for(GSList* l = files; l; l = l->next) { + FmFileInfo* info = FM_FILE_INFO(l->data); + int row; + QList::iterator it = model->findItemByFileInfo(info, &row); + if(it != model->items.end()) { + FolderModelItem& item = *it; + // try to update the item + item.displayName = QString::fromUtf8(fm_file_info_get_disp_name(info)); + item.updateIcon(); + item.thumbnails.clear(); + QModelIndex index = model->createIndex(row, 0, &item); + Q_EMIT model->dataChanged(index, index); + } + } +} + +//static +void FolderModel::onFilesRemoved(FmFolder* folder, GSList* files, gpointer user_data) { + FolderModel* model = static_cast(user_data); + for(GSList* l = files; l; l = l->next) { + FmFileInfo* info = FM_FILE_INFO(l->data); + const char* name = fm_file_info_get_name(info); + int row; + QList::iterator it = model->findItemByName(name, &row); + if(it != model->items.end()) { + model->beginRemoveRows(QModelIndex(), row, row); + model->items.erase(it); + model->endRemoveRows(); + } + } +} + +void FolderModel::insertFiles(int row, FmFileInfoList* files) { + int n_files = fm_file_info_list_get_length(files); + beginInsertRows(QModelIndex(), row, row + n_files - 1); + for(GList* l = fm_file_info_list_peek_head_link(files); l; l = l->next) { + FolderModelItem item(FM_FILE_INFO(l->data)); + items.append(item); + } + endInsertRows(); +} + +void FolderModel::removeAll() { + if(items.empty()) + return; + beginRemoveRows(QModelIndex(), 0, items.size() - 1); + items.clear(); + endRemoveRows(); +} + +int FolderModel::rowCount(const QModelIndex & parent) const { + if(parent.isValid()) + return 0; + return items.size(); +} + +int FolderModel::columnCount (const QModelIndex & parent = QModelIndex()) const { + if(parent.isValid()) + return 0; + return NumOfColumns; +} + +FolderModelItem* FolderModel::itemFromIndex(const QModelIndex& index) const { + return reinterpret_cast(index.internalPointer()); +} + +FmFileInfo* FolderModel::fileInfoFromIndex(const QModelIndex& index) const { + FolderModelItem* item = itemFromIndex(index); + return item ? item->info : NULL; +} + +QVariant FolderModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const { + if(!index.isValid() || index.row() > items.size() || index.column() >= NumOfColumns) { + return QVariant(); + } + FolderModelItem* item = itemFromIndex(index); + FmFileInfo* info = item->info; + + switch(role) { + case Qt::ToolTipRole: + return QVariant(item->displayName); + case Qt::DisplayRole: { + switch(index.column()) { + case ColumnFileName: { + return QVariant(item->displayName); + } + case ColumnFileType: { + FmMimeType* mime = fm_file_info_get_mime_type(info); + const char* desc = fm_mime_type_get_desc(mime); + return QString::fromUtf8(desc); + } + case ColumnFileMTime: { + const char* name = fm_file_info_get_disp_mtime(info); + return QString::fromUtf8(name); + } + case ColumnFileSize: { + const char* name = fm_file_info_get_disp_size(info); + return QString::fromUtf8(name); + break; + } + case ColumnFileOwner: { + const char* name = fm_file_info_get_disp_owner(info); + return QString::fromUtf8(name); + break; + } + } + } + case Qt::DecorationRole: { + if(index.column() == 0) { + // QPixmap pix = IconTheme::loadIcon(fm_file_info_get_icon(info), iconSize_); + return QVariant(item->icon); + // return QVariant(pix); + } + } + case FileInfoRole: + return qVariantFromValue((void*)info); + } + return QVariant(); +} + +QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const { + if(role == Qt::DisplayRole) { + if(orientation == Qt::Horizontal) { + QString title; + switch(section) { + case ColumnFileName: + title = tr("Name"); + break; + case ColumnFileType: + title = tr("Type"); + break; + case ColumnFileSize: + title = tr("Size"); + break; + case ColumnFileMTime: + title = tr("Modified"); + break; + case ColumnFileOwner: + title = tr("Owner"); + break; + } + return QVariant(title); + } + } + return QVariant(); +} + +QModelIndex FolderModel::index(int row, int column, const QModelIndex & parent) const { + if(row <0 || row >= items.size() || column < 0 || column >= NumOfColumns) + return QModelIndex(); + const FolderModelItem& item = items.at(row); + return createIndex(row, column, (void*)&item); +} + +QModelIndex FolderModel::parent(const QModelIndex & index) const { + return QModelIndex(); +} + +Qt::ItemFlags FolderModel::flags(const QModelIndex& index) const { + // FIXME: should not return same flags unconditionally for all columns + Qt::ItemFlags flags; + if(index.isValid()) { + flags = Qt::ItemIsEnabled|Qt::ItemIsSelectable; + if(index.column() == ColumnFileName) + flags |= (Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); + } + else { + flags = Qt::ItemIsDropEnabled; + } + return flags; +} + +// FIXME: this is very inefficient and should be replaced with a +// more reasonable implementation later. +QList::iterator FolderModel::findItemByPath(FmPath* path, int* row) { + QList::iterator it = items.begin(); + int i = 0; + while(it != items.end()) { + FolderModelItem& item = *it; + FmPath* item_path = fm_file_info_get_path(item.info); + if(fm_path_equal(item_path, path)) { + *row = i; + return it; + } + ++it; + ++i; + } + return items.end(); +} + +// FIXME: this is very inefficient and should be replaced with a +// more reasonable implementation later. +QList::iterator FolderModel::findItemByName(const char* name, int* row) { + QList::iterator it = items.begin(); + int i = 0; + while(it != items.end()) { + FolderModelItem& item = *it; + const char* item_name = fm_file_info_get_name(item.info); + if(strcmp(name, item_name) == 0) { + *row = i; + return it; + } + ++it; + ++i; + } + return items.end(); +} + +QList< FolderModelItem >::iterator FolderModel::findItemByFileInfo(FmFileInfo* info, int* row) { + QList::iterator it = items.begin(); + int i = 0; + while(it != items.end()) { + FolderModelItem& item = *it; + if(item.info == info) { + *row = i; + return it; + } + ++it; + ++i; + } + return items.end(); +} + +QStringList FolderModel::mimeTypes() const { + qDebug("FolderModel::mimeTypes"); + QStringList types = QAbstractItemModel::mimeTypes(); + // now types contains "application/x-qabstractitemmodeldatalist" + types << "text/uri-list"; + // types << "x-special/gnome-copied-files"; + return types; +} + +QMimeData* FolderModel::mimeData(const QModelIndexList& indexes) const { + QMimeData* data = QAbstractItemModel::mimeData(indexes); + qDebug("FolderModel::mimeData"); + // build a uri list + QByteArray urilist; + urilist.reserve(4096); + + QModelIndexList::const_iterator it; + for(it = indexes.constBegin(); it != indexes.end(); ++it) { + const QModelIndex index = *it; + FolderModelItem* item = itemFromIndex(index); + if(item) { + FmPath* path = fm_file_info_get_path(item->info); + char* uri = fm_path_to_uri(path); + urilist.append(uri); + urilist.append('\n'); + g_free(uri); + } + } + data->setData("text/uri-list", urilist); + + return data; +} + +bool FolderModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { + qDebug("FolderModel::dropMimeData"); + if(!folder_) + return false; + FmPath* destPath; + if(parent.isValid()) { // drop on an item + FmFileInfo* info; + if(row == -1 && column == -1) + info = fileInfoFromIndex(parent); + else { + QModelIndex itemIndex = parent.child(row, column); + info = fileInfoFromIndex(itemIndex); + } + if(info) + destPath = fm_file_info_get_path(info); + else + return false; + } + else { // drop on blank area of the folder + destPath = path(); + } + + // FIXME: should we put this in dropEvent handler of FolderView instead? + if(data->hasUrls()) { + qDebug("drop action: %d", action); + FmPathList* srcPaths = pathListFromQUrls(data->urls()); + switch(action) { + case Qt::CopyAction: + FileOperation::copyFiles(srcPaths, destPath); + break; + case Qt::MoveAction: + FileOperation::moveFiles(srcPaths, destPath); + break; + case Qt::LinkAction: + FileOperation::symlinkFiles(srcPaths, destPath); + default: + fm_path_list_unref(srcPaths); + return false; + } + fm_path_list_unref(srcPaths); + return true; + } + else if(data->hasFormat("application/x-qabstractitemmodeldatalist")) { + return true; + } + return QAbstractListModel::dropMimeData(data, action, row, column, parent); +} + +Qt::DropActions FolderModel::supportedDropActions() const { + qDebug("FolderModel::supportedDropActions"); + return Qt::CopyAction|Qt::MoveAction|Qt::LinkAction; +} + +// ask the model to load thumbnails of the specified size +void FolderModel::cacheThumbnails(int size) { + QVector >::iterator it; + for(it = thumbnailRefCounts.begin(); it != thumbnailRefCounts.end(); ++it) { + if(it->first == size) { + break; + } + } + if(it != thumbnailRefCounts.end()) + ++it->second; + else + thumbnailRefCounts.append(QPair(size, 1)); +} + +// ask the model to free cached thumbnails of the specified size +void FolderModel::releaseThumbnails(int size) { + QVector >::iterator it; + for(it = thumbnailRefCounts.begin(); it != thumbnailRefCounts.end(); ++it) { + if(it->first == size) { + break; + } + } + if(it != thumbnailRefCounts.end()) { + --it->second; + if(it->second == 0) { + thumbnailRefCounts.erase(it); + + // remove thumbnails that ara queued for loading from thumbnailResults + QLinkedList::iterator it; + for(it = thumbnailResults.begin(); it != thumbnailResults.end();) { + QLinkedList::iterator next = it + 1; + FmThumbnailLoader* res = *it; + if(ThumbnailLoader::size(res) == size) { + ThumbnailLoader::cancel(res); + thumbnailResults.erase(it); + } + it = next; + } + + // remove all cached thumbnails of the specified size + QList::iterator itemIt; + for(itemIt = items.begin(); itemIt != items.end(); ++itemIt) { + FolderModelItem& item = *itemIt; + item.removeThumbnail(size); + } + } + } +} + +void FolderModel::onThumbnailLoaded(FmThumbnailLoader* res, gpointer user_data) { + FolderModel* pThis = reinterpret_cast(user_data); + QLinkedList::iterator it; + for(it = pThis->thumbnailResults.begin(); it != pThis->thumbnailResults.end(); ++it) { + if(*it == res) { // the thumbnail result is in our list + pThis->thumbnailResults.erase(it); // remove it from the list + FmFileInfo* info = ThumbnailLoader::fileInfo(res); + int row = -1; + // find the model item this thumbnail belongs to + QList::iterator it = pThis->findItemByFileInfo(info, &row); + if(it != pThis->items.end()) { + // the file is found in our model + FolderModelItem& item = *it; + QModelIndex index = pThis->createIndex(row, 0, (void*)&item); + // store the image in the folder model item. + int size = ThumbnailLoader::size(res); + QImage image = ThumbnailLoader::image(res); + FolderModelItem::Thumbnail* thumbnail = item.findThumbnail(size); + thumbnail->image = image; + // qDebug("thumbnail loaded for: %s, size: %d", item.displayName.toUtf8().constData(), size); + if(image.isNull()) + thumbnail->status = FolderModelItem::ThumbnailFailed; + else { + thumbnail->status = FolderModelItem::ThumbnailLoaded; + // FIXME: due to bugs in Qt's QStyledItemDelegate, if the image width and height + // are not the same, painting errors will happen. It's quite unfortunate. + // Let's do some padding to make its width and height equals. + // This greatly decrease performance :-( + // Later if we can re-implement our own item delegate, this can be avoided. + QPixmap pixmap = QPixmap(size, size); + pixmap.fill(QColor(0, 0, 0, 0)); // fill the pixmap with transparent color (alpha:0) + QPainter painter(&pixmap); + int x = (size - image.width()) / 2; + int y = (size - image.height()) / 2; + painter.drawImage(QPoint(x, y), image); // draw the image to the pixmap at center. + // FIXME: should we cache QPixmap instead for performance reason? + thumbnail->image = pixmap.toImage(); // convert it back to image + + // tell the world that we have the thumbnail loaded + Q_EMIT pThis->thumbnailLoaded(index, size); + } + } + break; + } + } +} + +// get a thumbnail of size at the index +// if a thumbnail is not yet loaded, this will initiate loading of the thumbnail. +QImage FolderModel::thumbnailFromIndex(const QModelIndex& index, int size) { + FolderModelItem* item = itemFromIndex(index); + if(item) { + FolderModelItem::Thumbnail* thumbnail = item->findThumbnail(size); + // qDebug("FolderModel::thumbnailFromIndex: %d, %s", thumbnail->status, item->displayName.toUtf8().data()); + switch(thumbnail->status) { + case FolderModelItem::ThumbnailNotChecked: { + // load the thumbnail + FmThumbnailLoader* res = ThumbnailLoader::load(item->info, size, onThumbnailLoaded, this); + thumbnailResults.push_back(res); + thumbnail->status = FolderModelItem::ThumbnailLoading; + break; + } + case FolderModelItem::ThumbnailLoaded: + return thumbnail->image; + default: + break; + } + } + return QImage(); +} + +void FolderModel::updateIcons() { + QList::iterator it = items.begin(); + for(;it != items.end(); ++it) { + (*it).updateIcon(); + } +} diff --git a/libfm-qt/foldermodel.h b/libfm-qt/foldermodel.h new file mode 100644 index 0000000..f34fea8 --- /dev/null +++ b/libfm-qt/foldermodel.h @@ -0,0 +1,121 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_FOLDERMODEL_H +#define FM_FOLDERMODEL_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "foldermodelitem.h" + +namespace Fm { + +class LIBFM_QT_API FolderModel : public QAbstractListModel { +Q_OBJECT +public: + + enum Role { + FileInfoRole = Qt::UserRole + }; + + enum ColumnId { + ColumnFileName, + ColumnFileType, + ColumnFileSize, + ColumnFileMTime, + ColumnFileOwner, + NumOfColumns + }; + +public: + FolderModel(); + virtual ~FolderModel(); + + FmFolder* folder() { + return folder_; + } + void setFolder(FmFolder* new_folder); + + FmPath* path() { + return folder_ ? fm_folder_get_path(folder_) : NULL; + } + + int rowCount(const QModelIndex & parent = QModelIndex()) const; + int columnCount (const QModelIndex & parent) const; + QVariant data(const QModelIndex & index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; + QModelIndex parent( const QModelIndex & index ) const; + // void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + + Qt::ItemFlags flags(const QModelIndex & index) const; + + virtual QStringList mimeTypes() const; + virtual QMimeData* mimeData(const QModelIndexList & indexes) const; + virtual Qt::DropActions supportedDropActions() const; + virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); + + FmFileInfo* fileInfoFromIndex(const QModelIndex& index) const; + FolderModelItem* itemFromIndex(const QModelIndex& index) const; + QImage thumbnailFromIndex(const QModelIndex& index, int size); + + void cacheThumbnails(int size); + void releaseThumbnails(int size); + +Q_SIGNALS: + void thumbnailLoaded(const QModelIndex& index, int size); + +public Q_SLOTS: + void updateIcons(); + +protected: + static void onStartLoading(FmFolder* folder, gpointer user_data); + static void onFinishLoading(FmFolder* folder, gpointer user_data); + static void onFilesAdded(FmFolder* folder, GSList* files, gpointer user_data); + static void onFilesChanged(FmFolder* folder, GSList* files, gpointer user_data); + static void onFilesRemoved(FmFolder* folder, GSList* files, gpointer user_data); + static void onThumbnailLoaded(FmThumbnailLoader *res, gpointer user_data); + + void insertFiles(int row, FmFileInfoList* files); + void removeAll(); + QList::iterator findItemByPath(FmPath* path, int* row); + QList::iterator findItemByName(const char* name, int* row); + QList::iterator findItemByFileInfo(FmFileInfo* info, int* row); + +private: + FmFolder* folder_; + // FIXME: should we use a hash table here so item lookup becomes much faster? + QList items; + + // record what size of thumbnails we should cache in an array of pairs. + QVector > thumbnailRefCounts; + QLinkedList thumbnailResults; +}; + +} + +#endif // FM_FOLDERMODEL_H diff --git a/libfm-qt/foldermodelitem.cpp b/libfm-qt/foldermodelitem.cpp new file mode 100644 index 0000000..59c95e9 --- /dev/null +++ b/libfm-qt/foldermodelitem.cpp @@ -0,0 +1,93 @@ +/* + * + * Copyright (C) 2012 Hong Jen Yee (PCMan) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "foldermodelitem.h" + +using namespace Fm; + +FolderModelItem::FolderModelItem(FmFileInfo* _info): + info(fm_file_info_ref(_info)) { + displayName = QString::fromUtf8(fm_file_info_get_disp_name(info)); + icon = IconTheme::icon(fm_file_info_get_icon(_info)); + thumbnails.reserve(2); +} + +FolderModelItem::FolderModelItem(const FolderModelItem& other) { + info = other.info ? fm_file_info_ref(other.info) : NULL; + displayName = QString::fromUtf8(fm_file_info_get_disp_name(info)); + icon = other.icon; + thumbnails = other.thumbnails; +} + +FolderModelItem::~FolderModelItem() { + if(info) + fm_file_info_unref(info); +} + +// find thumbnail of the specified size +// The returned thumbnail item is temporary and short-lived +// If you need to use the struct later, copy it to your own struct to keep it. +FolderModelItem::Thumbnail* FolderModelItem::findThumbnail(int size) { + QVector::iterator it; + for(it = thumbnails.begin(); it != thumbnails.end(); ++it) { + if(it->size == size) { // an image of the same size is found + return it; + } + } + if(it == thumbnails.end()) { + Thumbnail thumbnail; + thumbnail.status = ThumbnailNotChecked; + thumbnail.size = size; + thumbnails.append(thumbnail); + } + return &thumbnails.back(); +} + +// remove cached thumbnail of the specified size +void FolderModelItem::removeThumbnail(int size) { + QVector::iterator it; + for(it = thumbnails.begin(); it != thumbnails.end(); ++it) { + if(it->size == size) { // an image of the same size is found + thumbnails.erase(it); + break; + } + } +} + +#if 0 +// cache the thumbnail of the specified size in the folder item +void FolderModelItem::setThumbnail(int size, QImage image) { + QVector::iterator it; + for(it = thumbnails.begin(); it != thumbnails.end(); ++it) { + if(it->size == size) { // an image of the same size already exists + it->image = image; // replace it + it->status = ThumbnailLoaded; + break; + } + } + if(it == thumbnails.end()) { // the image is not found + Thumbnail thumbnail; + thumbnail.size = size; + thumbnail.status = ThumbnailLoaded; + thumbnail.image = image; + thumbnails.append(thumbnail); // add a new entry + } +} +#endif diff --git a/libfm-qt/foldermodelitem.h b/libfm-qt/foldermodelitem.h new file mode 100644 index 0000000..7363606 --- /dev/null +++ b/libfm-qt/foldermodelitem.h @@ -0,0 +1,71 @@ +/* + * + * Copyright (C) 2012 Hong Jen Yee (PCMan) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef FM_FOLDERMODELITEM_H +#define FM_FOLDERMODELITEM_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include +#include "icontheme.h" + +namespace Fm { + +class LIBFM_QT_API FolderModelItem { +public: + + enum ThumbnailStatus { + ThumbnailNotChecked, + ThumbnailLoading, + ThumbnailLoaded, + ThumbnailFailed + }; + + struct Thumbnail { + int size; + ThumbnailStatus status; + QImage image; + }; + +public: + FolderModelItem(FmFileInfo* _info); + FolderModelItem(const FolderModelItem& other); + virtual ~FolderModelItem(); + + Thumbnail* findThumbnail(int size); + // void setThumbnail(int size, QImage image); + void removeThumbnail(int size); + + void updateIcon() { + icon = IconTheme::icon(fm_file_info_get_icon(info)); + } + + QString displayName; + QIcon icon; + FmFileInfo* info; + QVector thumbnails; +}; + +} + +#endif // FM_FOLDERMODELITEM_H diff --git a/libfm-qt/folderview.cpp b/libfm-qt/folderview.cpp new file mode 100644 index 0000000..d741128 --- /dev/null +++ b/libfm-qt/folderview.cpp @@ -0,0 +1,928 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "folderview.h" +#include "foldermodel.h" +#include +#include +#include +#include "proxyfoldermodel.h" +#include "folderitemdelegate.h" +#include "dndactionmenu.h" +#include "filemenu.h" +#include "foldermenu.h" +#include "filelauncher.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "folderview_p.h" + +Q_DECLARE_OPAQUE_POINTER(FmFileInfo*) + +namespace Fm { + +FolderViewListView::FolderViewListView(QWidget* parent): + QListView(parent), + activationAllowed_(true) { + connect(this, &QListView::activated, this, &FolderViewListView::activation); +} + +FolderViewListView::~FolderViewListView() { +} + +void FolderViewListView::startDrag(Qt::DropActions supportedActions) { + if(movement() != Static) + QListView::startDrag(supportedActions); + else + QAbstractItemView::startDrag(supportedActions); +} + +void FolderViewListView::mousePressEvent(QMouseEvent* event) { + QListView::mousePressEvent(event); + static_cast(parent())->childMousePressEvent(event); +} + +QModelIndex FolderViewListView::indexAt(const QPoint& point) const { + QModelIndex index = QListView::indexAt(point); + // NOTE: QListView has a severe design flaw here. It does hit-testing based on the + // total bound rect of the item. The width of an item is determined by max(icon_width, text_width). + // So if the text label is much wider than the icon, when you click outside the icon but + // the point is still within the outer bound rect, the item is still selected. + // This results in very poor usability. Let's do precise hit-testing here. + // An item is hit only when the point is in the icon or text label. + // If the point is in the bound rectangle but outside the icon or text, it should not be selected. + if(viewMode() == QListView::IconMode && index.isValid()) { + // FIXME: this hack only improves the usability partially. We still need more precise sizeHint handling. + // FolderItemDelegate* delegate = static_cast(itemDelegateForColumn(FolderModel::ColumnFileName)); + // Q_ASSERT(delegate != NULL); + // We use the grid size - (2, 2) as the size of the bounding rectangle of the whole item. + // The width of the text label hence is gridSize.width - 2, and the width and height of the icon is from iconSize(). + QRect visRect = visualRect(index); // visibal area on the screen + QSize itemSize = gridSize(); + itemSize.setWidth(itemSize.width() - 2); + itemSize.setHeight(itemSize.height() - 2); + QSize _iconSize = iconSize(); + int textHeight = itemSize.height() - _iconSize.height(); + if(point.y() < visRect.bottom() - textHeight) { + // the point is in the icon area, not over the text label + int iconXMargin = (itemSize.width() - _iconSize.width()) / 2; + if(point.x() < (visRect.left() + iconXMargin) || point.x() > (visRect.right() - iconXMargin)) + return QModelIndex(); + } + // qDebug() << "visualRect: " << visRect << "point:" << point; + } + return index; +} + + +// NOTE: +// QListView has a problem which I consider a bug or a design flaw. +// When you set movement property to Static, theoratically the icons +// should not be movable. However, if you turned on icon mode, +// the icons becomes freely movable despite the value of movement is Static. +// To overcome this bug, we override all drag handling methods, and +// call QAbstractItemView directly, bypassing QListView. +// In this way, we can workaround the buggy behavior. +// The drag handlers of QListView basically does the same things +// as its parent QAbstractItemView, but it also stores the currently +// dragged item and paint them in the view as needed. +// TODO: I really should file a bug report to Qt developers. + +void FolderViewListView::dragEnterEvent(QDragEnterEvent* event) { + if(movement() != Static) + QListView::dragEnterEvent(event); + else + QAbstractItemView::dragEnterEvent(event); + qDebug("dragEnterEvent"); + //static_cast(parent())->childDragEnterEvent(event); +} + +void FolderViewListView::dragLeaveEvent(QDragLeaveEvent* e) { + if(movement() != Static) + QListView::dragLeaveEvent(e); + else + QAbstractItemView::dragLeaveEvent(e); + static_cast(parent())->childDragLeaveEvent(e); +} + +void FolderViewListView::dragMoveEvent(QDragMoveEvent* e) { + if(movement() != Static) + QListView::dragMoveEvent(e); + else + QAbstractItemView::dragMoveEvent(e); + static_cast(parent())->childDragMoveEvent(e); +} + +void FolderViewListView::dropEvent(QDropEvent* e) { + + static_cast(parent())->childDropEvent(e); + + if(movement() != Static) + QListView::dropEvent(e); + else + QAbstractItemView::dropEvent(e); +} + +void FolderViewListView::mouseReleaseEvent(QMouseEvent* event) { + bool activationWasAllowed = activationAllowed_; + if ((!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, NULL, this)) || (event->button() != Qt::LeftButton)) { + activationAllowed_ = false; + } + + QListView::mouseReleaseEvent(event); + + activationAllowed_ = activationWasAllowed; +} + +void FolderViewListView::mouseDoubleClickEvent(QMouseEvent* event) { + bool activationWasAllowed = activationAllowed_; + if ((style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, NULL, this)) || (event->button() != Qt::LeftButton)) { + activationAllowed_ = false; + } + + QListView::mouseDoubleClickEvent(event); + + activationAllowed_ = activationWasAllowed; +} + +void FolderViewListView::activation(const QModelIndex &index) { + if (activationAllowed_) { + Q_EMIT activatedFiltered(index); + } +} + +//----------------------------------------------------------------------------- + +FolderViewTreeView::FolderViewTreeView(QWidget* parent): + QTreeView(parent), + layoutTimer_(NULL), + doingLayout_(false), + activationAllowed_(true) { + + header()->setStretchLastSection(false); + setIndentation(0); + + connect(this, &QTreeView::activated, this, &FolderViewTreeView::activation); +} + +FolderViewTreeView::~FolderViewTreeView() { + if(layoutTimer_) + delete layoutTimer_; +} + +void FolderViewTreeView::setModel(QAbstractItemModel* model) { + QTreeView::setModel(model); + layoutColumns(); +} + +void FolderViewTreeView::mousePressEvent(QMouseEvent* event) { + QTreeView::mousePressEvent(event); + static_cast(parent())->childMousePressEvent(event); +} + +void FolderViewTreeView::dragEnterEvent(QDragEnterEvent* event) { + QTreeView::dragEnterEvent(event); + static_cast(parent())->childDragEnterEvent(event); +} + +void FolderViewTreeView::dragLeaveEvent(QDragLeaveEvent* e) { + QTreeView::dragLeaveEvent(e); + static_cast(parent())->childDragLeaveEvent(e); +} + +void FolderViewTreeView::dragMoveEvent(QDragMoveEvent* e) { + QTreeView::dragMoveEvent(e); + static_cast(parent())->childDragMoveEvent(e); +} + +void FolderViewTreeView::dropEvent(QDropEvent* e) { + static_cast(parent())->childDropEvent(e); + QTreeView::dropEvent(e); +} + +// the default list mode of QListView handles column widths +// very badly (worse than gtk+) and it's not very flexible. +// so, let's handle column widths outselves. +void FolderViewTreeView::layoutColumns() { + // qDebug("layoutColumns"); + if(!model()) + return; + doingLayout_ = true; + QHeaderView* headerView = header(); + // the width that's available for showing the columns. + int availWidth = viewport()->contentsRect().width(); + int desiredWidth = 0; + + // get the width that every column want + int numCols = headerView->count(); + int* widths = new int[numCols]; // array to store the widths every column needs + int column; + for(column = 0; column < numCols; ++column) { + int columnId = headerView->logicalIndex(column); + // get the size that the column needs + widths[column] = sizeHintForColumn(columnId); + } + + // the best case is every column can get its full width + for(column = 0; column < numCols; ++column) { + desiredWidth += widths[column]; + } + + // if the total witdh we want exceeds the available space + if(desiredWidth > availWidth) { + // we don't have that much space for every column + int filenameColumn = headerView->visualIndex(FolderModel::ColumnFileName); + // shrink the filename column first + desiredWidth -= widths[filenameColumn]; // total width of all other columns + + // see if setting the width of the filename column to 200 solve the problem + if(desiredWidth + 200 > availWidth) { + // even when we reduce the width of the filename column to 200, + // the available space is not enough. So we give up trying. + widths[filenameColumn] = 200; + desiredWidth += 200; + } + else { // we still have more space, so the width of filename column can be increased + // expand the filename column to fill all available space. + widths[filenameColumn] = availWidth - desiredWidth; + desiredWidth = availWidth; + } + } + + // really do the resizing for every column + for(int column = 0; column < numCols; ++column) { + headerView->resizeSection(column, widths[column]); + } + + delete []widths; + doingLayout_ = false; + + if(layoutTimer_) { + delete layoutTimer_; + layoutTimer_ = NULL; + } +} + +void FolderViewTreeView::resizeEvent(QResizeEvent* event) { + QAbstractItemView::resizeEvent(event); + if(!doingLayout_) // prevent endless recursion. + layoutColumns(); // layoutColumns() also triggers resizeEvent +} + +void FolderViewTreeView::rowsInserted(const QModelIndex& parent, int start, int end) { + QTreeView::rowsInserted(parent, start, end); + queueLayoutColumns(); +} + +void FolderViewTreeView::rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { + QTreeView::rowsAboutToBeRemoved(parent, start, end); + queueLayoutColumns(); +} + +void FolderViewTreeView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { + QTreeView::dataChanged(topLeft, bottomRight); + // FIXME: this will be very inefficient + // queueLayoutColumns(); +} + +void FolderViewTreeView::queueLayoutColumns() { + // qDebug("queueLayoutColumns"); + if(!layoutTimer_) { + layoutTimer_ = new QTimer(); + layoutTimer_->setSingleShot(true); + layoutTimer_->setInterval(0); + connect(layoutTimer_, &QTimer::timeout, this, &FolderViewTreeView::layoutColumns); + } + layoutTimer_->start(); +} + +void FolderViewTreeView::mouseReleaseEvent(QMouseEvent* event) { + bool activationWasAllowed = activationAllowed_; + if ((!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, NULL, this)) || (event->button() != Qt::LeftButton)) { + activationAllowed_ = false; + } + + QTreeView::mouseReleaseEvent(event); + + activationAllowed_ = activationWasAllowed; +} + +void FolderViewTreeView::mouseDoubleClickEvent(QMouseEvent* event) { + bool activationWasAllowed = activationAllowed_; + if ((style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, NULL, this)) || (event->button() != Qt::LeftButton)) { + activationAllowed_ = false; + } + + QTreeView::mouseDoubleClickEvent(event); + + activationAllowed_ = activationWasAllowed; +} + +void FolderViewTreeView::activation(const QModelIndex &index) { + if (activationAllowed_) { + Q_EMIT activatedFiltered(index); + } +} + + +//----------------------------------------------------------------------------- + +FolderView::FolderView(ViewMode _mode, QWidget* parent): + QWidget(parent), + view(NULL), + mode((ViewMode)0), + autoSelectionDelay_(600), + autoSelectionTimer_(NULL), + selChangedTimer_(NULL), + fileLauncher_(NULL), + model_(NULL) { + + iconSize_[IconMode - FirstViewMode] = QSize(48, 48); + iconSize_[CompactMode - FirstViewMode] = QSize(24, 24); + iconSize_[ThumbnailMode - FirstViewMode] = QSize(128, 128); + iconSize_[DetailedListMode - FirstViewMode] = QSize(24, 24); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->setMargin(0); + setLayout(layout); + + setViewMode(_mode); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + connect(this, &FolderView::clicked, this, &FolderView::onFileClicked); +} + +FolderView::~FolderView() { + // qDebug("delete FolderView"); +} + +void FolderView::onItemActivated(QModelIndex index) { + if(index.isValid() && index.model()) { + QVariant data = index.model()->data(index, FolderModel::FileInfoRole); + FmFileInfo* info = (FmFileInfo*)data.value(); + if(info) { + if (!(QApplication::keyboardModifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { + Q_EMIT clicked(ActivatedClick, info); + } + } + } +} + +void FolderView::onSelChangedTimeout() { + selChangedTimer_->deleteLater(); + selChangedTimer_ = NULL; + + QItemSelectionModel* selModel = selectionModel(); + int nSel = 0; + if(viewMode() == DetailedListMode) + nSel = selModel->selectedRows().count(); + else { + nSel = selModel->selectedIndexes().count(); + } + // qDebug()<<"selected:" << nSel; + Q_EMIT selChanged(nSel); // FIXME: this is inefficient +} + +void FolderView::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { + // It's possible that the selected items change too often and this slot gets called for thousands of times. + // For example, when you select thousands of files and delete them, we will get one selectionChanged() event + // for every deleted file. So, we use a timer to delay the handling to avoid too frequent updates of the UI. + if(!selChangedTimer_) { + selChangedTimer_ = new QTimer(this); + selChangedTimer_->setSingleShot(true); + connect(selChangedTimer_, &QTimer::timeout, this, &FolderView::onSelChangedTimeout); + selChangedTimer_->start(200); + } +} + + +void FolderView::setViewMode(ViewMode _mode) { + if(_mode == mode) // if it's the same more, ignore + return; + // FIXME: retain old selection + + // since only detailed list mode uses QTreeView, and others + // all use QListView, it's wise to preserve QListView when possible. + bool recreateView = false; + if(view && (mode == DetailedListMode || _mode == DetailedListMode)) { + delete view; // FIXME: no virtual dtor? + view = NULL; + recreateView = true; + } + mode = _mode; + QSize iconSize = iconSize_[mode - FirstViewMode]; + + if(mode == DetailedListMode) { + FolderViewTreeView* treeView = new FolderViewTreeView(this); + connect(treeView, &FolderViewTreeView::activatedFiltered, this, &FolderView::onItemActivated); + + view = treeView; + treeView->setItemsExpandable(false); + treeView->setRootIsDecorated(false); + treeView->setAllColumnsShowFocus(false); + + // set our own custom delegate + FolderItemDelegate* delegate = new FolderItemDelegate(treeView); + treeView->setItemDelegateForColumn(FolderModel::ColumnFileName, delegate); + } + else { + FolderViewListView* listView; + if(view) + listView = static_cast(view); + else { + listView = new FolderViewListView(this); + connect(listView, &FolderViewListView::activatedFiltered, this, &FolderView::onItemActivated); + view = listView; + } + // set our own custom delegate + FolderItemDelegate* delegate = new FolderItemDelegate(listView); + listView->setItemDelegateForColumn(FolderModel::ColumnFileName, delegate); + // FIXME: should we expose the delegate? + listView->setMovement(QListView::Static); + listView->setResizeMode(QListView::Adjust); + listView->setWrapping(true); + switch(mode) { + case IconMode: { + listView->setViewMode(QListView::IconMode); + listView->setWordWrap(true); + listView->setFlow(QListView::LeftToRight); + break; + } + case CompactMode: { + listView->setViewMode(QListView::ListMode); + listView->setWordWrap(false); + listView->setFlow(QListView::QListView::TopToBottom); + break; + } + case ThumbnailMode: { + listView->setViewMode(QListView::IconMode); + listView->setWordWrap(true); + listView->setFlow(QListView::LeftToRight); + break; + } + default:; + } + updateGridSize(); + } + if(view) { + // we have to install the event filter on the viewport instead of the view itself. + view->viewport()->installEventFilter(this); + // we want the QEvent::HoverMove event for single click + auto-selection support + view->viewport()->setAttribute(Qt::WA_Hover, true); + view->setContextMenuPolicy(Qt::NoContextMenu); // defer the context menu handling to parent widgets + view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + view->setIconSize(iconSize); + + view->setSelectionMode(QAbstractItemView::ExtendedSelection); + layout()->addWidget(view); + + // enable dnd + view->setDragEnabled(true); + view->setAcceptDrops(true); + view->setDragDropMode(QAbstractItemView::DragDrop); + view->setDropIndicatorShown(true); + + if(model_) { + // FIXME: preserve selections + model_->setThumbnailSize(iconSize.width()); + view->setModel(model_); + if(recreateView) + connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FolderView::onSelectionChanged); + } + } +} + +// set proper grid size for the QListView based on current view mode, icon size, and font size. +void FolderView::updateGridSize() { + if(mode == DetailedListMode || !view) + return; + FolderViewListView* listView = static_cast(view); + QSize icon = iconSize(mode); // size of the icon + QFontMetrics fm = fontMetrics(); // size of current font + QSize grid; // the final grid size + switch(mode) { + case IconMode: + case ThumbnailMode: { + // NOTE by PCMan about finding the optimal text label size: + // The average filename length on my root filesystem is roughly 18-20 chars. + // So, a reasonable size for the text label is about 10 chars each line since string of this length + // can be shown in two lines. If you consider word wrap, then the result is around 10 chars per word. + // In average, 10 char per line should be enough to display a "word" in the filename without breaking. + // The values can be estimated with this command: + // > find / | xargs basename -a | sed -e s'/[_-]/ /g' | wc -mcw + // However, this average only applies to English. For some Asian characters, such as Chinese chars, + // each char actually takes doubled space. To be safe, we use 13 chars per line x average char width + // to get a nearly optimal width for the text label. As most of the filenames have less than 40 chars + // 13 chars x 3 lines should be enough to show the full filenames for most files. + int textWidth = fm.averageCharWidth() * 12 + 4; // add 2 px padding for left and right border + int textHeight = fm.height() * 3 + 4; // add 2 px padding for top and bottom border + grid.setWidth(qMax(icon.width(), textWidth) + 8); // add a margin 4 px for every cell + grid.setHeight(icon.height() + textHeight + 8); // add a margin 4 px for every cell + break; + } + default: + ; // do not use grid size + } + listView->setGridSize(grid); + FolderItemDelegate* delegate = static_cast(listView->itemDelegateForColumn(FolderModel::ColumnFileName)); + delegate->setGridSize(grid); +} + +void FolderView::setIconSize(ViewMode mode, QSize size) { + Q_ASSERT(mode >= FirstViewMode && mode <= LastViewMode); + iconSize_[mode - FirstViewMode] = size; + if(viewMode() == mode) { + view->setIconSize(size); + if(model_) + model_->setThumbnailSize(size.width()); + updateGridSize(); + } +} + +QSize FolderView::iconSize(ViewMode mode) const { + Q_ASSERT(mode >= FirstViewMode && mode <= LastViewMode); + return iconSize_[mode - FirstViewMode]; +} + +FolderView::ViewMode FolderView::viewMode() const { + return mode; +} + +void FolderView::setAutoSelectionDelay(int delay) { + autoSelectionDelay_ = delay; +} + +QAbstractItemView* FolderView::childView() const { + return view; +} + +ProxyFolderModel* FolderView::model() const { + return model_; +} + +void FolderView::setModel(ProxyFolderModel* model) { + if(view) { + view->setModel(model); + QSize iconSize = iconSize_[mode - FirstViewMode]; + model->setThumbnailSize(iconSize.width()); + if(view->selectionModel()) + connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FolderView::onSelectionChanged); + } + if(model_) + delete model_; + model_ = model; +} + +bool FolderView::event(QEvent* event) { + switch(event->type()) { + case QEvent::StyleChange: + break; + case QEvent::FontChange: + updateGridSize(); + break; + }; + return QWidget::event(event); +} + +void FolderView::contextMenuEvent(QContextMenuEvent* event) { + QWidget::contextMenuEvent(event); + QPoint pos = event->pos(); + QPoint view_pos = view->mapFromParent(pos); + QPoint viewport_pos = view->viewport()->mapFromParent(view_pos); + emitClickedAt(ContextMenuClick, viewport_pos); +} + +void FolderView::childMousePressEvent(QMouseEvent* event) { + // called from mousePressEvent() of child view + if(event->button() == Qt::MiddleButton) { + emitClickedAt(MiddleClick, event->pos()); + } +} + +void FolderView::emitClickedAt(ClickType type, const QPoint& pos) { + // indexAt() needs a point in "viewport" coordinates. + QModelIndex index = view->indexAt(pos); + if(index.isValid()) { + QVariant data = index.data(FolderModel::FileInfoRole); + FmFileInfo* info = reinterpret_cast(data.value()); + Q_EMIT clicked(type, info); + } + else { + // FIXME: should we show popup menu for the selected files instead + // if there are selected files? + if(type == ContextMenuClick) { + // clear current selection if clicked outside selected files + view->clearSelection(); + Q_EMIT clicked(type, NULL); + } + } +} + +QModelIndexList FolderView::selectedRows(int column) const { + QItemSelectionModel* selModel = selectionModel(); + if(selModel) { + return selModel->selectedRows(column); + } + return QModelIndexList(); +} + +// This returns all selected "cells", which means all cells of the same row are returned. +QModelIndexList FolderView::selectedIndexes() const { + QItemSelectionModel* selModel = selectionModel(); + if(selModel) { + return selModel->selectedIndexes(); + } + return QModelIndexList(); +} + +QItemSelectionModel* FolderView::selectionModel() const { + return view ? view->selectionModel() : NULL; +} + +FmPathList* FolderView::selectedFilePaths() const { + if(model_) { + QModelIndexList selIndexes = mode == DetailedListMode ? selectedRows() : selectedIndexes(); + if(!selIndexes.isEmpty()) { + FmPathList* paths = fm_path_list_new(); + QModelIndexList::const_iterator it; + for(it = selIndexes.begin(); it != selIndexes.end(); ++it) { + FmFileInfo* file = model_->fileInfoFromIndex(*it); + fm_path_list_push_tail(paths, fm_file_info_get_path(file)); + } + return paths; + } + } + return NULL; +} + +FmFileInfoList* FolderView::selectedFiles() const { + if(model_) { + QModelIndexList selIndexes = mode == DetailedListMode ? selectedRows() : selectedIndexes(); + if(!selIndexes.isEmpty()) { + FmFileInfoList* files = fm_file_info_list_new(); + QModelIndexList::const_iterator it; + for(it = selIndexes.constBegin(); it != selIndexes.constEnd(); it++) { + FmFileInfo* file = model_->fileInfoFromIndex(*it); + fm_file_info_list_push_tail(files, file); + } + return files; + } + } + return NULL; +} + +void FolderView::selectAll() { + if(mode == DetailedListMode) + view->selectAll(); + else { + // NOTE: By default QListView::selectAll() selects all columns in the model. + // However, QListView only show the first column. Normal selection by mouse + // can only select the first column of every row. I consider this discripancy yet + // another design flaw of Qt. To make them consistent, we do it ourselves by only + // selecting the first column of every row and do not select all columns as Qt does. + // This will trigger one selectionChanged event per row, which is very inefficient, + // but we have no other choices to workaround the Qt bug. + // I'll report a Qt bug for this later. + if(model_) { + int rowCount = model_->rowCount(); + for(int row = 0; row < rowCount; ++row) { + QModelIndex index = model_->index(row, 0); + selectionModel()->select(index, QItemSelectionModel::Select); + } + } + } +} + +void FolderView::invertSelection() { + if(model_) { + QItemSelectionModel* selModel = view->selectionModel(); + int rows = model_->rowCount(); + QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Toggle; + if(mode == DetailedListMode) + flags |= QItemSelectionModel::Rows; + for(int row = 0; row < rows; ++row) { + QModelIndex index = model_->index(row, 0); + selModel->select(index, flags); + } + } +} + +void FolderView::childDragEnterEvent(QDragEnterEvent* event) { + qDebug("drag enter"); + if(event->mimeData()->hasFormat("text/uri-list")) { + event->accept(); + } + else + event->ignore(); +} + +void FolderView::childDragLeaveEvent(QDragLeaveEvent* e) { + qDebug("drag leave"); + e->accept(); +} + +void FolderView::childDragMoveEvent(QDragMoveEvent* e) { + qDebug("drag move"); +} + +void FolderView::childDropEvent(QDropEvent* e) { + qDebug("drop"); + if(e->keyboardModifiers() == Qt::NoModifier) { + // if no key modifiers are used, popup a menu + // to ask the user for the action he/she wants to perform. + Qt::DropAction action = DndActionMenu::askUser(QCursor::pos()); + e->setDropAction(action); + } +} + +bool FolderView::eventFilter(QObject* watched, QEvent* event) { + // NOTE: Instead of simply filtering the drag and drop events of the child view in + // the event filter, we overrided each event handler virtual methods in + // both QListView and QTreeView and added some childXXXEvent() callbacks. + // We did this because of a design flaw of Qt. + // All QAbstractScrollArea derived widgets, including QAbstractItemView + // contains an internal child widget, which is called a viewport. + // The events actually comes from the child viewport, not the parent view itself. + // Qt redirects the events of viewport to the viewportEvent() method of + // QAbstractScrollArea and let the parent widget handle the events. + // Qt implemented this using a event filter installed on the child viewport widget. + // That means, when we try to install an event filter on the viewport, + // there is already a filter installed by Qt which will be called before ours. + // So we can never intercept the event handling of QAbstractItemView by using a filter. + // That's why we override respective virtual methods for different events. + if(view && watched == view->viewport()) { + switch(event->type()) { + case QEvent::HoverMove: + // activate items on single click + if(style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) { + QHoverEvent* hoverEvent = static_cast(event); + QModelIndex index = view->indexAt(hoverEvent->pos()); // find out the hovered item + if(index.isValid()) { // change the cursor to a hand when hovering on an item + setCursor(Qt::PointingHandCursor); + if(!selectionModel()->hasSelection()) + selectionModel()->setCurrentIndex(index, QItemSelectionModel::Current); + } + else + setCursor(Qt::ArrowCursor); + // turn on auto-selection for hovered item when single click mode is used. + if(autoSelectionDelay_ > 0 && model_) { + if(!autoSelectionTimer_) { + autoSelectionTimer_ = new QTimer(this); + connect(autoSelectionTimer_, &QTimer::timeout, this, &FolderView::onAutoSelectionTimeout); + lastAutoSelectionIndex_ = QModelIndex(); + } + autoSelectionTimer_->start(autoSelectionDelay_); + } + break; + } + case QEvent::HoverLeave: + if(style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) + setCursor(Qt::ArrowCursor); + break; + case QEvent::Wheel: + // This is to fix #85: Scrolling doesn't work in compact view + // Actually, I think it's the bug of Qt, not ours. + // When in compact mode, only the horizontal scroll bar is used and the vertical one is hidden. + // So, when a user scroll his mouse wheel, it's reasonable to scroll the horizontal scollbar. + // Qt does not implement such a simple feature, unfortunately. + // We do it by forwarding the scroll event in the viewport to the horizontal scrollbar. + // FIXME: if someday Qt supports this, we have to disable the workaround. + if(mode == CompactMode) { + QScrollBar* scroll = view->horizontalScrollBar(); + if(scroll) { + QApplication::sendEvent(scroll, event); + return true; + } + } + break; + } + } + return QObject::eventFilter(watched, event); +} + +// this slot handles auto-selection of items. +void FolderView::onAutoSelectionTimeout() { + if(QApplication::mouseButtons() != Qt::NoButton) + return; + + Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); + QPoint pos = view->viewport()->mapFromGlobal(QCursor::pos()); // convert to viewport coordinates + QModelIndex index = view->indexAt(pos); // find out the hovered item + QItemSelectionModel::SelectionFlags flags = (mode == DetailedListMode ? QItemSelectionModel::Rows : QItemSelectionModel::NoUpdate); + QItemSelectionModel* selModel = view->selectionModel(); + + if(mods & Qt::ControlModifier) { // Ctrl key is pressed + if(selModel->isSelected(index) && index != lastAutoSelectionIndex_) { + // unselect a previously selected item + selModel->select(index, flags|QItemSelectionModel::Deselect); + lastAutoSelectionIndex_ = QModelIndex(); + } + else { + // select an unselected item + selModel->select(index, flags|QItemSelectionModel::Select); + lastAutoSelectionIndex_ = index; + } + selModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); // move the cursor + } + else if(mods & Qt::ShiftModifier) { // Shift key is pressed + // select all items between current index and the hovered index. + QModelIndex current = selModel->currentIndex(); + if(selModel->hasSelection() && current.isValid()) { + selModel->clear(); // clear old selection + selModel->setCurrentIndex(current, QItemSelectionModel::NoUpdate); + int begin = current.row(); + int end = index.row(); + if(begin > end) + qSwap(begin, end); + for(int row = begin; row <= end; ++row) { + QModelIndex sel = model_->index(row, 0); + selModel->select(sel, flags|QItemSelectionModel::Select); + } + } + else { // no items are selected, select the hovered item. + if(index.isValid()) { + selModel->select(index, flags|QItemSelectionModel::SelectCurrent); + selModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + } + } + lastAutoSelectionIndex_ = index; + } + else if(mods == Qt::NoModifier) { // no modifier keys are pressed. + if(index.isValid()) { + // select the hovered item + view->clearSelection(); + selModel->select(index, flags|QItemSelectionModel::SelectCurrent); + selModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); + } + lastAutoSelectionIndex_ = index; + } + + autoSelectionTimer_->deleteLater(); + autoSelectionTimer_ = NULL; +} + +void FolderView::onFileClicked(int type, FmFileInfo* fileInfo) { + if(type == ActivatedClick) { + if(fileLauncher_) { + GList* files = g_list_append(NULL, fileInfo); + fileLauncher_->launchFiles(NULL, files); + g_list_free(files); + } + } + else if(type == ContextMenuClick) { + FmPath* folderPath = path(); + QMenu* menu = NULL; + if(fileInfo) { + // show context menu + if (FmFileInfoList* files = selectedFiles()) { + Fm::FileMenu* fileMenu = new Fm::FileMenu(files, fileInfo, folderPath); + fileMenu->setFileLauncher(fileLauncher_); + prepareFileMenu(fileMenu); + fm_file_info_list_unref(files); + menu = fileMenu; + } + } + else { + FmFolder* _folder = folder(); + FmFileInfo* info = fm_folder_get_info(_folder); + Fm::FolderMenu* folderMenu = new Fm::FolderMenu(this); + prepareFolderMenu(folderMenu); + menu = folderMenu; + } + if (menu) { + menu->popup(QCursor::pos()); + connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); + } + } +} + +void FolderView::prepareFileMenu(FileMenu* menu) { +} + +void FolderView::prepareFolderMenu(FolderMenu* menu) { +} + + +} // namespace Fm diff --git a/libfm-qt/folderview.h b/libfm-qt/folderview.h new file mode 100644 index 0000000..33d7f7b --- /dev/null +++ b/libfm-qt/folderview.h @@ -0,0 +1,167 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_FOLDERVIEW_H +#define FM_FOLDERVIEW_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include +#include "foldermodel.h" +#include "proxyfoldermodel.h" + +class QTimer; + +namespace Fm { + +class FileMenu; +class FolderMenu; +class FileLauncher; +class FolderViewStyle; + +class LIBFM_QT_API FolderView : public QWidget { + Q_OBJECT + +public: + enum ViewMode { + FirstViewMode = 1, + IconMode = FirstViewMode, + CompactMode, + DetailedListMode, + ThumbnailMode, + LastViewMode = ThumbnailMode, + NumViewModes = (LastViewMode - FirstViewMode + 1) + }; + + enum ClickType { + ActivatedClick, + MiddleClick, + ContextMenuClick + }; + +public: + + friend class FolderViewTreeView; + friend class FolderViewListView; + + explicit FolderView(ViewMode _mode = IconMode, QWidget* parent = 0); + virtual ~FolderView(); + + void setViewMode(ViewMode _mode); + ViewMode viewMode() const; + + void setIconSize(ViewMode mode, QSize size); + QSize iconSize(ViewMode mode) const; + + QAbstractItemView* childView() const; + + ProxyFolderModel* model() const; + void setModel(ProxyFolderModel* _model); + + FmFolder* folder() { + return model_ ? static_cast(model_->sourceModel())->folder() : NULL; + } + + FmFileInfo* folderInfo() { + FmFolder* _folder = folder(); + return _folder ? fm_folder_get_info(_folder) : NULL; + } + + FmPath* path() { + FmFolder* _folder = folder(); + return _folder ? fm_folder_get_path(_folder) : NULL; + } + + QItemSelectionModel* selectionModel() const; + FmFileInfoList* selectedFiles() const; + FmPathList* selectedFilePaths() const; + + void selectAll(); + + void invertSelection(); + + void setFileLauncher(FileLauncher* launcher) { + fileLauncher_ = launcher; + } + + FileLauncher* fileLauncher() { + return fileLauncher_; + } + + int autoSelectionDelay() const { + return autoSelectionDelay_; + } + + void setAutoSelectionDelay(int delay); + +protected: + virtual bool event(QEvent* event); + virtual void contextMenuEvent(QContextMenuEvent* event); + virtual void childMousePressEvent(QMouseEvent* event); + virtual void childDragEnterEvent(QDragEnterEvent* event); + virtual void childDragMoveEvent(QDragMoveEvent* e); + virtual void childDragLeaveEvent(QDragLeaveEvent* e); + virtual void childDropEvent(QDropEvent* e); + + void emitClickedAt(ClickType type, const QPoint& pos); + + QModelIndexList selectedRows ( int column = 0 ) const; + QModelIndexList selectedIndexes() const; + + virtual void prepareFileMenu(Fm::FileMenu* menu); + virtual void prepareFolderMenu(Fm::FolderMenu* menu); + + virtual bool eventFilter(QObject* watched, QEvent* event); + + void updateGridSize(); // called when view mode, icon size, or font size is changed + +public Q_SLOTS: + void onItemActivated(QModelIndex index); + void onSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + virtual void onFileClicked(int type, FmFileInfo* fileInfo); + +private Q_SLOTS: + void onAutoSelectionTimeout(); + void onSelChangedTimeout(); + +Q_SIGNALS: + void clicked(int type, FmFileInfo* file); + void selChanged(int n_sel); + void sortChanged(); + +private: + + QAbstractItemView* view; + ProxyFolderModel* model_; + ViewMode mode; + QSize iconSize_[NumViewModes]; + FileLauncher* fileLauncher_; + int autoSelectionDelay_; + QTimer* autoSelectionTimer_; + QModelIndex lastAutoSelectionIndex_; + QTimer* selChangedTimer_; +}; + +} + +#endif // FM_FOLDERVIEW_H diff --git a/libfm-qt/folderview_p.h b/libfm-qt/folderview_p.h new file mode 100644 index 0000000..38944e2 --- /dev/null +++ b/libfm-qt/folderview_p.h @@ -0,0 +1,107 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_FOLDERVIEW_P_H +#define FM_FOLDERVIEW_P_H + +#include +#include +#include +#include "folderview.h" + +class QTimer; + +namespace Fm { + +// override these classes for implementing FolderView +class FolderViewListView : public QListView { + Q_OBJECT +public: + friend class FolderView; + FolderViewListView(QWidget* parent = 0); + virtual ~FolderViewListView(); + virtual void startDrag(Qt::DropActions supportedActions); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void mouseDoubleClickEvent(QMouseEvent* event); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragMoveEvent(QDragMoveEvent* e); + virtual void dragLeaveEvent(QDragLeaveEvent* e); + virtual void dropEvent(QDropEvent* e); + + virtual QModelIndex indexAt(const QPoint & point) const; + + inline void setPositionForIndex(const QPoint & position, const QModelIndex & index) { + QListView::setPositionForIndex(position, index); + } + + inline QRect rectForIndex(const QModelIndex & index) const { + return QListView::rectForIndex(index); + } + +Q_SIGNALS: + void activatedFiltered(const QModelIndex &index); + +private Q_SLOTS: + void activation(const QModelIndex &index); + +private: + bool activationAllowed_; +}; + +class FolderViewTreeView : public QTreeView { + Q_OBJECT +public: + friend class FolderView; + FolderViewTreeView(QWidget* parent = 0); + virtual ~FolderViewTreeView(); + virtual void setModel(QAbstractItemModel* model); + virtual void mousePressEvent(QMouseEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void mouseDoubleClickEvent(QMouseEvent* event); + virtual void dragEnterEvent(QDragEnterEvent* event); + virtual void dragMoveEvent(QDragMoveEvent* e); + virtual void dragLeaveEvent(QDragLeaveEvent* e); + virtual void dropEvent(QDropEvent* e); + + virtual void rowsInserted(const QModelIndex& parent,int start, int end); + virtual void rowsAboutToBeRemoved(const QModelIndex& parent,int start, int end); + virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + virtual void resizeEvent(QResizeEvent* event); + void queueLayoutColumns(); + +Q_SIGNALS: + void activatedFiltered(const QModelIndex &index); + +private Q_SLOTS: + void layoutColumns(); + void activation(const QModelIndex &index); + +private: + bool doingLayout_; + QTimer* layoutTimer_; + bool activationAllowed_; +}; + + +} // namespace Fm + +#endif // FM_FOLDERVIEW_P_H diff --git a/libfm-qt/fontbutton.cpp b/libfm-qt/fontbutton.cpp new file mode 100644 index 0000000..bfb7a15 --- /dev/null +++ b/libfm-qt/fontbutton.cpp @@ -0,0 +1,55 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "fontbutton.h" +#include +#include + +using namespace Fm; + +FontButton::FontButton(QWidget* parent): QPushButton(parent) { + connect(this, &QPushButton::clicked, this, &FontButton::onClicked); +} + +FontButton::~FontButton() { +} + +void FontButton::onClicked() { + QFontDialog dlg(font_); + if(dlg.exec() == QDialog::Accepted) { + setFont(dlg.selectedFont()); + } +} + +void FontButton::setFont(QFont font) { + font_ = font; + QString text = font.family(); + if(font.bold()) { + text += " "; + text += tr("Bold"); + } + if(font.italic()) { + text += " "; + text += tr("Italic"); + } + text += QString(" %1").arg(font.pointSize()); + setText(text); + Q_EMIT changed(); +} diff --git a/libfm-qt/fontbutton.h b/libfm-qt/fontbutton.h new file mode 100644 index 0000000..bba7d45 --- /dev/null +++ b/libfm-qt/fontbutton.h @@ -0,0 +1,54 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_FONTBUTTON_H +#define FM_FONTBUTTON_H + +#include "libfmqtglobals.h" +#include + + +namespace Fm { + +class LIBFM_QT_API FontButton : public QPushButton { +Q_OBJECT +public: + explicit FontButton(QWidget* parent = 0); + virtual ~FontButton(); + + QFont font() { + return font_; + } + + void setFont(QFont font); + +Q_SIGNALS: + void changed(); + +private Q_SLOTS: + void onClicked(); + +private: + QFont font_; +}; + +} + +#endif // FM_FONTBUTTON_H diff --git a/libfm-qt/icontheme.cpp b/libfm-qt/icontheme.cpp new file mode 100644 index 0000000..a8b6b86 --- /dev/null +++ b/libfm-qt/icontheme.cpp @@ -0,0 +1,143 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "icontheme.h" +#include +#include +#include +#include +#include +#include + +using namespace Fm; + +static IconTheme* theIconTheme = NULL; // the global single instance of IconTheme. +static const char* fallbackNames[] = {"unknown", "application-octet-stream", NULL}; + +static void fmIconDataDestroy(gpointer data) { + QIcon* picon = reinterpret_cast(data); + delete picon; +} + +IconTheme::IconTheme(): + currentThemeName_(QIcon::themeName()) { + // NOTE: only one instance is allowed + Q_ASSERT(theIconTheme == NULL); + Q_ASSERT(qApp != NULL); // QApplication should exists before contructing IconTheme. + + theIconTheme = this; + fm_icon_set_user_data_destroy(reinterpret_cast(fmIconDataDestroy)); + fallbackIcon_ = iconFromNames(fallbackNames); + + // We need to get notified when there is a QEvent::StyleChange event so + // we can check if the current icon theme name is changed. + // To do this, we can filter QApplication object itself to intercept + // signals of all widgets, but this may be too inefficient. + // So, we only filter the events on QDesktopWidget instead. + qApp->desktop()->installEventFilter(this); +} + +IconTheme::~IconTheme() { +} + +IconTheme* IconTheme::instance() { + return theIconTheme; +} + +// check if the icon theme name is changed and emit "changed()" signal if any change is detected. +void IconTheme::checkChanged() { + if(QIcon::themeName() != theIconTheme->currentThemeName_) { + // if the icon theme is changed + theIconTheme->currentThemeName_ = QIcon::themeName(); + // invalidate the cached data + fm_icon_reset_user_data_cache(fm_qdata_id); + + theIconTheme->fallbackIcon_ = iconFromNames(fallbackNames); + Q_EMIT theIconTheme->changed(); + } +} + +QIcon IconTheme::iconFromNames(const char* const* names) { + const gchar* const* name; + // qDebug("names: %p", names); + for(name = names; *name; ++name) { + // qDebug("icon name=%s", *name); + QString qname = *name; + QIcon qicon = QIcon::fromTheme(qname); + if(!qicon.isNull()) { + return qicon; + } + } + return QIcon(); +} + +QIcon IconTheme::convertFromGIcon(GIcon* gicon) { + if(G_IS_THEMED_ICON(gicon)) { + const gchar * const * names = g_themed_icon_get_names(G_THEMED_ICON(gicon)); + QIcon icon = iconFromNames(names); + if(!icon.isNull()) + return icon; + } + else if(G_IS_FILE_ICON(gicon)) { + GFile* file = g_file_icon_get_file(G_FILE_ICON(gicon)); + char* fpath = g_file_get_path(file); + QString path = fpath; + g_free(fpath); + return QIcon(path); + } + return theIconTheme->fallbackIcon_; +} + + +//static +QIcon IconTheme::icon(FmIcon* fmicon) { + // check if we have a cached version + QIcon* picon = reinterpret_cast(fm_icon_get_user_data(fmicon)); + if(!picon) { // we don't have a cache yet + picon = new QIcon(); // what a waste! + *picon = convertFromGIcon(G_ICON(fmicon)); + fm_icon_set_user_data(fmicon, picon); // store it in FmIcon + } + return *picon; +} + +//static +QIcon IconTheme::icon(GIcon* gicon) { + if(G_IS_THEMED_ICON(gicon)) { + FmIcon* fmicon = fm_icon_from_gicon(gicon); + QIcon qicon = icon(fmicon); + fm_icon_unref(fmicon); + return qicon; + } + else if(G_IS_FILE_ICON(gicon)) { + // we do not map GFileIcon to FmIcon deliberately. + return convertFromGIcon(gicon); + } + return theIconTheme->fallbackIcon_; +} + +// this method is called whenever there is an event on the QDesktopWidget object. +bool IconTheme::eventFilter(QObject* obj, QEvent* event) { + // we're only interested in the StyleChange event. + if(event->type() == QEvent::StyleChange) { + checkChanged(); // check if the icon theme is changed + } + return QObject::eventFilter(obj, event); +} diff --git a/libfm-qt/icontheme.h b/libfm-qt/icontheme.h new file mode 100644 index 0000000..0b6ddec --- /dev/null +++ b/libfm-qt/icontheme.h @@ -0,0 +1,69 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_ICONTHEME_H +#define FM_ICONTHEME_H + +#include "libfmqtglobals.h" +#include +#include +#include "libfm/fm.h" + +namespace Fm { + +// NOTE: +// Qt seems to has its own QIcon pixmap caching mechanism internally. +// Besides, it also caches QIcon objects created by QIcon::fromTheme(). +// So maybe we should not duplicate the work. +// See http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/image/qicon.cpp +// QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state). +// In addition, QPixmap is actually stored in X11 server, not client side. +// Hence maybe we should not cache too many pixmaps, I guess? +// Let's have Qt do its work and only translate GIcon to QIcon here. + +// Nice article about QPixmap from KDE: http://techbase.kde.org/Development/Tutorials/Graphics/Performance + +class LIBFM_QT_API IconTheme: public QObject { + Q_OBJECT +public: + IconTheme(); + ~IconTheme(); + + static IconTheme* instance(); + static QIcon icon(FmIcon* fmicon); + static QIcon icon(GIcon* gicon); + + static void checkChanged(); // check if current icon theme name is changed +Q_SIGNALS: + void changed(); // emitted when the name of current icon theme is changed + +protected: + bool eventFilter(QObject *obj, QEvent *event); + static QIcon convertFromGIcon(GIcon* gicon); + static QIcon iconFromNames(const char * const * names); + +protected: + QIcon fallbackIcon_; + QString currentThemeName_; +}; + +} + +#endif // FM_ICONTHEME_H diff --git a/libfm-qt/libfm-qt.pc.in b/libfm-qt/libfm-qt.pc.in new file mode 100644 index 0000000..ea71465 --- /dev/null +++ b/libfm-qt/libfm-qt.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libfm-qt +Description: A Qt/glib/gio-based lib used to develop file managers providing some file management utilities. (This is a Qt port of the original libfm library) +URL: http://pcmanfm.sourceforge.net/ +Requires: @REQUIRED_QT@ libfm >= 1.2.0 +Version: @LIBFM_QT_VERSION@ +Libs: -L${libdir} -lfm -l@LIBRARY_NAME@ +Cflags: -I${includedir} diff --git a/libfm-qt/libfmqt.cpp b/libfm-qt/libfmqt.cpp new file mode 100644 index 0000000..769cc4f --- /dev/null +++ b/libfm-qt/libfmqt.cpp @@ -0,0 +1,78 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "libfmqt.h" +#include +#include "icontheme.h" +#include "thumbnailloader.h" + +namespace Fm { + +struct LibFmQtData { + LibFmQtData(); + ~LibFmQtData(); + + IconTheme* iconTheme; + ThumbnailLoader* thumbnailLoader; + QTranslator translator; + int refCount; +}; + +static LibFmQtData* theLibFmData = NULL; + +LibFmQtData::LibFmQtData(): refCount(1) { +#if !GLIB_CHECK_VERSION(2, 36, 0) + g_type_init(); +#endif + fm_init(NULL); + // turn on glib debug message + // g_setenv("G_MESSAGES_DEBUG", "all", true); + iconTheme = new IconTheme(); + thumbnailLoader = new ThumbnailLoader(); + translator.load("libfm-qt_" + QLocale::system().name(), LIBFM_DATA_DIR "/translations"); +} + +LibFmQtData::~LibFmQtData() { + delete iconTheme; + delete thumbnailLoader; + fm_finalize(); +} + +LibFmQt::LibFmQt() { + if(!theLibFmData) { + theLibFmData = new LibFmQtData(); + } + else + ++theLibFmData->refCount; + d = theLibFmData; +} + +LibFmQt::~LibFmQt() { + if(--d->refCount == 0) { + delete d; + theLibFmData = NULL; + } +} + +QTranslator* LibFmQt::translator() { + return &d->translator; +} + +} // namespace Fm diff --git a/libfm-qt/libfmqt.h b/libfm-qt/libfmqt.h new file mode 100644 index 0000000..208f164 --- /dev/null +++ b/libfm-qt/libfmqt.h @@ -0,0 +1,47 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_APPLICATION_H +#define FM_APPLICATION_H + +#include "libfmqtglobals.h" +#include +#include +#include + +namespace Fm { + +struct LibFmQtData; + +class LIBFM_QT_API LibFmQt { +public: + LibFmQt(); + ~LibFmQt(); + + QTranslator* translator(); + +private: + LibFmQt(LibFmQt& other); // disable copy + LibFmQtData* d; +}; + +} + +#endif // FM_APPLICATION_H diff --git a/libfm-qt/libfmqtglobals.h b/libfm-qt/libfmqtglobals.h new file mode 100644 index 0000000..3b3f999 --- /dev/null +++ b/libfm-qt/libfmqtglobals.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _LIBFM_QT_GLOBALS_ +#define _LIBFM_QT_GLOBALS_ + +#include + +#ifdef LIBFM_QT_COMPILATION + #define LIBFM_QT_API Q_DECL_EXPORT +#else + #define LIBFM_QT_API Q_DECL_IMPORT +#endif + +#endif diff --git a/libfm-qt/mount-operation-password.ui b/libfm-qt/mount-operation-password.ui new file mode 100644 index 0000000..75ebf31 --- /dev/null +++ b/libfm-qt/mount-operation-password.ui @@ -0,0 +1,205 @@ + + + MountOperationPasswordDialog + + + + 0 + 0 + 244 + 302 + + + + + 0 + 0 + + + + Mount + + + + + + false + + + false + + + + + + + 0 + 0 + + + + + + + + + + + Connect &anonymously + + + usernameGroup + + + + + + + Connect as u&ser: + + + usernameGroup + + + + + + + + + + + + + 0 + 0 + + + + &Username: + + + username + + + + + + + QLineEdit::Password + + + + + + + + 0 + 0 + + + + &Password: + + + password + + + + + + + &Domain: + + + domain + + + + + + + + + + + + Forget password &immediately + + + passwordGroup + + + + + + + Remember password until you &logout + + + passwordGroup + + + + + + + Remember &forever + + + passwordGroup + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + MountOperationPasswordDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MountOperationPasswordDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + + + diff --git a/libfm-qt/mountoperation.cpp b/libfm-qt/mountoperation.cpp new file mode 100644 index 0000000..469d351 --- /dev/null +++ b/libfm-qt/mountoperation.cpp @@ -0,0 +1,227 @@ +/* + + Copyright (C) 2013 - 2014 Hong Jen Yee (PCMan) + + 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 "mountoperation.h" +#include // for _() +#include +#include +#include +#include "mountoperationpassworddialog_p.h" +#include "mountoperationquestiondialog_p.h" +#include "ui_mount-operation-password.h" + +namespace Fm { + +MountOperation::MountOperation(bool interactive, QWidget* parent): + QObject(parent), + interactive_(interactive), + running(false), + op(g_mount_operation_new()), + cancellable_(g_cancellable_new()), + eventLoop(NULL), + autoDestroy_(true) { + + g_signal_connect(op, "ask-password", G_CALLBACK(onAskPassword), this); + g_signal_connect(op, "ask-question", G_CALLBACK(onAskQuestion), this); + // g_signal_connect(op, "reply", G_CALLBACK(onReply), this); + +#if GLIB_CHECK_VERSION(2, 20, 0) + g_signal_connect(op, "aborted", G_CALLBACK(onAbort), this); +#endif +#if GLIB_CHECK_VERSION(2, 22, 0) + g_signal_connect(op, "show-processes", G_CALLBACK(onShowProcesses), this); +#endif +#if GLIB_CHECK_VERSION(2, 34, 0) + g_signal_connect(op, "show-unmount-progress", G_CALLBACK(onShowUnmountProgress), this); +#endif + +} + +MountOperation::~MountOperation() { + qDebug("delete MountOperation"); + if(cancellable_) { + cancel(); + g_object_unref(cancellable_); + } + + if(eventLoop) { // if wait() is called to block the main loop, but the event loop is still running + // NOTE: is this possible? + eventLoop->exit(1); + } + + if(op) { + g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAskPassword), this); + g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAskQuestion), this); +#if GLIB_CHECK_VERSION(2, 20, 0) + g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onAbort), this); +#endif +#if GLIB_CHECK_VERSION(2, 22, 0) + g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onShowProcesses), this); +#endif +#if GLIB_CHECK_VERSION(2, 34, 0) + g_signal_handlers_disconnect_by_func(op, (gpointer)G_CALLBACK(onShowUnmountProgress), this); +#endif + g_object_unref(op); + } + // qDebug("MountOperation deleted"); +} + +void MountOperation::onAbort(GMountOperation* _op, MountOperation* pThis) { + +} + +void MountOperation::onAskPassword(GMountOperation* _op, gchar* message, gchar* default_user, gchar* default_domain, GAskPasswordFlags flags, MountOperation* pThis) { + qDebug("ask password"); + MountOperationPasswordDialog dlg(pThis, flags); + dlg.setMessage(QString::fromUtf8(message)); + dlg.setDefaultUser(QString::fromUtf8(default_user)); + dlg.setDefaultDomain(QString::fromUtf8(default_domain)); + dlg.exec(); +} + +void MountOperation::onAskQuestion(GMountOperation* _op, gchar* message, GStrv choices, MountOperation* pThis) { + qDebug("ask question"); + MountOperationQuestionDialog dialog(pThis, message, choices); + dialog.exec(); +} + +/* +void MountOperation::onReply(GMountOperation* _op, GMountOperationResult result, MountOperation* pThis) { + qDebug("reply"); +} +*/ + +void MountOperation::onShowProcesses(GMountOperation* _op, gchar* message, GArray* processes, GStrv choices, MountOperation* pThis) { + qDebug("show processes"); +} + +void MountOperation::onShowUnmountProgress(GMountOperation* _op, gchar* message, gint64 time_left, gint64 bytes_left, MountOperation* pThis) { + qDebug("show unmount progress"); +} + +void MountOperation::onEjectMountFinished(GMount* mount, GAsyncResult* res, QPointer< MountOperation >* pThis) { + if(*pThis) { + GError* error = NULL; + g_mount_eject_with_operation_finish(mount, res, &error); + (*pThis)->handleFinish(error); + } + delete pThis; +} + +void MountOperation::onEjectVolumeFinished(GVolume* volume, GAsyncResult* res, QPointer< MountOperation >* pThis) { + if(*pThis) { + GError* error = NULL; + g_volume_eject_with_operation_finish(volume, res, &error); + (*pThis)->handleFinish(error); + } + delete pThis; +} + +void MountOperation::onMountFileFinished(GFile* file, GAsyncResult* res, QPointer< MountOperation >* pThis) { + if(*pThis) { + GError* error = NULL; + g_file_mount_enclosing_volume_finish(file, res, &error); + (*pThis)->handleFinish(error); + } + delete pThis; +} + +void MountOperation::onMountVolumeFinished(GVolume* volume, GAsyncResult* res, QPointer< MountOperation >* pThis) { + if(*pThis) { + GError* error = NULL; + g_volume_mount_finish(volume, res, &error); + (*pThis)->handleFinish(error); + } + delete pThis; +} + +void MountOperation::onUnmountMountFinished(GMount* mount, GAsyncResult* res, QPointer< MountOperation >* pThis) { + if(*pThis) { + GError* error = NULL; + g_mount_unmount_with_operation_finish(mount, res, &error); + (*pThis)->handleFinish(error); + } + delete pThis; +} + +void MountOperation::handleFinish(GError* error) { + qDebug("operation finished: %p", error); + if(error) { + bool showError = interactive_; + if(error->domain == G_IO_ERROR) { + if(error->code == G_IO_ERROR_FAILED) { + // Generate a more human-readable error message instead of using a gvfs one. + // The original error message is something like: + // Error unmounting: umount exited with exit code 1: + // helper failed with: umount: only root can unmount + // UUID=18cbf00c-e65f-445a-bccc-11964bdea05d from /media/sda4 */ + // Why they pass this back to us? This is not human-readable for the users at all. + if(strstr(error->message, "only root can ")) { + g_free(error->message); + error->message = g_strdup(_("Only system administrators have the permission to do this.")); + } + } + else if(error->code == G_IO_ERROR_FAILED_HANDLED) + showError = false; + } + if(showError) + QMessageBox::critical(NULL, QObject::tr("Error"), QString::fromUtf8(error->message)); + } + + Q_EMIT finished(error); + + if(eventLoop) { // if wait() is called to block the main loop + eventLoop->exit(error != NULL ? 1 : 0); + eventLoop = NULL; + } + + if(error) + g_error_free(error); + + // free ourself here!! + if(autoDestroy_) + deleteLater(); +} + +void MountOperation::prepareUnmount(GMount* mount) { + /* ensure that CWD is not on the mounted filesystem. */ + char* cwd_str = g_get_current_dir(); + GFile* cwd = g_file_new_for_path(cwd_str); + GFile* root = g_mount_get_root(mount); + g_free(cwd_str); + /* FIXME: This cannot cover 100% cases since symlinks are not checked. + * There may be other cases that cwd is actually under mount root + * but checking prefix is not enough. We already did our best, though. */ + if(g_file_has_prefix(cwd, root)) + g_chdir("/"); + g_object_unref(cwd); + g_object_unref(root); +} + +// block the operation used an internal QEventLoop and returns +// only after the whole operation is finished. +bool MountOperation::wait() { + QEventLoop loop; + eventLoop = &loop; + int exitCode = loop.exec(); + return exitCode == 0 ? true : false; +} + +} // namespace Fm diff --git a/libfm-qt/mountoperation.h b/libfm-qt/mountoperation.h new file mode 100644 index 0000000..8d94311 --- /dev/null +++ b/libfm-qt/mountoperation.h @@ -0,0 +1,155 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_MOUNTOPERATION_H +#define FM_MOUNTOPERATION_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include + +class QEventLoop; + +namespace Fm { + +// FIXME: the original APIs in gtk+ version of libfm for mounting devices is poor. +// Need to find a better API design which make things fully async and cancellable. + +// FIXME: parent_ does not work. All dialogs shown by the mount operation has no parent window assigned. +// FIXME: Need to reconsider the propery way of API design. Blocking sync calls are handy, but +// indeed causes some problems. :-( + +class LIBFM_QT_API MountOperation: public QObject { +Q_OBJECT + +public: + explicit MountOperation(bool interactive = true, QWidget* parent = 0); + ~MountOperation(); + + void mount(FmPath* path) { + GFile* gf = fm_path_to_gfile(path); + g_file_mount_enclosing_volume(gf, G_MOUNT_MOUNT_NONE, op, cancellable_, (GAsyncReadyCallback)onMountFileFinished, new QPointer(this)); + g_object_unref(gf); + } + + void mount(GVolume* volume) { + g_volume_mount(volume, G_MOUNT_MOUNT_NONE, op, cancellable_, (GAsyncReadyCallback)onMountVolumeFinished, new QPointer(this)); + } + + void unmount(GMount* mount) { + prepareUnmount(mount); + g_mount_unmount_with_operation(mount, G_MOUNT_UNMOUNT_NONE, op, cancellable_, (GAsyncReadyCallback)onUnmountMountFinished, new QPointer(this)); + } + + void unmount(GVolume* volume) { + GMount* mount = g_volume_get_mount(volume); + if(!mount) + return; + unmount(mount); + g_object_unref(mount); + } + + void eject(GMount* mount) { + prepareUnmount(mount); + g_mount_eject_with_operation(mount, G_MOUNT_UNMOUNT_NONE, op, cancellable_, (GAsyncReadyCallback)onEjectMountFinished, new QPointer(this)); + } + + void eject(GVolume* volume) { + GMount* mnt = g_volume_get_mount(volume); + prepareUnmount(mnt); + g_object_unref(mnt); + g_volume_eject_with_operation(volume, G_MOUNT_UNMOUNT_NONE, op, cancellable_, (GAsyncReadyCallback)onEjectVolumeFinished, new QPointer(this)); + } + + QWidget* parent() const { + return parent_; + } + + void setParent(QWidget* parent) { + parent_ = parent; + } + + GCancellable* cancellable() const { + return cancellable_; + } + + GMountOperation* mountOperation() { + return op; + } + + void cancel() { + g_cancellable_cancel(cancellable_); + } + + bool isRunning() const { + return running; + } + + // block the operation used an internal QEventLoop and returns + // only after the whole operation is finished. + bool wait(); + + bool autoDestroy() { + return autoDestroy_; + } + + void setAutoDestroy(bool destroy = true) { + autoDestroy_ = destroy; + } + +Q_SIGNALS: + void finished(GError* error = NULL); + +private: + void prepareUnmount(GMount* mount); + + static void onAskPassword(GMountOperation *_op, gchar* message, gchar* default_user, gchar* default_domain, GAskPasswordFlags flags, MountOperation* pThis); + static void onAskQuestion(GMountOperation *_op, gchar* message, GStrv choices, MountOperation* pThis); + // static void onReply(GMountOperation *_op, GMountOperationResult result, MountOperation* pThis); + + static void onAbort(GMountOperation *_op, MountOperation* pThis); + static void onShowProcesses(GMountOperation *_op, gchar* message, GArray* processes, GStrv choices, MountOperation* pThis); + static void onShowUnmountProgress(GMountOperation *_op, gchar* message, gint64 time_left, gint64 bytes_left, MountOperation* pThis); + + // it's possible that this object is freed when the callback is called by gio, so guarding with QPointer is needed here. + static void onMountFileFinished(GFile* file, GAsyncResult *res, QPointer* pThis); + static void onMountVolumeFinished(GVolume* volume, GAsyncResult *res, QPointer* pThis); + static void onUnmountMountFinished(GMount* mount, GAsyncResult *res, QPointer* pThis); + static void onEjectMountFinished(GMount* mount, GAsyncResult *res, QPointer* pThis); + static void onEjectVolumeFinished(GVolume* volume, GAsyncResult *res, QPointer* pThis); + + void handleFinish(GError* error); + +private: + GMountOperation* op; + GCancellable* cancellable_; + QWidget* parent_; + bool running; + bool interactive_; + QEventLoop* eventLoop; + bool autoDestroy_; +}; + +} + +#endif // FM_MOUNTOPERATION_H diff --git a/libfm-qt/mountoperationpassworddialog.cpp b/libfm-qt/mountoperationpassworddialog.cpp new file mode 100644 index 0000000..e360d29 --- /dev/null +++ b/libfm-qt/mountoperationpassworddialog.cpp @@ -0,0 +1,125 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "mountoperationpassworddialog_p.h" +#include "ui_mount-operation-password.h" +#include "mountoperation.h" + +namespace Fm { + +MountOperationPasswordDialog::MountOperationPasswordDialog(MountOperation* op, GAskPasswordFlags flags): + QDialog(), + mountOperation(op), + canAnonymous(flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED ? true : false), + canSavePassword(flags & G_ASK_PASSWORD_SAVING_SUPPORTED ? true : false), + needUserName(flags & G_ASK_PASSWORD_NEED_USERNAME ? true : false), + needPassword(flags & G_ASK_PASSWORD_NEED_PASSWORD ? true : false), + needDomain(flags & G_ASK_PASSWORD_NEED_DOMAIN ? true : false) { + + ui = new Ui::MountOperationPasswordDialog(); + ui->setupUi(this); + + // change the text of Ok button to Connect + ui->buttonBox->buttons().first()->setText(tr("&Connect")); + connect(ui->Anonymous, &QAbstractButton::toggled, this, &MountOperationPasswordDialog::onAnonymousToggled); + + if(canAnonymous) { + // select ananymous by default if applicable. + ui->Anonymous->setChecked(true); + } + else { + ui->Anonymous->setEnabled(false); + } + if(!needUserName) { + ui->username->setEnabled(false); + } + if(!needPassword) { + ui->password->setEnabled(false); + } + if(!needDomain) { + ui->domain->hide(); + ui->domainLabel->hide(); + } + if(canSavePassword) { + ui->sessionPassword->setChecked(true); + } + else { + ui->storePassword->setEnabled(false); + ui->sessionPassword->setEnabled(false); + ui->forgetPassword->setChecked(true); + } +} + +MountOperationPasswordDialog::~MountOperationPasswordDialog() { + delete ui; +} + +void MountOperationPasswordDialog::onAnonymousToggled(bool checked) { + // disable username/password entries if anonymous mode is used + bool useUserPassword = !checked; + if(needUserName) + ui->username->setEnabled(useUserPassword); + if(needPassword) + ui->password->setEnabled(useUserPassword); + if(needDomain) + ui->domain->setEnabled(useUserPassword); + + if(canSavePassword) { + ui->forgetPassword->setEnabled(useUserPassword); + ui->sessionPassword->setEnabled(useUserPassword); + ui->storePassword->setEnabled(useUserPassword); + } +} + +void MountOperationPasswordDialog::setMessage(QString message) { + ui->message->setText(message); +} + +void MountOperationPasswordDialog::setDefaultDomain(QString domain) { + ui->domain->setText(domain); +} + +void MountOperationPasswordDialog::setDefaultUser(QString user) { + ui->username->setText(user); +} + +void MountOperationPasswordDialog::done(int r) { + GMountOperation* gmop = mountOperation->mountOperation(); + + if(r == QDialog::Accepted) { + + if(needUserName) + g_mount_operation_set_username(gmop, ui->username->text().toUtf8()); + if(needDomain) + g_mount_operation_set_domain(gmop, ui->domain->text().toUtf8()); + if(needPassword) + g_mount_operation_set_password(gmop, ui->password->text().toUtf8()); + if(canAnonymous) + g_mount_operation_set_anonymous(gmop, ui->Anonymous->isChecked()); + + g_mount_operation_reply(gmop, G_MOUNT_OPERATION_HANDLED); + } + else { + g_mount_operation_reply(gmop, G_MOUNT_OPERATION_ABORTED); + } + QDialog::done(r); +} + +} // namespace Fm diff --git a/libfm-qt/mountoperationpassworddialog_p.h b/libfm-qt/mountoperationpassworddialog_p.h new file mode 100644 index 0000000..410d92d --- /dev/null +++ b/libfm-qt/mountoperationpassworddialog_p.h @@ -0,0 +1,64 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_MOUNTOPERATIONPASSWORDDIALOG_H +#define FM_MOUNTOPERATIONPASSWORDDIALOG_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Ui { + class MountOperationPasswordDialog; +}; + +namespace Fm { + +class MountOperation; + +class MountOperationPasswordDialog : public QDialog { +Q_OBJECT + +public: + explicit MountOperationPasswordDialog(MountOperation* op, GAskPasswordFlags flags); + virtual ~MountOperationPasswordDialog(); + + void setMessage(QString message); + void setDefaultUser(QString user); + void setDefaultDomain(QString domain); + + virtual void done(int r); + +private Q_SLOTS: + void onAnonymousToggled(bool checked); + +private: + Ui::MountOperationPasswordDialog* ui; + MountOperation* mountOperation; + bool needPassword; + bool needUserName; + bool needDomain; + bool canSavePassword; + bool canAnonymous; +}; + +} + +#endif // FM_MOUNTOPERATIONPASSWORDDIALOG_H diff --git a/libfm-qt/mountoperationquestiondialog.cpp b/libfm-qt/mountoperationquestiondialog.cpp new file mode 100644 index 0000000..2c33638 --- /dev/null +++ b/libfm-qt/mountoperationquestiondialog.cpp @@ -0,0 +1,71 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "mountoperationquestiondialog_p.h" +#include "mountoperation.h" +#include + +namespace Fm { + +MountOperationQuestionDialog::MountOperationQuestionDialog(MountOperation* op, gchar* message, GStrv choices): + QMessageBox(), + mountOperation(op) { + + setIcon(QMessageBox::Question); + setText(QString::fromUtf8(message)); + + choiceCount = g_strv_length(choices); + choiceButtons = new QAbstractButton*[choiceCount]; + for(int i = 0; i < choiceCount; ++i) { + // It's not allowed to add custom buttons without standard roles + // to QMessageBox. So we set role of all buttons to AcceptRole and + // handle their clicked() signals in our own slots. + // When anyone of the buttons is clicked, exec() always returns "accept". + QPushButton* button = new QPushButton(QString::fromUtf8(choices[i])); + addButton(button, QMessageBox::AcceptRole); + choiceButtons[i] = button; + } + connect(this, &MountOperationQuestionDialog::buttonClicked, this, &MountOperationQuestionDialog::onButtonClicked); +} + +MountOperationQuestionDialog::~MountOperationQuestionDialog() { + delete []choiceButtons; +} + +void MountOperationQuestionDialog::done(int r) { + if(r != QDialog::Accepted) { + GMountOperation* op = mountOperation->mountOperation(); + g_mount_operation_reply(op, G_MOUNT_OPERATION_ABORTED); + } + QDialog::done(r); +} + +void MountOperationQuestionDialog::onButtonClicked(QAbstractButton* button) { + GMountOperation* op = mountOperation->mountOperation(); + for(int i = 0; i < choiceCount; ++i) { + if(choiceButtons[i] == button) { + g_mount_operation_set_choice(op, i); + g_mount_operation_reply(op, G_MOUNT_OPERATION_HANDLED); + break; + } + } +} + +} // namespace Fm diff --git a/libfm-qt/mountoperationquestiondialog_p.h b/libfm-qt/mountoperationquestiondialog_p.h new file mode 100644 index 0000000..fb5a705 --- /dev/null +++ b/libfm-qt/mountoperationquestiondialog_p.h @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_MOUNTOPERATIONQUESTIONDIALOG_H +#define FM_MOUNTOPERATIONQUESTIONDIALOG_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class MountOperation; + +class MountOperationQuestionDialog : public QMessageBox { +Q_OBJECT +public: + MountOperationQuestionDialog(MountOperation* op, gchar* message, GStrv choices); + virtual ~MountOperationQuestionDialog(); + + virtual void done(int r); + +private Q_SLOTS: + void onButtonClicked(QAbstractButton* button); + +private: + MountOperation* mountOperation; + QAbstractButton** choiceButtons; + int choiceCount; +}; + +} + +#endif // FM_MOUNTOPERATIONQUESTIONDIALOG_H diff --git a/libfm-qt/path.cpp b/libfm-qt/path.cpp new file mode 100644 index 0000000..044bf2d --- /dev/null +++ b/libfm-qt/path.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 Hong Jen Yee (PCMan) + * + * 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 "path.h" + +using namespace Fm; diff --git a/libfm-qt/path.h b/libfm-qt/path.h new file mode 100644 index 0000000..2efb5be --- /dev/null +++ b/libfm-qt/path.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2014 Hong Jen Yee (PCMan) + * + * 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 FM_PATH_H +#define FM_PATH_H + +#include "libfmqtglobals.h" +#include +#include +#include + +namespace Fm { + +class LIBFM_QT_API Path { +public: + + Path(): data_(NULL) { + } + + Path(FmPath* path, bool takeOwnership = false): data_(path) { + if(path && !takeOwnership) + fm_path_ref(data_); + } + + Path(const Path& other): data_(other.data_ ? fm_path_ref(other.data_) : NULL) { + } + + Path(GFile* gf): data_(fm_path_new_for_gfile(gf)) { + } + + ~Path() { + if(data_) + fm_path_unref(data_); + } + + static Path fromPathName(const char* path_name) { + return Path(fm_path_new_for_path(path_name), true); + } + + static Path fromUri(const char* uri) { + return Path(fm_path_new_for_uri(uri), true); + } + + static Path fromDisplayName(const char* path_name) { + return Path(fm_path_new_for_display_name(path_name), true); + } + + static Path fromString(const char* path_str) { + return Path(fm_path_new_for_str(path_str), true); + } + + static Path fromCommandlineArg(const char* arg) { + return Path(fm_path_new_for_commandline_arg(arg), true); + } + + Path child(const char* basename) { + return Path(fm_path_new_child(data_, basename), true); + } + + Path child(const char* basename, int name_len) { + return Path(fm_path_new_child_len(data_, basename, name_len), true); + } + + Path relative(const char* rel) { + return Path(fm_path_new_relative(data_, rel), true); + } + + /* predefined paths */ + static Path root(void) { /* / */ + return Path(fm_path_get_root(), false); + } + + static Path home(void) { /* home directory */ + return Path(fm_path_get_home(), false); + } + + static Path desktop(void) { /* $HOME/Desktop */ + return Path(fm_path_get_desktop(), false); + } + + static Path trash(void) { /* trash:/// */ + return Path(fm_path_get_trash(), false); + } + + static Path appsMenu(void) { /* menu://applications.menu/ */ + return Path(fm_path_get_apps_menu(), false); + } + + Path parent() { + return Path(fm_path_get_parent(data_), false); + } + + const char* basename() { + return fm_path_get_basename(data_); + } + + FmPathFlags flags() { + return fm_path_get_flags(data_); + } + + bool hasPrefix(FmPath* prefix) { + return fm_path_has_prefix(data_, prefix); + } + + Path schemePath() { + return Path(fm_path_get_scheme_path(data_), true); + } + + bool isNative() { + return fm_path_is_native(data_); + } + + bool isTrash() { + return fm_path_is_trash(data_); + } + + bool isTrashRoot() { + return fm_path_is_trash_root(data_); + } + + bool isNativeOrTrash() { + return fm_path_is_native_or_trash(data_); + } + + char* toString() { + return fm_path_to_str(data_); + } + + QByteArray toByteArray() { + char* s = fm_path_to_str(data_); + QByteArray str(s); + g_free(s); + return str; + } + + char* toUri() { + return fm_path_to_uri(data_); + } + + GFile* toGfile() { + return fm_path_to_gfile(data_); + } + + /* + char* displayName(bool human_readable = true) { + return fm_path_display_name(data_, human_readable); + } + */ + + QString displayName(bool human_readable = true) { + char* dispname = fm_path_display_name(data_, human_readable); + QString str = QString::fromUtf8(dispname); + g_free(dispname); + return str; + } + + /* + char* displayBasename() { + return fm_path_display_basename(data_); + } + */ + + QString displayBasename() { + char* basename = fm_path_display_basename(data_); + QString s = QString::fromUtf8(basename); + g_free(basename); + return s; + } + + /* For used in hash tables */ + guint hash() { + return fm_path_hash(data_); + } + + Path& operator = (const Path& other) { + if(data_) + fm_path_unref(data_); + data_ = fm_path_ref(other.data_); + return *this; + } + + bool operator == (const Path& other) const { + return fm_path_equal(data_, other.data_); + } + + bool operator != (const Path& other) const { + return !fm_path_equal(data_, other.data_); + } + + bool operator < (const Path& other) const { + return compare(other); + } + + bool operator > (const Path& other) const { + return (other < *this); + } + + /* can be used for sorting */ + int compare(const Path& other) const { + return fm_path_compare(data_, other.data_); + } + + /* used for completion in entry */ + bool equal(const gchar *str, int n) const { + return fm_path_equal_str(data_, str, n); + } + + /* calculate how many elements are in this path. */ + int depth() const { + return fm_path_depth(data_); + } + + FmPath* data() const { + return data_; + } + +private: + FmPath* data_; +}; + +} + +Q_DECLARE_OPAQUE_POINTER(FmPath*) + +#endif // FM_PATH_H diff --git a/libfm-qt/pathedit.cpp b/libfm-qt/pathedit.cpp new file mode 100644 index 0000000..c6c9e42 --- /dev/null +++ b/libfm-qt/pathedit.cpp @@ -0,0 +1,195 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "pathedit.h" +#include +#include +#include +#include +#include + +namespace Fm { + +PathEdit::PathEdit(QWidget* parent): + QLineEdit(parent), + cancellable_(NULL), + model_(new QStringListModel()), + completer_(new QCompleter()) { + setCompleter(completer_); + completer_->setModel(model_); + connect(this, &PathEdit::textChanged, this, &PathEdit::onTextChanged); +} + +PathEdit::~PathEdit() { + delete completer_; + if(model_) + delete model_; + if(cancellable_) { + g_cancellable_cancel(cancellable_); + g_object_unref(cancellable_); + } +} + +void PathEdit::focusInEvent(QFocusEvent* e) { + QLineEdit::focusInEvent(e); + // build the completion list only when we have the keyboard focus + reloadCompleter(true); +} + +void PathEdit::focusOutEvent(QFocusEvent* e) { + QLineEdit::focusOutEvent(e); + // free the completion list since we don't need it anymore + freeCompleter(); +} + +void PathEdit::onTextChanged(const QString& text) { + int pos = text.lastIndexOf('/'); + if(pos >= 0) + ++pos; + else + pos = text.length(); + QString newPrefix = text.left(pos); + if(currentPrefix_ != newPrefix) { + currentPrefix_ = newPrefix; + // only build the completion list if we have the keyboard focus + // if we don't have the focus now, then we'll rebuild the completion list + // when focusInEvent happens. this avoid unnecessary dir loading. + if(hasFocus()) + reloadCompleter(false); + } +} + +struct JobData { + GCancellable* cancellable; + GFile* dirName; + QStringList subDirs; + PathEdit* edit; + bool triggeredByFocusInEvent; + + ~JobData() { + g_object_unref(dirName); + g_object_unref(cancellable); + } + + static void freeMe(JobData* data) { + delete data; + } +}; + +void PathEdit::reloadCompleter(bool triggeredByFocusInEvent) { + // parent dir has been changed, reload dir list + // if(currentPrefix_[0] == "~") { // special case for home dir + // cancel running dir-listing jobs, if there's any + if(cancellable_) { + g_cancellable_cancel(cancellable_); + g_object_unref(cancellable_); + } + // launch a new job to do dir listing + JobData* data = new JobData(); + data->edit = this; + data->triggeredByFocusInEvent = triggeredByFocusInEvent; + // need to use fm_file_new_for_commandline_arg() rather than g_file_new_for_commandline_arg(). + // otherwise, our own vfs, such as menu://, won't be loaded. + data->dirName = fm_file_new_for_commandline_arg(currentPrefix_.toLocal8Bit().constData()); + // qDebug("load: %s", g_file_get_uri(data->dirName)); + cancellable_ = g_cancellable_new(); + data->cancellable = (GCancellable*)g_object_ref(cancellable_); + g_io_scheduler_push_job((GIOSchedulerJobFunc)jobFunc, + data, (GDestroyNotify)JobData::freeMe, + G_PRIORITY_LOW, cancellable_); +} + +void PathEdit::freeCompleter() { + if(cancellable_) { + g_cancellable_cancel(cancellable_); + g_object_unref(cancellable_); + cancellable_ = NULL; + } + model_->setStringList(QStringList()); +} + +gboolean PathEdit::jobFunc(GIOSchedulerJob* job, GCancellable* cancellable, gpointer user_data) { + JobData* data = reinterpret_cast(user_data); + GError *err = NULL; + GFileEnumerator* enu = g_file_enumerate_children(data->dirName, + // G_FILE_ATTRIBUTE_STANDARD_NAME"," + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME"," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, cancellable, + &err); + if(enu) { + while(!g_cancellable_is_cancelled(cancellable)) { + GFileInfo* inf = g_file_enumerator_next_file(enu, cancellable, &err); + if(inf) { + GFileType type = g_file_info_get_file_type(inf); + if(type == G_FILE_TYPE_DIRECTORY) { + const char* name = g_file_info_get_display_name(inf); + // FIXME: encoding conversion here? + data->subDirs.append(QString::fromUtf8(name)); + } + g_object_unref(inf); + } + else { + if(err) { + g_error_free(err); + err = NULL; + } + else /* EOF */ + break; + } + } + g_file_enumerator_close(enu, cancellable, NULL); + g_object_unref(enu); + } + // finished! let's update the UI in the main thread + g_io_scheduler_job_send_to_mainloop(job, _onJobFinished, data, NULL); + return FALSE; +} + +// static +gboolean PathEdit::_onJobFinished(gpointer user_data) { + JobData* data = reinterpret_cast(user_data); + data->edit->onJobFinished(data); + return TRUE; +} + +// This callback function is called from main thread so it's safe to access the GUI +void PathEdit::onJobFinished(JobData* data) { + if(!g_cancellable_is_cancelled(data->cancellable)) { + // update the completer only if the job is not cancelled + QStringList::iterator it; + for(it = data->subDirs.begin(); it != data->subDirs.end(); ++it) { + // qDebug("%s", it->toUtf8().constData()); + *it = (currentPrefix_ % *it); + } + model_->setStringList(data->subDirs); + // trigger completion manually + if(hasFocus() && !data->triggeredByFocusInEvent) + completer_->complete(); + } + else + model_->setStringList(QStringList()); + if(cancellable_) { + g_object_unref(cancellable_); + cancellable_ = NULL; + } +} + +} // namespace Fm diff --git a/libfm-qt/pathedit.h b/libfm-qt/pathedit.h new file mode 100644 index 0000000..e5cab4c --- /dev/null +++ b/libfm-qt/pathedit.h @@ -0,0 +1,64 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_PATHEDIT_H +#define FM_PATHEDIT_H + +#include "libfmqtglobals.h" +#include +#include + +class QCompleter; +class QStringListModel; + +namespace Fm { + +struct JobData; + +class LIBFM_QT_API PathEdit : public QLineEdit { +Q_OBJECT +public: + explicit PathEdit(QWidget* parent = 0); + virtual ~PathEdit(); + +protected: + virtual void focusInEvent(QFocusEvent* e); + virtual void focusOutEvent(QFocusEvent* e); + +private Q_SLOTS: + void onTextChanged(const QString & text); + +private: + void reloadCompleter(bool triggeredByFocusInEvent = false); + void freeCompleter(); + static gboolean jobFunc(GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data); + static gboolean _onJobFinished(gpointer user_data); + void onJobFinished(JobData* data); + +private: + QCompleter* completer_; + QStringListModel* model_; + QString currentPrefix_; + GCancellable* cancellable_; +}; + +} + +#endif // FM_PATHEDIT_H diff --git a/libfm-qt/placesmodel.cpp b/libfm-qt/placesmodel.cpp new file mode 100644 index 0000000..d0dab01 --- /dev/null +++ b/libfm-qt/placesmodel.cpp @@ -0,0 +1,519 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "placesmodel.h" +#include "icontheme.h" +#include +#include +#include +#include +#include "utilities.h" +#include "placesmodelitem.h" + +using namespace Fm; + +PlacesModel::PlacesModel(QObject* parent): + QStandardItemModel(parent), + showApplications_(true), + showDesktop_(true), + ejectIcon_(QIcon::fromTheme("media-eject")) { + + setColumnCount(2); + + PlacesModelItem* item; + placesRoot = new QStandardItem(tr("Places")); + placesRoot->setSelectable(false); + placesRoot->setColumnCount(2); + appendRow(placesRoot); + + homeItem = new PlacesModelItem("user-home", g_get_user_name(), fm_path_get_home()); + placesRoot->appendRow(homeItem); + + desktopItem = new PlacesModelItem("user-desktop", tr("Desktop"), fm_path_get_desktop()); + placesRoot->appendRow(desktopItem); + + createTrashItem(); + + FmPath* path; + if(isUriSchemeSupported("computer")) { + path = fm_path_new_for_uri("computer:///"); + computerItem = new PlacesModelItem("computer", tr("Computer"), path); + fm_path_unref(path); + placesRoot->appendRow(computerItem); + } + else + computerItem = NULL; + + const char* applicaion_icon_names[] = {"system-software-install", "applications-accessories", "application-x-executable"}; + // NOTE: g_themed_icon_new_from_names() accepts char**, but actually const char** is OK. + GIcon* gicon = g_themed_icon_new_from_names((char**)applicaion_icon_names, G_N_ELEMENTS(applicaion_icon_names)); + FmIcon* fmicon = fm_icon_from_gicon(gicon); + g_object_unref(gicon); + applicationsItem = new PlacesModelItem(fmicon, tr("Applications"), fm_path_get_apps_menu()); + fm_icon_unref(fmicon); + placesRoot->appendRow(applicationsItem); + + if(isUriSchemeSupported("network")) { + const char* network_icon_names[] = {"network", "folder-network", "folder"}; + // NOTE: g_themed_icon_new_from_names() accepts char**, but actually const char** is OK. + gicon = g_themed_icon_new_from_names((char**)network_icon_names, G_N_ELEMENTS(network_icon_names)); + fmicon = fm_icon_from_gicon(gicon); + g_object_unref(gicon); + path = fm_path_new_for_uri("network:///"); + networkItem = new PlacesModelItem(fmicon, tr("Network"), path); + fm_icon_unref(fmicon); + fm_path_unref(path); + placesRoot->appendRow(networkItem); + } + else + networkItem = NULL; + + devicesRoot = new QStandardItem(tr("Devices")); + devicesRoot->setSelectable(false); + devicesRoot->setColumnCount(2); + appendRow(devicesRoot); + + // volumes + volumeMonitor = g_volume_monitor_get(); + if(volumeMonitor) { + g_signal_connect(volumeMonitor, "volume-added", G_CALLBACK(onVolumeAdded), this); + g_signal_connect(volumeMonitor, "volume-removed", G_CALLBACK(onVolumeRemoved), this); + g_signal_connect(volumeMonitor, "volume-changed", G_CALLBACK(onVolumeChanged), this); + g_signal_connect(volumeMonitor, "mount-added", G_CALLBACK(onMountAdded), this); + g_signal_connect(volumeMonitor, "mount-changed", G_CALLBACK(onMountChanged), this); + g_signal_connect(volumeMonitor, "mount-removed", G_CALLBACK(onMountRemoved), this); + + // add volumes to side-pane + GList* vols = g_volume_monitor_get_volumes(volumeMonitor); + GList* l; + for(l = vols; l; l = l->next) { + GVolume* volume = G_VOLUME(l->data); + onVolumeAdded(volumeMonitor, volume, this); + g_object_unref(volume); + } + g_list_free(vols); + + /* add mounts to side-pane */ + vols = g_volume_monitor_get_mounts(volumeMonitor); + for(l = vols; l; l = l->next) { + GMount* mount = G_MOUNT(l->data); + GVolume* volume = g_mount_get_volume(mount); + if(volume) + g_object_unref(volume); + else { /* network mounts or others */ + item = new PlacesModelMountItem(mount); + devicesRoot->appendRow(item); + } + g_object_unref(mount); + } + g_list_free(vols); + } + + // bookmarks + bookmarksRoot = new QStandardItem(tr("Bookmarks")); + bookmarksRoot->setSelectable(false); + bookmarksRoot->setColumnCount(2); + appendRow(bookmarksRoot); + + bookmarks = fm_bookmarks_dup(); + loadBookmarks(); + g_signal_connect(bookmarks, "changed", G_CALLBACK(onBookmarksChanged), this); + + // update some icons when the icon theme is changed + connect(IconTheme::instance(), &IconTheme::changed, this, &PlacesModel::updateIcons); +} + +void PlacesModel::loadBookmarks() { + GList* allBookmarks = fm_bookmarks_get_all(bookmarks); + for(GList* l = allBookmarks; l; l = l->next) { + FmBookmarkItem* bm_item = (FmBookmarkItem*)l->data; + PlacesModelBookmarkItem* item = new PlacesModelBookmarkItem(bm_item); + bookmarksRoot->appendRow(item); + } + g_list_free_full(allBookmarks, (GDestroyNotify)fm_bookmark_item_unref); +} + +PlacesModel::~PlacesModel() { + if(bookmarks) { + g_signal_handlers_disconnect_by_func(bookmarks, (gpointer)onBookmarksChanged, this); + g_object_unref(bookmarks); + } + if(volumeMonitor) { + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onVolumeAdded), this); + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onVolumeRemoved), this); + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onVolumeChanged), this); + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onMountAdded), this); + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onMountChanged), this); + g_signal_handlers_disconnect_by_func(volumeMonitor, (gpointer)G_CALLBACK(onMountRemoved), this); + g_object_unref(volumeMonitor); + } + if(trashMonitor_) { + g_signal_handlers_disconnect_by_func(trashMonitor_, (gpointer)G_CALLBACK(onTrashChanged), this); + g_object_unref(trashMonitor_); + } +} + +// static +void PlacesModel::onTrashChanged(GFileMonitor* monitor, GFile* gf, GFile* other, GFileMonitorEvent evt, PlacesModel* pThis) { + QTimer::singleShot(0, pThis, SLOT(updateTrash())); +} + +void PlacesModel::updateTrash() { + if(trashItem_) { + GFile* gf = fm_file_new_for_uri("trash:///"); + GFileInfo* inf = g_file_query_info(gf, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT, G_FILE_QUERY_INFO_NONE, NULL, NULL); + g_object_unref(gf); + if(inf) { + guint32 n = g_file_info_get_attribute_uint32(inf, G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT); + g_object_unref(inf); + const char* icon_name = n > 0 ? "user-trash-full" : "user-trash"; + FmIcon* icon = fm_icon_from_name(icon_name); + trashItem_->setIcon(icon); + fm_icon_unref(icon); + } + } +} + +void PlacesModel::createTrashItem() { + GFile* gf; + gf = fm_file_new_for_uri("trash:///"); + // check if trash is supported by the current vfs + // if gvfs is not installed, this can be unavailable. + if(!g_file_query_exists(gf, NULL)) { + g_object_unref(gf); + trashItem_ = NULL; + trashMonitor_ = NULL; + return; + } + trashItem_ = new PlacesModelItem("user-trash", tr("Trash"), fm_path_get_trash()); + + trashMonitor_ = fm_monitor_directory(gf, NULL); + if(trashMonitor_) + g_signal_connect(trashMonitor_, "changed", G_CALLBACK(onTrashChanged), this); + g_object_unref(gf); + + placesRoot->insertRow(desktopItem->row() + 1, trashItem_); + QTimer::singleShot(0, this, SLOT(updateTrash())); +} + +void PlacesModel::setShowApplications(bool show) { + if(showApplications_ != show) { + showApplications_ = show; + } +} + +void PlacesModel::setShowDesktop(bool show) { + if(showDesktop_ != show) { + showDesktop_ = show; + } +} + +void PlacesModel::setShowTrash(bool show) { + if(show) { + if(!trashItem_) + createTrashItem(); + } + else { + if(trashItem_) { + if(trashMonitor_) { + g_signal_handlers_disconnect_by_func(trashMonitor_, (gpointer)G_CALLBACK(onTrashChanged), this); + g_object_unref(trashMonitor_); + trashMonitor_ = NULL; + } + placesRoot->removeRow(trashItem_->row()); // delete trashItem_; + trashItem_ = NULL; + } + } +} + +PlacesModelItem* PlacesModel::itemFromPath(FmPath* path) { + PlacesModelItem* item = itemFromPath(placesRoot, path); + if(!item) + item = itemFromPath(devicesRoot, path); + if(!item) + item = itemFromPath(bookmarksRoot, path); + return item; +} + +PlacesModelItem* PlacesModel::itemFromPath(QStandardItem* rootItem, FmPath* path) { + int rowCount = rootItem->rowCount(); + for(int i = 0; i < rowCount; ++i) { + PlacesModelItem* item = static_cast(rootItem->child(i, 0)); + if(fm_path_equal(item->path(), path)) + return item; + } + return NULL; +} + +PlacesModelVolumeItem* PlacesModel::itemFromVolume(GVolume* volume) { + int rowCount = devicesRoot->rowCount(); + for(int i = 0; i < rowCount; ++i) { + PlacesModelItem* item = static_cast(devicesRoot->child(i, 0)); + if(item->type() == PlacesModelItem::Volume) { + PlacesModelVolumeItem* volumeItem = static_cast(item); + if(volumeItem->volume() == volume) + return volumeItem; + } + } + return NULL; +} + +PlacesModelMountItem* PlacesModel::itemFromMount(GMount* mount) { + int rowCount = devicesRoot->rowCount(); + for(int i = 0; i < rowCount; ++i) { + PlacesModelItem* item = static_cast(devicesRoot->child(i, 0)); + if(item->type() == PlacesModelItem::Mount) { + PlacesModelMountItem* mountItem = static_cast(item); + if(mountItem->mount() == mount) + return mountItem; + } + } + return NULL; +} + +PlacesModelBookmarkItem* PlacesModel::itemFromBookmark(FmBookmarkItem* bkitem) { + int rowCount = bookmarksRoot->rowCount(); + for(int i = 0; i < rowCount; ++i) { + PlacesModelBookmarkItem* item = static_cast(bookmarksRoot->child(i, 0)); + if(item->bookmark() == bkitem) + return item; + } + return NULL; +} + +void PlacesModel::onMountAdded(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis) { + GVolume* vol = g_mount_get_volume(mount); + if(vol) { // mount-added is also emitted when a volume is newly mounted. + PlacesModelVolumeItem* item = pThis->itemFromVolume(vol); + if(item && !item->path()) { + // update the mounted volume and show a button for eject. + GFile* gf = g_mount_get_root(mount); + FmPath* path = fm_path_new_for_gfile(gf); + g_object_unref(gf); + item->setPath(path); + if(path) + fm_path_unref(path); + // update the mount indicator (eject button) + QStandardItem* ejectBtn = item->parent()->child(item->row(), 1); + Q_ASSERT(ejectBtn); + ejectBtn->setIcon(pThis->ejectIcon_); + } + g_object_unref(vol); + } + else { // network mounts and others + PlacesModelMountItem* item = pThis->itemFromMount(mount); + /* for some unknown reasons, sometimes we get repeated mount-added + * signals and added a device more than one. So, make a sanity check here. */ + if(!item) { + item = new PlacesModelMountItem(mount); + QStandardItem* eject_btn = new QStandardItem(pThis->ejectIcon_, ""); + pThis->devicesRoot->appendRow(QList() << item << eject_btn); + } + } +} + +void PlacesModel::onMountChanged(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis) { + PlacesModelMountItem* item = pThis->itemFromMount(mount); + if(item) + item->update(); +} + +void PlacesModel::onMountRemoved(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis) { + GVolume* vol = g_mount_get_volume(mount); + qDebug() << "volume umounted: " << vol; + if(vol) { + // a volume is unmounted + g_object_unref(vol); + } + else { // network mounts and others + PlacesModelMountItem* item = pThis->itemFromMount(mount); + if(item) { + pThis->devicesRoot->removeRow(item->row()); + } + } +} + +void PlacesModel::onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis) { + // for some unknown reasons, sometimes we get repeated volume-added + // signals and added a device more than one. So, make a sanity check here. + PlacesModelVolumeItem* volumeItem = pThis->itemFromVolume(volume); + if(!volumeItem) { + volumeItem = new PlacesModelVolumeItem(volume); + QStandardItem* ejectBtn = new QStandardItem(); + if(volumeItem->isMounted()) + ejectBtn->setIcon(pThis->ejectIcon_); + pThis->devicesRoot->appendRow(QList() << volumeItem << ejectBtn); + } +} + +void PlacesModel::onVolumeChanged(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis) { + PlacesModelVolumeItem* item = pThis->itemFromVolume(volume); + if(item) { + item->update(); + if(!item->isMounted()) { // the volume is unmounted, remove the eject button if needed + // remove the eject button for the volume (at column 1 of the same row) + QStandardItem* ejectBtn = item->parent()->child(item->row(), 1); + Q_ASSERT(ejectBtn); + ejectBtn->setIcon(QIcon()); + } + } +} + +void PlacesModel::onVolumeRemoved(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis) { + PlacesModelVolumeItem* item = pThis->itemFromVolume(volume); + if(item) { + pThis->devicesRoot->removeRow(item->row()); + } +} + +void PlacesModel::onBookmarksChanged(FmBookmarks* bookmarks, PlacesModel* pThis) { + // remove all items + pThis->bookmarksRoot->removeRows(0, pThis->bookmarksRoot->rowCount()); + pThis->loadBookmarks(); +} + +void PlacesModel::updateIcons() { + // the icon theme is changed and we need to update the icons + PlacesModelItem* item; + int row; + int n = placesRoot->rowCount(); + for(row = 0; row < n; ++row) { + item = static_cast(placesRoot->child(row)); + item->updateIcon(); + } + n = devicesRoot->rowCount(); + for(row = 0; row < n; ++row) { + item = static_cast(devicesRoot->child(row)); + item->updateIcon(); + } +} + +Qt::ItemFlags PlacesModel::flags(const QModelIndex& index) const { + if(index.column() == 1) // make 2nd column of every row selectable. + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; + if(!index.parent().isValid()) { // root items + if(index.row() == 2) // bookmarks root + return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + else + return Qt::ItemIsEnabled; + } + return QStandardItemModel::flags(index); +} + +bool PlacesModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { + QStandardItem* item = itemFromIndex(parent); + if(data->hasFormat("application/x-bookmark-row")) { // the data being dopped is a bookmark row + // decode it and do bookmark reordering + QByteArray buf = data->data("application/x-bookmark-row"); + QDataStream stream(&buf, QIODevice::ReadOnly); + int oldPos = -1; + char* pathStr = NULL; + stream >> oldPos >> pathStr; + // find the source bookmark item being dragged + GList* allBookmarks = fm_bookmarks_get_all(bookmarks); + FmBookmarkItem* draggedItem = static_cast(g_list_nth_data(allBookmarks, oldPos)); + // If we cannot find the dragged bookmark item at position , or we find an item, + // but the path of the item is not the same as what we expected, than it's the wrong item. + // This means that the bookmarks are changed during our dnd processing, which is an extremely rare case. + if(!draggedItem || !fm_path_equal_str(draggedItem->path, pathStr, -1)) { + delete []pathStr; + return false; + } + delete []pathStr; + + int newPos = -1; + if(row == -1 && column == -1) { // drop on an item + // we only allow dropping on an bookmark item + if(item && item->parent() == bookmarksRoot) + newPos = parent.row(); + } + else { // drop on a position between items + if(item == bookmarksRoot) // we only allow dropping on a bookmark item + newPos = row; + } + if(newPos != -1 && newPos != oldPos) // reorder the bookmark item + fm_bookmarks_reorder(bookmarks, draggedItem, newPos); + } + else if(data->hasUrls()) { // files uris are dropped + if(row == -1 && column == -1) { // drop uris on an item + if(item && item->parent()) { // need to be a child item + PlacesModelItem* placesItem = static_cast(item); + if(placesItem->path()) { + qDebug() << "dropped dest:" << placesItem->text(); + // TODO: copy or move the dragged files to the dir pointed by the item. + qDebug() << "drop on" << item->text(); + } + } + } + else { // drop uris on a position between items + if(item == bookmarksRoot) { // we only allow dropping on blank row of bookmarks section + FmPathList* paths = pathListFromQUrls(data->urls()); + for(GList* l = fm_path_list_peek_head_link(paths); l; l = l->next) { + FmPath* path = FM_PATH(l->data); + GFile* gf = fm_path_to_gfile(path); + // FIXME: this is a blocking call + if(g_file_query_file_type(gf, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL) == G_FILE_TYPE_DIRECTORY) { + char* disp_name = fm_path_display_basename(path); + fm_bookmarks_insert(bookmarks, path, disp_name, row); + g_free(disp_name); + } + g_object_unref(gf); + return true; + } + } + } + } + return false; +} + +// we only support dragging bookmark items and use our own +// custom pseudo-mime-type: application/x-bookmark-row +QMimeData* PlacesModel::mimeData(const QModelIndexList& indexes) const { + if(!indexes.isEmpty()) { + // we only allow dragging one bookmark item at a time, so handle the first index only. + QModelIndex index = indexes.first(); + QStandardItem* item = itemFromIndex(index); + // ensure that it's really a bookmark item + if(item && item->parent() == bookmarksRoot) { + PlacesModelBookmarkItem* bookmarkItem = static_cast(item); + QMimeData* mime = new QMimeData(); + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + // There is no safe and cross-process way to store a reference of a row. + // Let's store the pos, name, and path of the bookmark item instead. + char* pathStr = fm_path_to_str(bookmarkItem->path()); + stream << index.row() << pathStr; + g_free(pathStr); + mime->setData("application/x-bookmark-row", data); + return mime; + } + } + return NULL; +} + +QStringList PlacesModel::mimeTypes() const { + return QStringList() << "application/x-bookmark-row" << "text/uri-list"; +} + +Qt::DropActions PlacesModel::supportedDropActions() const { + return QStandardItemModel::supportedDropActions(); +} + diff --git a/libfm-qt/placesmodel.h b/libfm-qt/placesmodel.h new file mode 100644 index 0000000..f94a37a --- /dev/null +++ b/libfm-qt/placesmodel.h @@ -0,0 +1,131 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_PLACESMODEL_H +#define FM_PLACESMODEL_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include + +namespace Fm { + +class PlacesModelItem; +class PlacesModelVolumeItem; +class PlacesModelMountItem; +class PlacesModelBookmarkItem; + +class LIBFM_QT_API PlacesModel : public QStandardItemModel { +Q_OBJECT +friend class PlacesView; +public: + + // QAction used for popup menus + class ItemAction : public QAction { + public: + ItemAction(const QModelIndex& index, QString text, QObject* parent = 0): + QAction(text, parent), + index_(index) { + } + + QPersistentModelIndex& index() { + return index_; + } + private: + QPersistentModelIndex index_; + }; + +public: + explicit PlacesModel(QObject* parent = 0); + virtual ~PlacesModel(); + + bool showTrash() { + return trashItem_ != NULL; + } + void setShowTrash(bool show); + + bool showApplications() { + return showApplications_; + } + void setShowApplications(bool show); + + bool showDesktop() { + return showDesktop_; + } + void setShowDesktop(bool show); + +public Q_SLOTS: + void updateIcons(); + void updateTrash(); + +protected: + + PlacesModelItem* itemFromPath(FmPath* path); + PlacesModelItem* itemFromPath(QStandardItem* rootItem, FmPath* path); + PlacesModelVolumeItem* itemFromVolume(GVolume* volume); + PlacesModelMountItem* itemFromMount(GMount* mount); + PlacesModelBookmarkItem* itemFromBookmark(FmBookmarkItem* bkitem); + + virtual Qt::ItemFlags flags(const QModelIndex& index) 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); + Qt::DropActions supportedDropActions() const; + + void createTrashItem(); + +private: + void loadBookmarks(); + + static void onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis); + static void onVolumeRemoved(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis); + static void onVolumeChanged(GVolumeMonitor* monitor, GVolume* volume, PlacesModel* pThis); + static void onMountAdded(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis); + static void onMountRemoved(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis); + static void onMountChanged(GVolumeMonitor* monitor, GMount* mount, PlacesModel* pThis); + + static void onBookmarksChanged(FmBookmarks* bookmarks, PlacesModel* pThis); + + static void onTrashChanged(GFileMonitor *monitor, GFile *gf, GFile *other, GFileMonitorEvent evt, PlacesModel* pThis); +private: + FmBookmarks* bookmarks; + GVolumeMonitor* volumeMonitor; + QList jobs; + bool showApplications_; + bool showDesktop_; + QStandardItem* placesRoot; + QStandardItem* devicesRoot; + QStandardItem* bookmarksRoot; + PlacesModelItem* trashItem_; + GFileMonitor* trashMonitor_; + PlacesModelItem* desktopItem; + PlacesModelItem* homeItem; + PlacesModelItem* computerItem; + PlacesModelItem* networkItem; + PlacesModelItem* applicationsItem; + QIcon ejectIcon_; +}; + +} + +#endif // FM_PLACESMODEL_H diff --git a/libfm-qt/placesmodelitem.cpp b/libfm-qt/placesmodelitem.cpp new file mode 100644 index 0000000..af9b885 --- /dev/null +++ b/libfm-qt/placesmodelitem.cpp @@ -0,0 +1,188 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "placesmodelitem.h" +#include "icontheme.h" +#include + +namespace Fm { + +PlacesModelItem::PlacesModelItem(): + QStandardItem(), + path_(NULL), + icon_(NULL), + fileInfo_(NULL) { +} + +PlacesModelItem::PlacesModelItem(const char* iconName, QString title, FmPath* path): + QStandardItem(title), + path_(path ? fm_path_ref(path) : NULL), + icon_(fm_icon_from_name(iconName)), + fileInfo_(NULL) { + if(icon_) + QStandardItem::setIcon(IconTheme::icon(icon_)); + setEditable(false); +} + +PlacesModelItem::PlacesModelItem(FmIcon* icon, QString title, FmPath* path): + QStandardItem(title), + path_(path ? fm_path_ref(path) : NULL), + icon_(icon ? fm_icon_ref(icon) : NULL), + fileInfo_(NULL) { + if(icon_) + QStandardItem::setIcon(IconTheme::icon(icon)); + setEditable(false); +} + +PlacesModelItem::PlacesModelItem(QIcon icon, QString title, FmPath* path): + QStandardItem(icon, title), + icon_(NULL), + path_(path ? fm_path_ref(path) : NULL), + fileInfo_(NULL) { + setEditable(false); +} + +PlacesModelItem::~PlacesModelItem() { + if(path_) + fm_path_unref(path_); + if(fileInfo_) + g_object_unref(fileInfo_); + if(icon_) + fm_icon_unref(icon_); +} + +void PlacesModelItem::setPath(FmPath* path) { + if(path_) + fm_path_unref(path_); + path_ = path ? fm_path_ref(path) : NULL; +} + +void PlacesModelItem::setIcon(FmIcon* icon) { + if(icon_) + fm_icon_unref(icon_); + if(icon) { + icon_ = fm_icon_ref(icon); + QStandardItem::setIcon(IconTheme::icon(icon_)); + } + else { + icon_ = NULL; + QStandardItem::setIcon(QIcon()); + } +} + +void PlacesModelItem::setIcon(GIcon* gicon) { + FmIcon* icon = gicon ? fm_icon_from_gicon(gicon) : NULL; + setIcon(icon); + fm_icon_unref(icon); +} + +void PlacesModelItem::updateIcon() { + if(icon_) + QStandardItem::setIcon(IconTheme::icon(icon_)); +} + +QVariant PlacesModelItem::data(int role) const { + // we use a QPixmap from FmIcon cache rather than QIcon object for decoration role. + return QStandardItem::data(role); +} + +void PlacesModelItem::setFileInfo(FmFileInfo* fileInfo) { + // FIXME: how can we correctly update icon? + if(fileInfo_) + fm_file_info_unref(fileInfo_); + + if(fileInfo) { + fileInfo_ = fm_file_info_ref(fileInfo); + } + else + fileInfo_ = NULL; +} + +PlacesModelBookmarkItem::PlacesModelBookmarkItem(FmBookmarkItem* bm_item): + PlacesModelItem(QIcon::fromTheme("folder"), QString::fromUtf8(bm_item->name), bm_item->path), + bookmarkItem_(fm_bookmark_item_ref(bm_item)) { + setEditable(true); +} + +PlacesModelVolumeItem::PlacesModelVolumeItem(GVolume* volume): + PlacesModelItem(), + volume_(reinterpret_cast(g_object_ref(volume))) { + update(); + setEditable(false); +} + +void PlacesModelVolumeItem::update() { + // set title + setText(QString::fromUtf8(g_volume_get_name(volume_))); + + // set icon + GIcon* gicon = g_volume_get_icon(volume_); + setIcon(gicon); + g_object_unref(gicon); + + // set dir path + GMount* mount = g_volume_get_mount(volume_); + if(mount) { + GFile* mount_root = g_mount_get_root(mount); + FmPath* mount_path = fm_path_new_for_gfile(mount_root); + setPath(mount_path); + fm_path_unref(mount_path); + g_object_unref(mount_root); + g_object_unref(mount); + } + else { + setPath(NULL); + } +} + + +bool PlacesModelVolumeItem::isMounted() { + GMount* mount = g_volume_get_mount(volume_); + if(mount) + g_object_unref(mount); + return mount != NULL ? true : false; +} + + +PlacesModelMountItem::PlacesModelMountItem(GMount* mount): + PlacesModelItem(), + mount_(reinterpret_cast(mount)) { + update(); + setEditable(false); +} + +void PlacesModelMountItem::update() { + // set title + setText(QString::fromUtf8(g_mount_get_name(mount_))); + + // set path + GFile* mount_root = g_mount_get_root(mount_); + FmPath* mount_path = fm_path_new_for_gfile(mount_root); + setPath(mount_path); + fm_path_unref(mount_path); + g_object_unref(mount_root); + + // set icon + GIcon* gicon = g_mount_get_icon(mount_); + setIcon(gicon); + g_object_unref(gicon); +} + +} diff --git a/libfm-qt/placesmodelitem.h b/libfm-qt/placesmodelitem.h new file mode 100644 index 0000000..7f07661 --- /dev/null +++ b/libfm-qt/placesmodelitem.h @@ -0,0 +1,130 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_PLACESMODELITEM_H +#define FM_PLACESMODELITEM_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include + +namespace Fm { + +// model item +class LIBFM_QT_API PlacesModelItem : public QStandardItem { +public: + enum Type { + Places = QStandardItem::UserType + 1, + Volume, + Mount, + Bookmark + }; + +public: + PlacesModelItem(); + PlacesModelItem(QIcon icon, QString title, FmPath* path = NULL); + PlacesModelItem(const char* iconName, QString title, FmPath* path = NULL); + PlacesModelItem(FmIcon* icon, QString title, FmPath* path = NULL); + ~PlacesModelItem(); + + FmFileInfo* fileInfo() { + return fileInfo_; + } + void setFileInfo(FmFileInfo* fileInfo); + + FmPath* path() { + return path_; + } + void setPath(FmPath* path); + + FmIcon* icon() { + return icon_; + } + void setIcon(FmIcon* icon); + void setIcon(GIcon* gicon); + void updateIcon(); + + QVariant data(int role = Qt::UserRole + 1) const; + + virtual int type() const { + return Places; + } + +private: + FmPath* path_; + FmFileInfo* fileInfo_; + FmIcon* icon_; +}; + +class LIBFM_QT_API PlacesModelVolumeItem : public PlacesModelItem { +public: + PlacesModelVolumeItem(GVolume* volume); + bool isMounted(); + bool canEject() { + return g_volume_can_eject(volume_); + } + virtual int type() const { + return Volume; + } + GVolume* volume() { + return volume_; + } + void update(); +private: + GVolume* volume_; +}; + +class LIBFM_QT_API PlacesModelMountItem : public PlacesModelItem { +public: + PlacesModelMountItem(GMount* mount); + virtual int type() const { + return Mount; + } + GMount* mount() const { + return mount_; + } + void update(); +private: + GMount* mount_; +}; + +class LIBFM_QT_API PlacesModelBookmarkItem : public PlacesModelItem { +public: + virtual int type() const { + return Bookmark; + } + PlacesModelBookmarkItem(FmBookmarkItem* bm_item); + virtual ~PlacesModelBookmarkItem() { + if(bookmarkItem_) + fm_bookmark_item_unref(bookmarkItem_); + } + FmBookmarkItem* bookmark() const { + return bookmarkItem_; + } +private: + FmBookmarkItem* bookmarkItem_; +}; + +} + +#endif // FM_PLACESMODELITEM_H diff --git a/libfm-qt/placesview.cpp b/libfm-qt/placesview.cpp new file mode 100644 index 0000000..a13e26a --- /dev/null +++ b/libfm-qt/placesview.cpp @@ -0,0 +1,332 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + 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 "placesview.h" +#include "placesmodel.h" +#include "placesmodelitem.h" +#include "mountoperation.h" +#include "fileoperation.h" +#include +#include +#include +#include +#include + +using namespace Fm; + +PlacesView::PlacesView(QWidget* parent): + QTreeView(parent), + currentPath_(NULL) { + setRootIsDecorated(false); + setHeaderHidden(true); + setIndentation(12); + + connect(this, &QTreeView::clicked, this, &PlacesView::onClicked); + connect(this, &QTreeView::pressed, this, &PlacesView::onPressed); + + setIconSize(QSize(24, 24)); + + // FIXME: we may share this model amont all views + model_ = new PlacesModel(this); + setModel(model_); + + QHeaderView* headerView = header(); + headerView->setSectionResizeMode(0, QHeaderView::Stretch); + headerView->setSectionResizeMode(1, QHeaderView::ResizeToContents); + headerView->setStretchLastSection(false); + expandAll(); + + // FIXME: is there any better way to make the first column span the whole row? + setFirstColumnSpanned(0, QModelIndex(), true); // places root + setFirstColumnSpanned(1, QModelIndex(), true); // devices root + setFirstColumnSpanned(2, QModelIndex(), true); // bookmarks root + + // the 2nd column is for the eject buttons + setSelectionBehavior(QAbstractItemView::SelectRows); // FIXME: why this does not work? + setAllColumnsShowFocus(false); + + setAcceptDrops(true); + setDragEnabled(true); +} + +PlacesView::~PlacesView() { + if(currentPath_) + fm_path_unref(currentPath_); + // qDebug("delete PlacesView"); +} + +void PlacesView::activateRow(int type, const QModelIndex& index) { + if(!index.parent().isValid()) // ignore root items + return; + PlacesModelItem* item = static_cast(model_->itemFromIndex(index)); + if(item) { + FmPath* path = item->path(); + if(!path) { + // check if mounting volumes is needed + if(item->type() == PlacesModelItem::Volume) { + PlacesModelVolumeItem* volumeItem = static_cast(item); + if(!volumeItem->isMounted()) { + // Mount the volume + GVolume* volume = volumeItem->volume(); + MountOperation* op = new MountOperation(true, this); + op->mount(volume); + // connect(op, SIGNAL(finished(GError*)), SLOT(onMountOperationFinished(GError*))); + // blocking here until the mount operation is finished? + + // FIXME: update status of the volume after mount is finished!! + if(!op->wait()) + return; + path = item->path(); + } + } + } + if(path) { + Q_EMIT chdirRequested(type, path); + } + } +} + +// mouse button pressed +void PlacesView::onPressed(const QModelIndex& index) { + // if middle button is pressed + if(QGuiApplication::mouseButtons() & Qt::MiddleButton) { + activateRow(1, index); + } +} + +void PlacesView::onEjectButtonClicked(PlacesModelItem* item) { + // The eject button is clicked for a device item (volume or mount) + if(item->type() == PlacesModelItem::Volume) { + PlacesModelVolumeItem* volumeItem = static_cast(item); + MountOperation* op = new MountOperation(true, this); + if(volumeItem->canEject()) // do eject if applicable + op->eject(volumeItem->volume()); + else // otherwise, do unmount instead + op->unmount(volumeItem->volume()); + } + else if(item->type() == PlacesModelItem::Mount) { + PlacesModelMountItem* mountItem = static_cast(item); + MountOperation* op = new MountOperation(true, this); + op->unmount(mountItem->mount()); + } + qDebug("PlacesView::onEjectButtonClicked"); +} + +void PlacesView::onClicked(const QModelIndex& index) { + if(!index.parent().isValid()) // ignore root items + return; + + if(index.column() == 0) { + activateRow(0, index); + } + else if(index.column() == 1) { // column 1 contains eject buttons of the mounted devices + if(index.parent() == model_->devicesRoot->index()) { // this is a mounted device + // the eject button is clicked + QModelIndex itemIndex = index.sibling(index.row(), 0); // the real item is at column 0 + PlacesModelItem* item = static_cast(model_->itemFromIndex(itemIndex)); + if(item) { + // eject the volume or the mount + onEjectButtonClicked(item); + } + } + } +} + +void PlacesView::setCurrentPath(FmPath* path) { + if(currentPath_) + fm_path_unref(currentPath_); + if(path) { + currentPath_ = fm_path_ref(path); + // TODO: search for item with the path in model_ and select it. + PlacesModelItem* item = model_->itemFromPath(currentPath_); + if(item) { + selectionModel()->select(item->index(), QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); + } + else + clearSelection(); + } + else { + currentPath_ = NULL; + clearSelection(); + } +} + + +void PlacesView::dragMoveEvent(QDragMoveEvent* event) { + QTreeView::dragMoveEvent(event); + /* + QModelIndex index = indexAt(event->pos()); + if(event->isAccepted() && index.isValid() && index.parent() == model_->bookmarksRoot->index()) { + if(dropIndicatorPosition() != OnItem) { + event->setDropAction(Qt::LinkAction); + event->accept(); + } + } + */ +} + +void PlacesView::dropEvent(QDropEvent* event) { + QTreeView::dropEvent(event); +} + +void PlacesView::onEmptyTrash() { + FmPathList* files = fm_path_list_new(); + fm_path_list_push_tail(files, fm_path_get_trash()); + Fm::FileOperation::deleteFiles(files); + fm_path_list_unref(files); +} + +void PlacesView::onDeleteBookmark() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelBookmarkItem* item = static_cast(model_->itemFromIndex(action->index())); + FmBookmarkItem* bookmarkItem = item->bookmark(); + FmBookmarks* bookmarks = fm_bookmarks_dup(); + fm_bookmarks_remove(bookmarks, bookmarkItem); + g_object_unref(bookmarks); +} + +// virtual +void PlacesView::commitData(QWidget * editor) { + QTreeView::commitData(editor); + PlacesModelBookmarkItem* item = static_cast(model_->itemFromIndex(currentIndex())); + FmBookmarkItem* bookmarkItem = item->bookmark(); + FmBookmarks* bookmarks = fm_bookmarks_dup(); + // rename bookmark + fm_bookmarks_rename(bookmarks, bookmarkItem, item->text().toUtf8().constData()); + g_object_unref(bookmarks); +} + +void PlacesView::onRenameBookmark() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelBookmarkItem* item = static_cast(model_->itemFromIndex(action->index())); + setFocus(); + setCurrentIndex(item->index()); + edit(item->index()); +} + +void PlacesView::onMountVolume() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelVolumeItem* item = static_cast(model_->itemFromIndex(action->index())); + MountOperation* op = new MountOperation(true, this); + op->mount(item->volume()); + op->wait(); +} + +void PlacesView::onUnmountVolume() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelVolumeItem* item = static_cast(model_->itemFromIndex(action->index())); + GMount* mount = NULL; + MountOperation* op = new MountOperation(true, this); + op->unmount(item->volume()); + op->wait(); +} + +void PlacesView::onUnmountMount() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelMountItem* item = static_cast(model_->itemFromIndex(action->index())); + GMount* mount = item->mount(); + MountOperation* op = new MountOperation(true, this); + op->unmount(mount); + op->wait(); +} + +void PlacesView::onEjectVolume() { + PlacesModel::ItemAction* action = static_cast(sender()); + if(!action->index().isValid()) + return; + PlacesModelVolumeItem* item = static_cast(model_->itemFromIndex(action->index())); + MountOperation* op = new MountOperation(true, this); + op->eject(item->volume()); + op->wait(); +} + +void PlacesView::contextMenuEvent(QContextMenuEvent* event) { + QModelIndex index = indexAt(event->pos()); + if(index.isValid() && index.parent().isValid()) { + QMenu* menu = NULL; + QAction* action; + PlacesModelItem* item = static_cast(model_->itemFromIndex(index)); + switch(item->type()) { + case PlacesModelItem::Places: { + FmPath* path = item->path(); + if(path && fm_path_equal(fm_path_get_trash(), path)) { + menu = new QMenu(this); + action = new PlacesModel::ItemAction(item->index(), tr("Empty Trash"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onEmptyTrash); + menu->addAction(action); + } + break; + } + case PlacesModelItem::Bookmark: { + // create context menu for bookmark item + menu = new QMenu(this); + action = new PlacesModel::ItemAction(item->index(), tr("Rename"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onRenameBookmark); + menu->addAction(action); + action = new PlacesModel::ItemAction(item->index(), tr("Delete"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onDeleteBookmark); + menu->addAction(action); + break; + } + case PlacesModelItem::Volume: { + PlacesModelVolumeItem* volumeItem = static_cast(item); + menu = new QMenu(this); + + if(volumeItem->isMounted()) { + action = new PlacesModel::ItemAction(item->index(), tr("Unmount"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onUnmountVolume); + } + else { + action = new PlacesModel::ItemAction(item->index(), tr("Mount"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onMountVolume); + } + menu->addAction(action); + + if(volumeItem->canEject()) { + action = new PlacesModel::ItemAction(item->index(), tr("Eject"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onEjectVolume); + menu->addAction(action); + } + break; + } + case PlacesModelItem::Mount: { + menu = new QMenu(this); + action = new PlacesModel::ItemAction(item->index(), tr("Unmount"), menu); + connect(action, &QAction::triggered, this, &PlacesView::onUnmountMount); + menu->addAction(action); + break; + } + } + if(menu) { + menu->popup(mapToGlobal(event->pos())); + connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); + } + } +} diff --git a/libfm-qt/placesview.h b/libfm-qt/placesview.h new file mode 100644 index 0000000..4959111 --- /dev/null +++ b/libfm-qt/placesview.h @@ -0,0 +1,94 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + 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 FM_PLACESVIEW_H +#define FM_PLACESVIEW_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Fm { + +class PlacesModel; +class PlacesModelItem; + +class LIBFM_QT_API PlacesView : public QTreeView { +Q_OBJECT + +public: + explicit PlacesView(QWidget* parent = 0); + virtual ~PlacesView(); + + void setCurrentPath(FmPath* path); + FmPath* currentPath() { + return currentPath_; + } + + // libfm-gtk compatible alias + FmPath* getCwd() { + return currentPath(); + } + + void chdir(FmPath* path) { + setCurrentPath(path); + } + +Q_SIGNALS: + void chdirRequested(int type, FmPath* path); + +protected Q_SLOTS: + void onClicked(const QModelIndex & index); + void onPressed(const QModelIndex & index); + // void onMountOperationFinished(GError* error); + + void onEmptyTrash(); + + void onMountVolume(); + void onUnmountVolume(); + void onEjectVolume(); + void onUnmountMount(); + + void onDeleteBookmark(); + void onRenameBookmark(); + +protected: + void drawBranches ( QPainter * painter, const QRect & rect, const QModelIndex & index ) const { + // override this method to inhibit drawing of the branch grid lines by Qt. + } + + virtual void dragMoveEvent(QDragMoveEvent* event); + virtual void dropEvent(QDropEvent* event); + virtual void contextMenuEvent(QContextMenuEvent* event); + + virtual void commitData(QWidget * editor); + +private: + void onEjectButtonClicked(PlacesModelItem* item); + void activateRow(int type, const QModelIndex& index); + +private: + PlacesModel* model_; + FmPath* currentPath_; +}; + +} + +#endif // FM_PLACESVIEW_H diff --git a/libfm-qt/proxyfoldermodel.cpp b/libfm-qt/proxyfoldermodel.cpp new file mode 100644 index 0000000..b74cf3f --- /dev/null +++ b/libfm-qt/proxyfoldermodel.cpp @@ -0,0 +1,269 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#include "proxyfoldermodel.h" +#include "foldermodel.h" +#include + +using namespace Fm; + +ProxyFolderModel::ProxyFolderModel(QObject * parent): + QSortFilterProxyModel(parent), + thumbnailSize_(0), + showHidden_(false), + showThumbnails_(false), + folderFirst_(true) { + setDynamicSortFilter(true); + setSortCaseSensitivity(Qt::CaseInsensitive); +} + +ProxyFolderModel::~ProxyFolderModel() { + qDebug("delete ProxyFolderModel"); + + if(showThumbnails_ && thumbnailSize_ != 0) { + FolderModel* srcModel = static_cast(sourceModel()); + // tell the source model that we don't need the thumnails anymore + if(srcModel) { + srcModel->releaseThumbnails(thumbnailSize_); + disconnect(srcModel, SIGNAL(thumbnailLoaded(QModelIndex,int))); + } + } +} + +void ProxyFolderModel::setSourceModel(QAbstractItemModel* model) { + if(model) { + // we only support Fm::FolderModel + Q_ASSERT(model->inherits("Fm::FolderModel")); + + if(showThumbnails_ && thumbnailSize_ != 0) { // if we're showing thumbnails + FolderModel* oldSrcModel = static_cast(sourceModel()); + FolderModel* newSrcModel = static_cast(model); + if(oldSrcModel) { // we need to release cached thumbnails for the old source model + oldSrcModel->releaseThumbnails(thumbnailSize_); + disconnect(oldSrcModel, SIGNAL(thumbnailLoaded(QModelIndex,int))); + } + if(newSrcModel) { // tell the new source model that we want thumbnails of this size + newSrcModel->cacheThumbnails(thumbnailSize_); + connect(newSrcModel, &FolderModel::thumbnailLoaded, this, &ProxyFolderModel::onThumbnailLoaded); + } + } + } + QSortFilterProxyModel::setSourceModel(model); +} + +void ProxyFolderModel::sort(int column, Qt::SortOrder order) { + int oldColumn = sortColumn(); + Qt::SortOrder oldOrder = sortOrder(); + QSortFilterProxyModel::sort(column, order); + if(column != oldColumn || order != oldOrder) { + Q_EMIT sortFilterChanged(); + } +} + +void ProxyFolderModel::setShowHidden(bool show) { + if(show != showHidden_) { + showHidden_ = show; + invalidateFilter(); + Q_EMIT sortFilterChanged(); + } +} + +// need to call invalidateFilter() manually. +void ProxyFolderModel::setFolderFirst(bool folderFirst) { + if(folderFirst != folderFirst_) { + folderFirst_ = folderFirst; + invalidate(); + Q_EMIT sortFilterChanged(); + } +} + +bool ProxyFolderModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const { + if(!showHidden_) { + QAbstractItemModel* srcModel = sourceModel(); + QString name = srcModel->data(srcModel->index(source_row, 0, source_parent)).toString(); + if(name.startsWith(".") || name.endsWith("~")) + return false; + } + // apply additional filters if there're any + Q_FOREACH(ProxyFolderModelFilter* filter, filters_) { + FolderModel* srcModel = static_cast(sourceModel()); + FmFileInfo* fileInfo = srcModel->fileInfoFromIndex(srcModel->index(source_row, 0, source_parent)); + if(!filter->filterAcceptsRow(this, fileInfo)) + return false; + } + return true; +} + +bool ProxyFolderModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { + FolderModel* srcModel = static_cast(sourceModel()); + // left and right are indexes of source model, not the proxy model. + if(srcModel) { + FmFileInfo* leftInfo = srcModel->fileInfoFromIndex(left); + FmFileInfo* rightInfo = srcModel->fileInfoFromIndex(right); + + if(folderFirst_) { + bool leftIsFolder = (bool)fm_file_info_is_dir(leftInfo); + bool rightIsFolder = (bool)fm_file_info_is_dir(rightInfo); + if(leftIsFolder != rightIsFolder) + return leftIsFolder ? true : false; + } + + switch(sortColumn()) { + case FolderModel::ColumnFileName: + if(sortCaseSensitivity() == Qt::CaseSensitive) { + // fm_file_info_get_collate_key_nocasefold() uses g_utf8_casefold() from glib internally, which + // is only an approximation not working correctly in some locales. + // FIXME: we may use QCollator (since Qt 5.2) for this, but the performance impact is unknown + return strcmp(fm_file_info_get_collate_key_nocasefold(leftInfo), fm_file_info_get_collate_key_nocasefold(rightInfo)) < 0; + /* + QCollator coll; + coll.setCaseSensitivity(Qt::CaseSensitive); + coll.setIgnorePunctuation(false); + coll.setNumericMode(true); + return coll.compare(QString::fromUtf8(fm_file_info_get_disp_name(leftInfo)), QString::fromUtf8(fm_file_info_get_disp_name(rightInfo))) < 0; + */ + } + else { + // linguistic case insensitive ordering + return strcmp(fm_file_info_get_collate_key(leftInfo), fm_file_info_get_collate_key(rightInfo)) < 0; + } + case FolderModel::ColumnFileMTime: + return fm_file_info_get_mtime(leftInfo) < fm_file_info_get_mtime(rightInfo); + case FolderModel::ColumnFileSize: + return fm_file_info_get_size(leftInfo) < fm_file_info_get_size(rightInfo); + case FolderModel::ColumnFileOwner: + // TODO: sort by owner + break; + case FolderModel::ColumnFileType: + break; + } + } + return QSortFilterProxyModel::lessThan(left, right); +} + +FmFileInfo* ProxyFolderModel::fileInfoFromIndex(const QModelIndex& index) const { + FolderModel* srcModel = static_cast(sourceModel()); + if(srcModel) { + QModelIndex srcIndex = mapToSource(index); + return srcModel->fileInfoFromIndex(srcIndex); + } + return NULL; +} + +void ProxyFolderModel::setShowThumbnails(bool show) { + if(show != showThumbnails_) { + showThumbnails_ = show; + FolderModel* srcModel = static_cast(sourceModel()); + if(srcModel && thumbnailSize_ != 0) { + if(show) { + // ask for cache of thumbnails of the new size in source model + srcModel->cacheThumbnails(thumbnailSize_); + // connect to the srcModel so we can be notified when a thumbnail is loaded. + connect(srcModel, &FolderModel::thumbnailLoaded, this, &ProxyFolderModel::onThumbnailLoaded); + } + else { // turn off thumbnails + // free cached old thumbnails in souce model + srcModel->releaseThumbnails(thumbnailSize_); + disconnect(srcModel, SIGNAL(thumbnailLoaded(QModelIndex,int))); + } + // reload all items, FIXME: can we only update items previously having thumbnails + Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0)); + } + } +} + +void ProxyFolderModel::setThumbnailSize(int size) { + if(size != thumbnailSize_) { + FolderModel* srcModel = static_cast(sourceModel()); + if(showThumbnails_ && srcModel) { + // free cached thumbnails of the old size + if(thumbnailSize_ != 0) + srcModel->releaseThumbnails(thumbnailSize_); + else { + // if the old thumbnail size is 0, we did not turn on thumbnail initially + connect(srcModel, &FolderModel::thumbnailLoaded, this, &ProxyFolderModel::onThumbnailLoaded); + } + // ask for cache of thumbnails of the new size in source model + srcModel->cacheThumbnails(size); + // reload all items, FIXME: can we only update items previously having thumbnails + Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0)); + } + + thumbnailSize_ = size; + } +} + +QVariant ProxyFolderModel::data(const QModelIndex& index, int role) const { + if(index.column() == 0) { // only show the decoration role for the first column + if(role == Qt::DecorationRole && showThumbnails_ && thumbnailSize_) { + // we need to show thumbnails instead of icons + FolderModel* srcModel = static_cast(sourceModel()); + QModelIndex srcIndex = mapToSource(index); + QImage image = srcModel->thumbnailFromIndex(srcIndex, thumbnailSize_); + if(!image.isNull()) // if we got a thumbnail of the desired size, use it + return QVariant(image); + } + } + // fallback to icons if thumbnails are not available + return QSortFilterProxyModel::data(index, role); +} + +void ProxyFolderModel::onThumbnailLoaded(const QModelIndex& srcIndex, int size) { + + FolderModel* srcModel = static_cast(sourceModel()); + FolderModelItem* item = srcModel->itemFromIndex(srcIndex); + // qDebug("ProxyFolderModel::onThumbnailLoaded: %d, %s", size, item->displayName.toUtf8().data()); + + if(size == thumbnailSize_) { // if a thumbnail of the size we want is loaded + QModelIndex index = mapFromSource(srcIndex); + Q_EMIT dataChanged(index, index); + } +} + +void ProxyFolderModel::addFilter(ProxyFolderModelFilter* filter) { + filters_.append(filter); + invalidateFilter(); + Q_EMIT sortFilterChanged(); +} + +void ProxyFolderModel::removeFilter(ProxyFolderModelFilter* filter) { + filters_.removeOne(filter); + invalidateFilter(); + Q_EMIT sortFilterChanged(); +} + + +#if 0 +void ProxyFolderModel::reloadAllThumbnails() { + // reload all thumbnails and update UI + FolderModel* srcModel = static_cast(sourceModel()); + if(srcModel) { + int rows= rowCount(); + for(int row = 0; row < rows; ++row) { + QModelIndex index = this->index(row, 0); + QModelIndex srcIndex = mapToSource(index); + QImage image = srcModel->thumbnailFromIndex(srcIndex, size); + // tell the world that the item is changed to trigger a UI update + if(!image.isNull()) + Q_EMIT dataChanged(index, index); + } + } +} +#endif diff --git a/libfm-qt/proxyfoldermodel.h b/libfm-qt/proxyfoldermodel.h new file mode 100644 index 0000000..e24567d --- /dev/null +++ b/libfm-qt/proxyfoldermodel.h @@ -0,0 +1,110 @@ +/* + + Copyright (C) 2012 Hong Jen Yee (PCMan) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef FM_PROXYFOLDERMODEL_H +#define FM_PROXYFOLDERMODEL_H + +#include "libfmqtglobals.h" +#include +#include +#include + +namespace Fm { + +// a proxy model used to sort and filter FolderModel + +class FolderModelItem; +class ProxyFolderModel; + +class LIBFM_QT_API ProxyFolderModelFilter { +public: + virtual bool filterAcceptsRow(const ProxyFolderModel* model, FmFileInfo* info) const = 0; + virtual ~ProxyFolderModelFilter() {} +}; + + +class LIBFM_QT_API ProxyFolderModel : public QSortFilterProxyModel { + Q_OBJECT +public: + +public: + explicit ProxyFolderModel(QObject * parent = 0); + virtual ~ProxyFolderModel(); + + // only Fm::FolderModel is allowed for being sourceModel + virtual void setSourceModel(QAbstractItemModel* model); + + void setShowHidden(bool show); + bool showHidden() { + return showHidden_; + } + + void setFolderFirst(bool folderFirst); + bool folderFirst() { + return folderFirst_; + } + + void setSortCaseSensitivity(Qt::CaseSensitivity cs) { + QSortFilterProxyModel::setSortCaseSensitivity(cs); + Q_EMIT sortFilterChanged(); + } + + bool showThumbnails() { + return showThumbnails_; + } + void setShowThumbnails(bool show); + + int thumbnailSize() { + return thumbnailSize_; + } + void setThumbnailSize(int size); + + FmFileInfo* fileInfoFromIndex(const QModelIndex& index) const; + + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + + void addFilter(ProxyFolderModelFilter* filter); + void removeFilter(ProxyFolderModelFilter* filter); + +Q_SIGNALS: + void sortFilterChanged(); + +protected Q_SLOTS: + void onThumbnailLoaded(const QModelIndex& srcIndex, int size); + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const; + bool lessThan(const QModelIndex & left, const QModelIndex & right) const; + // void reloadAllThumbnails(); + +private: + +private: + bool showHidden_; + bool folderFirst_; + bool showThumbnails_; + int thumbnailSize_; + QList filters_; +}; + +} + +#endif // FM_PROXYFOLDERMODEL_H diff --git a/libfm-qt/rename-dialog.ui b/libfm-qt/rename-dialog.ui new file mode 100644 index 0000000..2b0c123 --- /dev/null +++ b/libfm-qt/rename-dialog.ui @@ -0,0 +1,204 @@ + + + RenameDialog + + + + 0 + 0 + 398 + 220 + + + + Confirm to replace files + + + false + + + + 6 + + + 10 + + + + + + 0 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + + + + + + + 12 + + + 6 + + + + + + 0 + 0 + + + + dest + + + + + + + with the following file? + + + + + + + + 0 + 0 + + + + src file info + + + + + + + + 0 + 0 + + + + dest file info + + + + + + + + 0 + 0 + + + + src + + + + + + + + + 12 + + + + + + 0 + 0 + + + + &File name: + + + fileName + + + + + + + + + + + + Apply this option to all existing files + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ignore|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + RenameDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + RenameDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/libfm-qt/renamedialog.cpp b/libfm-qt/renamedialog.cpp new file mode 100644 index 0000000..c9b5b8f --- /dev/null +++ b/libfm-qt/renamedialog.cpp @@ -0,0 +1,137 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "renamedialog.h" +#include "ui_rename-dialog.h" +#include +#include +#include "icontheme.h" + +using namespace Fm; + +RenameDialog::RenameDialog(FmFileInfo* src, FmFileInfo* dest, QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f), + action_(ActionIgnore), + applyToAll_(false) { + + ui = new Ui::RenameDialog(); + ui->setupUi(this); + + FmPath* path = fm_file_info_get_path(dest); + FmIcon* srcIcon = fm_file_info_get_icon(src); + FmIcon* destIcon = fm_file_info_get_icon(dest); + + // show info for the source file + QIcon icon = IconTheme::icon(srcIcon); + QSize iconSize(fm_config->big_icon_size, fm_config->big_icon_size); + QPixmap pixmap = icon.pixmap(iconSize); + ui->srcIcon->setPixmap(pixmap); + + QString infoStr; + const char* disp_size = fm_file_info_get_disp_size(src); + if(disp_size) { + infoStr = QString(tr("Type: %1\nSize: %2\nModified: %3")) + .arg(QString::fromUtf8(fm_file_info_get_desc(src))) + .arg(QString::fromUtf8(disp_size)) + .arg(QString::fromUtf8(fm_file_info_get_disp_mtime(src))); + } + else { + infoStr = QString(tr("Type: %1\nModified: %2")) + .arg(QString::fromUtf8(fm_file_info_get_desc(src))) + .arg(QString::fromUtf8(fm_file_info_get_disp_mtime(src))); + } + ui->srcInfo->setText(infoStr); + + // show info for the dest file + icon = IconTheme::icon(destIcon); + pixmap = icon.pixmap(iconSize); + ui->destIcon->setPixmap(pixmap); + + disp_size = fm_file_info_get_disp_size(dest); + if(disp_size) { + infoStr = QString(tr("Type: %1\nSize: %2\nModified: %3")) + .arg(QString::fromUtf8(fm_file_info_get_desc(dest))) + .arg(QString::fromUtf8(disp_size)) + .arg(QString::fromUtf8(fm_file_info_get_disp_mtime(dest))); + } + else { + infoStr = QString(tr("Type: %1\nModified: %3")) + .arg(QString::fromUtf8(fm_file_info_get_desc(src))) + .arg(QString::fromUtf8(fm_file_info_get_disp_mtime(src))); + } + ui->destInfo->setText(infoStr); + + char* basename = fm_path_display_basename(path); + ui->fileName->setText(QString::fromUtf8(basename)); + oldName_ = basename; + g_free(basename); + connect(ui->fileName, &QLineEdit::textChanged, this, &RenameDialog::onFileNameChanged); + + // add "Rename" button + QAbstractButton* button = ui->buttonBox->button(QDialogButtonBox::Ok); + button->setText(tr("&Overwrite")); + // FIXME: there seems to be no way to place the Rename button next to the overwrite one. + renameButton_ = ui->buttonBox->addButton(tr("&Rename"), QDialogButtonBox::ActionRole); + connect(renameButton_, &QPushButton::clicked, this, &RenameDialog::onRenameClicked); + renameButton_->setEnabled(false); // disabled by default + + button = ui->buttonBox->button(QDialogButtonBox::Ignore); + connect(button, &QPushButton::clicked, this, &RenameDialog::onIgnoreClicked); +} + +RenameDialog::~RenameDialog() { + delete ui; +} + +void RenameDialog::onRenameClicked() { + action_ = ActionRename; + QDialog::done(QDialog::Accepted); +} + +void RenameDialog::onIgnoreClicked() { + action_ = ActionIgnore; +} + +// the overwrite button +void RenameDialog::accept() { + action_ = ActionOverwrite; + applyToAll_ = ui->applyToAll->isChecked(); + QDialog::accept(); +} + +// cancel, or close the dialog +void RenameDialog::reject() { + action_ = ActionCancel; + QDialog::reject(); +} + +void RenameDialog::onFileNameChanged(QString newName) { + newName_ = newName; + // FIXME: check if the name already exists in the current dir + bool hasNewName = (newName_ != oldName_); + renameButton_->setEnabled(hasNewName); + renameButton_->setDefault(hasNewName); + + // change default button to rename rather than overwrire + // if the user typed a new filename + QPushButton* overwriteButton = static_cast(ui->buttonBox->button(QDialogButtonBox::Ok)); + overwriteButton->setEnabled(!hasNewName); + overwriteButton->setDefault(!hasNewName); +} diff --git a/libfm-qt/renamedialog.h b/libfm-qt/renamedialog.h new file mode 100644 index 0000000..b98ba27 --- /dev/null +++ b/libfm-qt/renamedialog.h @@ -0,0 +1,83 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_RENAMEDIALOG_H +#define FM_RENAMEDIALOG_H + +#include "libfmqtglobals.h" +#include +#include + +namespace Ui { + class RenameDialog; +}; + +class QPushButton; + +namespace Fm { + +class LIBFM_QT_API RenameDialog : public QDialog { +Q_OBJECT + +public: + enum Action { + ActionCancel, + ActionRename, + ActionOverwrite, + ActionIgnore + }; + +public: + explicit RenameDialog(FmFileInfo* src, FmFileInfo* dest, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~RenameDialog(); + + Action action() { + return action_; + } + + bool applyToAll() { + return applyToAll_; + } + + QString newName() { + return newName_; + } + +protected Q_SLOTS: + void onRenameClicked(); + void onIgnoreClicked(); + void onFileNameChanged(QString newName); + +protected: + void accept(); + void reject(); + +private: + Ui::RenameDialog* ui; + QPushButton* renameButton_; + Action action_; + bool applyToAll_; + QString oldName_; + QString newName_; +}; + +} + +#endif // FM_RENAMEDIALOG_H diff --git a/libfm-qt/sidepane.cpp b/libfm-qt/sidepane.cpp new file mode 100644 index 0000000..c86497d --- /dev/null +++ b/libfm-qt/sidepane.cpp @@ -0,0 +1,234 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "sidepane.h" +#include +#include +#include +#include "placesview.h" +#include "dirtreeview.h" +#include "dirtreemodel.h" +#include "path.h" + +namespace Fm { + +SidePane::SidePane(QWidget* parent): + QWidget(parent), + showHidden_(false), + mode_(ModeNone), + view_(NULL), + combo_(NULL), + currentPath_(NULL), + iconSize_(24, 24) { + + verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + combo_ = new QComboBox(this); + combo_->setFrame(false); + combo_->addItem(tr("Places")); + combo_->addItem(tr("Directory Tree")); + connect(combo_, static_cast(&QComboBox::currentIndexChanged), this, &SidePane::onComboCurrentIndexChanged); + verticalLayout->addWidget(combo_); +} + +SidePane::~SidePane() { + if(currentPath_) + fm_path_unref(currentPath_); + // qDebug("delete SidePane"); +} + +void SidePane::onPlacesViewChdirRequested(int type, FmPath* path) { + Q_EMIT chdirRequested(type, path); +} + +void SidePane::onDirTreeViewChdirRequested(int type, FmPath* path) { + Q_EMIT chdirRequested(type, path); +} + +void SidePane::onComboCurrentIndexChanged(int current) { + if(current != mode_) { + setMode(Mode(current)); + } +} + +void SidePane::setIconSize(QSize size) { + iconSize_ = size; + switch(mode_) { + case ModePlaces: + case ModeDirTree: + static_cast(view_)->setIconSize(size); + break; + default:; + } +} + +void SidePane::setCurrentPath(FmPath* path) { + Q_ASSERT(path != NULL); + if(currentPath_) + fm_path_unref(currentPath_); + currentPath_ = fm_path_ref(path); + switch(mode_) { + case ModePlaces: + static_cast(view_)->setCurrentPath(path); + break; + case ModeDirTree: + static_cast(view_)->setCurrentPath(path); + break; + default:; + } +} + +SidePane::Mode SidePane::modeByName(const char* str) { + if(str == NULL) + return ModeNone; + if(strcmp(str, "places") == 0) + return ModePlaces; + if(strcmp(str, "dirtree") == 0) + return ModeDirTree; + return ModeNone; +} + +const char* SidePane::modeName(SidePane::Mode mode) { + switch(mode) { + case ModePlaces: + return "places"; + case ModeDirTree: + return "dirtree"; + default: + return NULL; + } +} + +#if 0 // FIXME: are these APIs from libfm-qt needed? + +QString SidePane::modeLabel(SidePane::Mode mode) { + switch(mode) { + case ModePlaces: + return tr("Places"); + case ModeDirTree: + return tr("Directory Tree"); + } + return QString(); +} + +QString SidePane::modeTooltip(SidePane::Mode mode) { + switch(mode) { + case ModePlaces: + return tr("Shows list of common places, devices, and bookmarks in sidebar"); + case ModeDirTree: + return tr("Shows tree of directories in sidebar"); + } + return QString(); +} +#endif + +bool SidePane::setHomeDir(const char* home_dir) { + if(view_ == NULL) + return false; + // TODO: SidePane::setHomeDir + + switch(mode_) { + case ModePlaces: + // static_cast(view_); + return true; + case ModeDirTree: + // static_cast(view_); + return true; + default:; + } + return true; +} + +void SidePane::initDirTree() { + // TODO + DirTreeModel* model = new DirTreeModel(view_); + FmFileInfoJob* job = fm_file_info_job_new(NULL, FM_FILE_INFO_JOB_NONE); + + GList* l; + /* query FmFileInfo for home dir and root dir, and then, + * add them to dir tree model */ + fm_file_info_job_add(job, fm_path_get_home()); + fm_file_info_job_add(job, fm_path_get_root()); + /* FIXME: maybe it's cleaner to use run_async here? */ + fm_job_run_sync_with_mainloop(FM_JOB(job)); + for(l = fm_file_info_list_peek_head_link(job->file_infos); l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + model->addRoot(fi); + } + g_object_unref(job); + + static_cast(view_)->setModel(model); +} + +void SidePane::setMode(Mode mode) { + if(mode == mode_) + return; + + if(view_) { + delete view_; + view_ = NULL; + //if(sp->update_popup) + // g_signal_handlers_disconnect_by_func(sp->view, on_item_popup, sp); + } + mode_ = mode; + + combo_->setCurrentIndex(mode); + switch(mode) { + case ModePlaces: { + PlacesView* placesView = new Fm::PlacesView(this); + view_ = placesView; + placesView->setIconSize(iconSize_); + placesView->setCurrentPath(currentPath_); + connect(placesView, &PlacesView::chdirRequested, this, &SidePane::onPlacesViewChdirRequested); + break; + } + case ModeDirTree: { + DirTreeView* dirTreeView = new Fm::DirTreeView(this); + view_ = dirTreeView; + initDirTree(); + dirTreeView->setIconSize(iconSize_); + dirTreeView->setCurrentPath(currentPath_); + connect(dirTreeView, &DirTreeView::chdirRequested, this, &SidePane::onDirTreeViewChdirRequested); + break; + } + default:; + } + if(view_) { + // if(sp->update_popup) + // g_signal_connect(sp->view, "item-popup", G_CALLBACK(on_item_popup), sp); + verticalLayout->addWidget(view_); + } + Q_EMIT modeChanged(); +} + +bool SidePane::setShowHidden(bool show_hidden) { + if(view_ == NULL) + return false; + // TODO: SidePane::setShowHidden + + // spec = g_object_class_find_property(klass, "show-hidden"); + //if(spec == NULL || spec->value_type != G_TYPE_BOOLEAN) + // return false; /* isn't supported by view */ + // g_object_set(sp->view, "show-hidden", show_hidden, NULL); + return true; +} + +} // namespace Fm diff --git a/libfm-qt/sidepane.h b/libfm-qt/sidepane.h new file mode 100644 index 0000000..67a7e32 --- /dev/null +++ b/libfm-qt/sidepane.h @@ -0,0 +1,126 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_SIDEPANE_H +#define FM_SIDEPANE_H + +#include "libfmqtglobals.h" +#include +#include + +class QComboBox; +class QVBoxLayout; +class QWidget; + +namespace Fm { + +class LIBFM_QT_API SidePane : public QWidget { + Q_OBJECT + +public: + enum Mode { + ModeNone = -1, + ModePlaces = 0, + ModeDirTree, + NumModes + }; + +public: + explicit SidePane(QWidget* parent = 0); + virtual ~SidePane(); + + QSize iconSize() { + return iconSize_; + } + + void setIconSize(QSize size); + + FmPath* currentPath() { + return currentPath_; + } + + void setCurrentPath(FmPath* path); + + void setMode(Mode mode); + + Mode mode() { + return mode_; + } + + QWidget* view() { + return view_; + } + + const char *modeName(Mode mode); + + Mode modeByName(const char *str); + +#if 0 // FIXME: are these APIs from libfm-qt needed? + int modeCount(void) { + return NumModes; + } + + QString modeLabel(Mode mode); + + QString modeTooltip(Mode mode); +#endif + + bool setShowHidden(bool show_hidden); + + bool showHidden() { + return showHidden_; + } + + bool setHomeDir(const char *home_dir); + + // libfm-gtk compatible alias + FmPath* getCwd() { + return currentPath(); + } + + void chdir(FmPath* path) { + setCurrentPath(path); + } + +Q_SIGNALS: + void chdirRequested(int type, FmPath* path); + void modeChanged(); + +protected Q_SLOTS: + void onPlacesViewChdirRequested(int type, FmPath* path); + void onDirTreeViewChdirRequested(int type, FmPath* path); + void onComboCurrentIndexChanged(int current); + +private: + void initDirTree(); + +private: + FmPath* currentPath_; + QWidget* view_; + QComboBox* combo_; + QVBoxLayout* verticalLayout; + QSize iconSize_; + Mode mode_; + bool showHidden_; +}; + +} + +#endif // FM_SIDEPANE_H diff --git a/libfm-qt/thumbnailloader.cpp b/libfm-qt/thumbnailloader.cpp new file mode 100644 index 0000000..8b6a14b --- /dev/null +++ b/libfm-qt/thumbnailloader.cpp @@ -0,0 +1,195 @@ +/* + + Copyright (C) 2013 PCMan + + 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 "thumbnailloader.h" +#include +#include + +using namespace Fm; + +// FmQImageWrapper is a GObject used to wrap QImage objects and use in glib-based libfm +#define FM_TYPE_QIMAGE_WRAPPER (fm_qimage_wrapper_get_type()) +#define FM_QIMAGE_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ +FM_TYPE_QIMAGE_WRAPPER, FmQImageWrapper)) +#define FM_QIMAGE_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ +FM_TYPE_QIMAGE_WRAPPER, FmQImageWrapperClass)) +#define FM_IS_QIMAGE_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ +FM_TYPE_QIMAGE_WRAPPER)) +#define FM_IS_QIMAGE_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ +FM_TYPE_QIMAGE_WRAPPER)) +#define FM_QIMAGE_WRAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),\ +FM_TYPE_QIMAGE_WRAPPER, FmQImageWrapperClass)) + +typedef struct _FmQImageWrapper FmQImageWrapper; +typedef struct _FmQImageWrapperClass FmQImageWrapperClass; + +struct _FmQImageWrapper { + GObject parent; + QImage image; +}; + +struct _FmQImageWrapperClass { + GObjectClass parent_class; +}; + +GType fm_qimage_wrapper_get_type(void); +GObject* fm_qimage_wrapper_new(void); +static void fm_qimage_wrapper_finalize(GObject *self); + +G_DEFINE_TYPE(FmQImageWrapper, fm_qimage_wrapper, G_TYPE_OBJECT) + +static void fm_qimage_wrapper_class_init(FmQImageWrapperClass *klass) { + GObjectClass* object_class = G_OBJECT_CLASS(klass); + object_class->finalize = fm_qimage_wrapper_finalize; +} + +static void fm_qimage_wrapper_init(FmQImageWrapper *self) { + // placement new for QImage + new(&self->image) QImage(); +} + +static void fm_qimage_wrapper_finalize(GObject *self) { + FmQImageWrapper *wrapper = FM_QIMAGE_WRAPPER(self); + // placement delete + wrapper->image.~QImage(); +} + +GObject *fm_qimage_wrapper_new(QImage& image) { + FmQImageWrapper *wrapper = (FmQImageWrapper*)g_object_new(FM_TYPE_QIMAGE_WRAPPER, NULL); + wrapper->image = image; + return (GObject*)wrapper; +} + +ThumbnailLoader* ThumbnailLoader::theThumbnailLoader = NULL; +bool ThumbnailLoader::localFilesOnly_ = true; +int ThumbnailLoader::maxThumbnailFileSize_ = 0; + +ThumbnailLoader::ThumbnailLoader() { + gboolean success; + // apply the settings to libfm + fm_config->thumbnail_local = localFilesOnly_; + fm_config->thumbnail_max = maxThumbnailFileSize_; + + FmThumbnailLoaderBackend qt_backend = { + readImageFromFile, + readImageFromStream, + writeImage, + scaleImage, + rotateImage, + getImageWidth, + getImageHeight, + getImageText, + setImageText + }; + success = fm_thumbnail_loader_set_backend(&qt_backend); +} + +ThumbnailLoader::~ThumbnailLoader() { + +} + +GObject* ThumbnailLoader::readImageFromFile(const char* filename) { + QImage image; + image.load(QString(filename)); + // qDebug("readImageFromFile: %s, %d", filename, image.isNull()); + return image.isNull() ? NULL : fm_qimage_wrapper_new(image); +} + +GObject* ThumbnailLoader::readImageFromStream(GInputStream* stream, guint64 len, GCancellable* cancellable) { + // qDebug("readImageFromStream: %p, %llu", stream, len); + // FIXME: should we set a limit here? Otherwise if len is too large, we can run out of memory. + unsigned char* buffer = new unsigned char[len]; // allocate enough buffer + unsigned char* pbuffer = buffer; + int totalReadSize = 0; + while(!g_cancellable_is_cancelled(cancellable) && totalReadSize < len) { + int bytesToRead = totalReadSize + 4096 > len ? len - totalReadSize : 4096; + gssize readSize = g_input_stream_read(stream, pbuffer, bytesToRead, cancellable, NULL); + if(readSize == 0) // end of file + break; + else if(readSize == -1) // error + return NULL; + totalReadSize += readSize; + pbuffer += readSize; + } + QImage image; + image.loadFromData(buffer, totalReadSize); + delete []buffer; + return image.isNull() ? NULL : fm_qimage_wrapper_new(image); +} + +gboolean ThumbnailLoader::writeImage(GObject* image, const char* filename) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + if(wrapper->image.isNull()) + return FALSE; + return (gboolean)wrapper->image.save(filename, "PNG"); +} + +GObject* ThumbnailLoader::scaleImage(GObject* ori_pix, int new_width, int new_height) { + // qDebug("scaleImage: %d, %d", new_width, new_height); + FmQImageWrapper* ori_wrapper = FM_QIMAGE_WRAPPER(ori_pix); + QImage scaled = ori_wrapper->image.scaled(new_width, new_height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + return scaled.isNull() ? NULL : fm_qimage_wrapper_new(scaled); +} + +GObject* ThumbnailLoader::rotateImage(GObject* image, int degree) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + // degree values are 0, 90, 180, and 270 counterclockwise. + // In Qt, QMatrix does rotation counterclockwise as well. + // However, because the y axis of widget coordinate system is downward, + // the real effect of the coordinate transformation becomes clockwise rotation. + // So we need to use (360 - degree) here. + // Quote from QMatrix API doc: + // Note that if you apply a QMatrix to a point defined in widget + // coordinates, the direction of the rotation will be clockwise because + // the y-axis points downwards. + QImage rotated = wrapper->image.transformed(QMatrix().rotate(360 - degree)); + return rotated.isNull() ? NULL : fm_qimage_wrapper_new(rotated); +} + +int ThumbnailLoader::getImageWidth(GObject* image) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + return wrapper->image.width(); +} + +int ThumbnailLoader::getImageHeight(GObject* image) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + return wrapper->image.height(); +} + +char* ThumbnailLoader::getImageText(GObject* image, const char* key) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + QByteArray text = wrapper->image.text(key).toLatin1(); + return (char*)g_memdup(text.constData(), text.length()); +} + +gboolean ThumbnailLoader::setImageText(GObject* image, const char* key, const char* val) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(image); + wrapper->image.setText(key, val); + return TRUE; +} + +QImage ThumbnailLoader::image(FmThumbnailLoader* result) { + FmQImageWrapper* wrapper = FM_QIMAGE_WRAPPER(fm_thumbnail_loader_get_data(result)); + if(wrapper) { + return wrapper->image; + } + return QImage(); +} + diff --git a/libfm-qt/thumbnailloader.h b/libfm-qt/thumbnailloader.h new file mode 100644 index 0000000..e7811ed --- /dev/null +++ b/libfm-qt/thumbnailloader.h @@ -0,0 +1,99 @@ +/* + + Copyright (C) 2013 PCMan + + 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 FM_THUMBNAILLOADER_H +#define FM_THUMBNAILLOADER_H + +#include "libfmqtglobals.h" +#include +#include +#include + +namespace Fm { + +class LIBFM_QT_API ThumbnailLoader { + +public: + ThumbnailLoader(); + virtual ~ThumbnailLoader(); + + static ThumbnailLoader* instance() { + return theThumbnailLoader; + } + + static FmThumbnailLoader* load(FmFileInfo* fileInfo, int size, FmThumbnailLoaderCallback callback, gpointer user_data) { + // qDebug("load thumbnail: %s", fm_file_info_get_disp_name(fileInfo)); + return fm_thumbnail_loader_load(fileInfo, size, callback, user_data); + } + + static FmFileInfo* fileInfo(FmThumbnailLoader* result) { + return fm_thumbnail_loader_get_file_info(result); + } + + static void cancel(FmThumbnailLoader* result) { + fm_thumbnail_loader_cancel(result); + } + + static QImage image(FmThumbnailLoader* result); + + static int size(FmThumbnailLoader* result) { + return fm_thumbnail_loader_get_size(result); + } + + static void setLocalFilesOnly(bool value) { + localFilesOnly_ = value; + if(fm_config) + fm_config->thumbnail_local = localFilesOnly_; + } + + static bool localFilesOnly() { + return localFilesOnly_; + } + + static int maxThumbnailFileSize() { + return maxThumbnailFileSize_; + } + + static void setMaxThumbnailFileSize(int size) { + maxThumbnailFileSize_ = size; + if(fm_config) + fm_config->thumbnail_max = maxThumbnailFileSize_; + } + +private: + static GObject* readImageFromFile(const char* filename); + static GObject* readImageFromStream(GInputStream* stream, guint64 len, GCancellable* cancellable); + static gboolean writeImage(GObject* image, const char* filename); + static GObject* scaleImage(GObject* ori_pix, int new_width, int new_height); + static int getImageWidth(GObject* image); + static int getImageHeight(GObject* image); + static char* getImageText(GObject* image, const char* key); + static gboolean setImageText(GObject* image, const char* key, const char* val); + static GObject* rotateImage(GObject* image, int degree); + +private: + static ThumbnailLoader* theThumbnailLoader; + static bool localFilesOnly_; + static int maxThumbnailFileSize_; +}; + +} + +#endif // FM_THUMBNAILLOADER_H diff --git a/libfm-qt/translations/libfm-qt_ar.ts b/libfm-qt/translations/libfm-qt_ar.ts new file mode 100644 index 0000000..6ae9dcd --- /dev/null +++ b/libfm-qt/translations/libfm-qt_ar.ts @@ -0,0 +1,1019 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + + + + + Name + + + + + Location + + + + + &Add Item + + + + + &Remove Item + + + + + Use drag and drop to reorder the items + + + + + ExecFileDialog + + + Execute file + + + + + &Open + + + + + E&xecute + + + + + Execute in &Terminal + + + + + Cancel + + + + + FileOperationDialog + + + Destination: + + + + + Processing: + + + + + Preparing... + + + + + Progress + + + + + Time remaining: + + + + + FilePropsDialog + + + File Properties + + + + + General + + + + + Location: + + + + + File type: + + + + + Mime type: + + + + + File size: + + + + + On-disk size: + + + + + Last modified: + + + + + Link target: + + + + + Open With: + + + + + Last accessed: + + + + + Permissions + + + + + Ownership + + + + + + + Group: + + + + + + + Owner: + + + + + Access Control + + + + + + Other: + + + + + Make the file executable + + + + + + + Read + + + + + + + Write + + + + + + + Execute + + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + + + + + Move here + + + + + Create symlink here + + + + + Cancel + + + + + Fm::EditBookmarksDialog + + + New bookmark + + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + + + + + Cut + + + + + Copy + + + + + Paste + + + + + + &Move to Trash + + + + + Output + + + + + &Delete + + + + + Rename + + + + + Open With... + + + + + Other Applications + + + + + &Restore + + + + + Extract to... + + + + + Extract Here + + + + + Compress + + + + + Properties + + + + + Fm::FileOperation + + + Error + + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + + + + + + Confirm + + + + + Do you want to delete the selected files? + + + + + Do you want to move the selected files to trash can? + + + + + Fm::FileOperationDialog + + + Move files + + + + + Moving the following files to destination folder: + + + + + Copy Files + + + + + Copying the following files to destination folder: + + + + + Trash Files + + + + + Moving the following files to trash can: + + + + + Delete Files + + + + + Deleting the following files + + + + + Create Symlinks + + + + + Creating symlinks for the following files: + + + + + Change Attributes + + + + + Changing attributes of the following files: + + + + + Restore Trashed Files + + + + + Restoring the following files from trash can: + + + + + Error + + + + + Fm::FilePropsDialog + + + View folder content + + + + + View and modify folder content + + + + + Read + + + + + Read and write + + + + + Forbidden + + + + + Files of different types + + + + + Multiple Files + + + + + Apply changes + + + + + Do you want to recursively apply these changes to all files and sub-folders? + + + + + Fm::FolderMenu + + + Create &New + + + + + &Paste + + + + + Select &All + + + + + Invert Selection + + + + + Sorting + + + + + Show Hidden + + + + + Folder Pr&operties + + + + + Folder + + + + + Blank File + + + + + By File Name + + + + + By Modification Time + + + + + By File Size + + + + + By File Type + + + + + By File Owner + + + + + Ascending + + + + + Descending + + + + + Folder First + + + + + Case Sensitive + + + + + Fm::FolderModel + + + Name + + + + + Type + + + + + Size + + + + + Modified + + + + + Owner + + + + + Fm::FontButton + + + Bold + + + + + Italic + + + + + Fm::MountOperationPasswordDialog + + + &Connect + + + + + Fm::PlacesModel + + + Places + + + + + Desktop + + + + + Trash + + + + + Computer + + + + + Applications + + + + + Network + + + + + Devices + + + + + Bookmarks + + + + + Fm::PlacesView + + + Empty Trash + + + + + Rename + + + + + Delete + + + + + + Unmount + + + + + Mount + + + + + Eject + + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + + + + + Type: %1 +Modified: %2 + + + + + Type: %1 +Modified: %3 + + + + + &Overwrite + + + + + &Rename + + + + + Fm::SidePane + + + + Places + + + + + + Directory Tree + + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + + + + + Connect &anonymously + + + + + Connect as u&ser: + + + + + &Username: + + + + + &Password: + + + + + &Domain: + + + + + Forget password &immediately + + + + + Remember password until you &logout + + + + + Remember &forever + + + + + QObject + + + + + + Error + + + + + Rename File + + + + + Please enter a new name: + + + + + Please enter a new file name: + + + + + New text file + + + + + Please enter a new folder name: + + + + + New folder + + + + + Enter a name for the new %1: + + + + + Create File + + + + + RenameDialog + + + Confirm to replace files + + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + + + + + dest + + + + + with the following file? + + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + + + + + Apply this option to all existing files + + + + diff --git a/libfm-qt/translations/libfm-qt_cs_CZ.ts b/libfm-qt/translations/libfm-qt_cs_CZ.ts new file mode 100644 index 0000000..3e01149 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_cs_CZ.ts @@ -0,0 +1,1019 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + + + + + Name + Jméno + + + + Location + + + + + &Add Item + + + + + &Remove Item + + + + + Use drag and drop to reorder the items + + + + + ExecFileDialog + + + Execute file + Spustit soubor + + + + &Open + &Otevřít + + + + E&xecute + &Spustit + + + + Execute in &Terminal + Spustit v &Terminálu + + + + Cancel + Zrušit + + + + FileOperationDialog + + + Destination: + + + + + Processing: + + + + + Preparing... + + + + + Progress + + + + + Time remaining: + + + + + FilePropsDialog + + + File Properties + + + + + General + + + + + Location: + + + + + File type: + + + + + Mime type: + + + + + File size: + + + + + On-disk size: + + + + + Last modified: + + + + + Link target: + + + + + Open With: + + + + + Last accessed: + + + + + Permissions + + + + + Ownership + + + + + + + Group: + + + + + + + Owner: + + + + + Access Control + + + + + + Other: + + + + + Make the file executable + + + + + + + Read + + + + + + + Write + + + + + + + Execute + + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + + + + + Move here + + + + + Create symlink here + + + + + Cancel + Zrušit + + + + Fm::EditBookmarksDialog + + + New bookmark + Nová záložka + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + Otevřít + + + + &Restore + + + + + Cut + Vyjmout + + + + Copy + Kopírovat + + + + Paste + Vložit + + + + + &Move to Trash + Přesunout do &koše + + + + Output + Výstup + + + + &Delete + &Smazat + + + + Rename + Přejmenovat + + + + Open With... + Otevřít v ... + + + + Other Applications + Ostatní programy + + + + Extract to... + Rozbalit do ... + + + + Extract Here + Rozbalit sem + + + + Compress + Komprimovat + + + + Properties + Vlastnosti + + + + Fm::FileOperation + + + Error + Chyba + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + + + + + + Confirm + + + + + Do you want to delete the selected files? + + + + + Do you want to move the selected files to trash can? + + + + + Fm::FileOperationDialog + + + Move files + + + + + Moving the following files to destination folder: + + + + + Copy Files + + + + + Copying the following files to destination folder: + + + + + Trash Files + + + + + Moving the following files to trash can: + + + + + Delete Files + + + + + Deleting the following files + + + + + Create Symlinks + + + + + Creating symlinks for the following files: + + + + + Change Attributes + + + + + Changing attributes of the following files: + + + + + Restore Trashed Files + + + + + Restoring the following files from trash can: + + + + + Error + Chyba + + + + Fm::FilePropsDialog + + + View folder content + + + + + View and modify folder content + + + + + Read + + + + + Read and write + + + + + Forbidden + + + + + Files of different types + + + + + Multiple Files + + + + + Apply changes + + + + + Do you want to recursively apply these changes to all files and sub-folders? + + + + + Fm::FolderMenu + + + Create &New + + + + + &Paste + + + + + Select &All + + + + + Invert Selection + + + + + Sorting + + + + + Show Hidden + + + + + Folder Pr&operties + + + + + Folder + + + + + Blank File + + + + + By File Name + + + + + By Modification Time + + + + + By File Size + + + + + By File Type + + + + + By File Owner + + + + + Ascending + + + + + Descending + + + + + Folder First + + + + + Case Sensitive + + + + + Fm::FolderModel + + + Name + Jméno + + + + Type + Typ + + + + Size + Velikost + + + + Modified + Změněno + + + + Owner + Vlastník + + + + Fm::FontButton + + + Bold + Tučné + + + + Italic + Kurzíva + + + + Fm::MountOperationPasswordDialog + + + &Connect + + + + + Fm::PlacesModel + + + Places + Místa + + + + Desktop + + + + + Trash + + + + + Computer + + + + + Applications + + + + + Network + + + + + Devices + + + + + Bookmarks + + + + + Fm::PlacesView + + + Empty Trash + Vysypat koš + + + + Rename + Přejmenovat + + + + Delete + Smazat + + + + + Unmount + Odpojit + + + + Mount + Připojit + + + + Eject + Vysunout + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + + + + + Type: %1 +Modified: %2 + + + + + Type: %1 +Modified: %3 + + + + + &Overwrite + + + + + &Rename + + + + + Fm::SidePane + + + + Places + Místa + + + + + Directory Tree + Strom adresářů + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + Připojit + + + + Connect &anonymously + + + + + Connect as u&ser: + + + + + &Username: + + + + + &Password: + + + + + &Domain: + + + + + Forget password &immediately + + + + + Remember password until you &logout + + + + + Remember &forever + + + + + QObject + + + + + + Error + Chyba + + + + Rename File + Přejmenovat Soubor + + + + Please enter a new name: + Prosím zadej nové jméno: + + + + Please enter a new file name: + Prosím zadej nové jméno souboru: + + + + New text file + Nový textový soubor + + + + Please enter a new folder name: + Prosím zadej nové jméno složky: + + + + New folder + Nová složka + + + + Enter a name for the new %1: + Zadej jméno pro nový %1: + + + + Create File + Vytvořit soubor + + + + RenameDialog + + + Confirm to replace files + + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + + + + + dest + + + + + with the following file? + + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + + + + + Apply this option to all existing files + + + + diff --git a/libfm-qt/translations/libfm-qt_de.ts b/libfm-qt/translations/libfm-qt_de.ts new file mode 100644 index 0000000..5b7bef2 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_de.ts @@ -0,0 +1,1031 @@ + + + + + AppChooserDialog + + + Choose an Application + Wählen Sie eine Anwendung + + + + Installed Applications + Installierte Anwendungen + + + + Custom Command + Benutzerdefinierter Befehl + + + + Command line to execute: + Auszuführender Befehl: + + + + Application name: + Anwendungsname: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>Diese speziellen Kürzel können im Befehl verwendet werden</b> +<ul> +<li><b>%f</b>: Repräsentiert eine einzelne Datei</li> +<li><b>%F</b>: Repräsentiert mehrere Dateien</li> +<li><b>%u</b>: Repräsentiert eine einzelne URI einer Datei</li> +<li><b>%U</b>: Repräsentiert mehrere URIs</li> +</ul> + + + + Keep terminal window open after command execution + Terminalfenster nach der Ausführung des Befehls offen lassen + + + + Execute in terminal emulator + In einem Terminalemulator ausführen + + + + Set selected application as default action of this file type + Ausgewählte Anwendung als Standardaktion für diesen Dateityp festlegen + + + + EditBookmarksDialog + + + Edit Bookmarks + Favoriten bearbeiten + + + + Name + Name + + + + Location + Ort + + + + &Add Item + Element &hinzufügen + + + + &Remove Item + Element &entfernen + + + + Use drag and drop to reorder the items + Klicken und ziehen Sie, um Elemente zu sortieren + + + + ExecFileDialog + + + Execute file + Datei ausführen + + + + &Open + Ö&ffnen + + + + E&xecute + &Ausführen + + + + Execute in &Terminal + In einem &Terminal ausführen + + + + Cancel + Abbrechen + + + + FileOperationDialog + + + Destination: + Ziel: + + + + Processing: + Verarbeitet: + + + + Preparing... + Vorbereiten... + + + + Progress + Fortschritt + + + + Time remaining: + Verbleibende Zeit: + + + + FilePropsDialog + + + File Properties + Dateieigenschaften + + + + General + Allgemeines + + + + Location: + Ort: + + + + File type: + Dateityp: + + + + Mime type: + MIME-Typ: + + + + File size: + Dateigröße: + + + + On-disk size: + Größe auf dem Datenträger: + + + + Last modified: + Letztes Änderungsdatum: + + + + Link target: + Verknüpfungsziel: + + + + Open With: + Öffnen mit: + + + + Last accessed: + Letzter Zugriff: + + + + Permissions + Berechtigungen + + + + Ownership + Besitz + + + + + + Group: + Gruppe: + + + + + + Owner: + Besitzer: + + + + Access Control + Zugriffskontrolle + + + + + Other: + Andere: + + + + Make the file executable + Datei ausführbar machen + + + + + + Read + Lesen + + + + + + Write + Schreiben + + + + + + Execute + Ausführen + + + + Sticky + "Sticky bit" + + + + SetUID + SetUID + + + + SetGID + SetGID + + + + Advanced Mode + Erweiterte Einstellungen + + + + Fm::AppChooserComboBox + + + Customize + Anpassen + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + Wählen Sie eine Anwendung für Dateien vom Typ "%1" + + + + Fm::DirTreeModel + + + Loading... + Lädt... + + + + <No sub folders> + <Keine Unterverzeichnisse> + + + + Fm::DndActionMenu + + + Copy here + Hierhin kopieren + + + + Move here + Hierhin verschieben + + + + Create symlink here + Hier eine symbolische Verknüpfung erstellen + + + + Cancel + Abbrechen + + + + Fm::EditBookmarksDialog + + + New bookmark + Neuer Favorit + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + Die Textdatei '%1' scheint ein ausführbares Skript zu sein. +Was möchten Sie damit tun? + + + + This file '%1' is executable. Do you want to execute it? + Die Datei '%1' ist ausführbar. Möchten Sie sie ausführen? + + + + Fm::FileMenu + + + Open + Öffnen + + + + &Restore + Wiede&rherstellen + + + + Cut + Ausschneiden + + + + Copy + Kopieren + + + + Paste + Einfügen + + + + + &Move to Trash + In den &Papierkorb verschieben + + + + Output + Ausgabe + + + + &Delete + &Löschen + + + + Rename + Umbenennen + + + + Open With... + Öffnen mit... + + + + Other Applications + Andere Anwendungen + + + + Extract to... + Entpacken nach... + + + + Extract Here + Hier entpacken + + + + Compress + Komprimieren + + + + Properties + Eigenschaften + + + + Fm::FileOperation + + + Error + Fehler + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Einige Dateien können nicht in den Papierkorb verschoben werden, da die zugrundeliegenden Dateisysteme den Vorgang nicht unterstützen. +Sollen die Dateien stattdessen gelöscht werden? + + + + + Confirm + Bestätigung + + + + Do you want to delete the selected files? + Möchten Sie die ausgewählten Dateien löschen? + + + + Do you want to move the selected files to trash can? + Möchten Sie die ausgewählten Dateien in den Papierkorb verschieben? + + + + Fm::FileOperationDialog + + + Move files + Dateien verschieben + + + + Moving the following files to destination folder: + Verschiebe die folgenden Dateien in den Zielordner: + + + + Copy Files + Dateien kopieren + + + + Copying the following files to destination folder: + Kopiere die folgenden Dateien in den Zielordner: + + + + Trash Files + Dateien für den Papierkorb + + + + Moving the following files to trash can: + Verschiebe die folgenden Dateien in den Papierkorb: + + + + Delete Files + Dateien löschen + + + + Deleting the following files + Lösche die folgenden Dateien + + + + Create Symlinks + Symbolische Verknüpfung erstellen + + + + Creating symlinks for the following files: + Symbolische Verknüpfungen für die folgenden Dateien erstellen: + + + + Change Attributes + Eigenschaften ändern + + + + Changing attributes of the following files: + Eigenschaften der folgenden Dateien ändern: + + + + Restore Trashed Files + Dateien aus dem Papierkorb wiederherstellen + + + + Restoring the following files from trash can: + Folgende Dateien aus dem Papierkorb wiederherstellen: + + + + Error + Fehler + + + + Fm::FilePropsDialog + + + View folder content + Ordnerinhalt ansehen + + + + View and modify folder content + Ordnerinhalt ansehen und modifizieren + + + + Read + Lesen + + + + Read and write + Lesen und schreiben + + + + Forbidden + Unzulässig + + + + Files of different types + Dateien unterschiedlicher Typen + + + + Multiple Files + Mehrere Dateien + + + + Apply changes + Änderungen anwenden + + + + Do you want to recursively apply these changes to all files and sub-folders? + Möchten Sie die Änderungen auf alle Dateien und Unterverzeichnisse anwenden? + + + + Fm::FolderMenu + + + Create &New + &Neu erstellen + + + + &Paste + &Einfügen + + + + Select &All + &Alle auswählen + + + + Invert Selection + Auswahl umkehren + + + + Sorting + Sortierung + + + + Show Hidden + Versteckte anzeigen + + + + Folder Pr&operties + Ordner&eigenschaften + + + + Folder + Ordner + + + + Blank File + Leere Datei + + + + By File Name + Nach Dateiname + + + + By Modification Time + Nach Änderungsdatum + + + + By File Size + Nach Dateigröße + + + + By File Type + Nach Typ + + + + By File Owner + Nach Besitzer + + + + Ascending + Aufsteigend + + + + Descending + Absteigend + + + + Folder First + Ordner zuerst + + + + Case Sensitive + Groß-/ Kleinschreibung beachten + + + + Fm::FolderModel + + + Name + Name + + + + Type + Typ + + + + Size + Größe + + + + Modified + Geändert + + + + Owner + Besitzer + + + + Fm::FontButton + + + Bold + Fett + + + + Italic + Kursiv + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Verbinden + + + + Fm::PlacesModel + + + Places + Orte + + + + Desktop + Arbeitsplatz + + + + Trash + Papierkorb + + + + Computer + Rechner + + + + Applications + Anwendungen + + + + Network + Netzwerk + + + + Devices + Geräte + + + + Bookmarks + Favoriten + + + + Fm::PlacesView + + + Empty Trash + Papierkorb leeren + + + + Rename + Umbenennen + + + + Delete + Löschen + + + + + Unmount + Aushängen + + + + Mount + Einhängen + + + + Eject + Auswerfen + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Typ: %1 +Größe: %2 +Geändert: %3 + + + + Type: %1 +Modified: %2 + Typ: %1 +Geändert: %2 + + + + Type: %1 +Modified: %3 + Typ: %1 +Geändert: %3 + + + + &Overwrite + Über&schreiben + + + + &Rename + &Umbenennen + + + + Fm::SidePane + + + + Places + Orte + + + + + Directory Tree + Verzeichnisbaum + + + + Shows list of common places, devices, and bookmarks in sidebar + Zeigt eine Liste diverser Orte, Geräte und Favoriten in der Seitenleiste + + + + Shows tree of directories in sidebar + Zeigt einen Verzeichnisbaum in der Seitenleiste + + + + MountOperationPasswordDialog + + + Mount + Einhängen + + + + Connect &anonymously + &Anonym verbinden + + + + Connect as u&ser: + Verbinden als &Benutzer: + + + + &Username: + Benutzer&name: + + + + &Password: + &Passwort: + + + + &Domain: + &Domäne: + + + + Forget password &immediately + Passwort &sofort vergessen + + + + Remember password until you &logout + Passwort &erst beim Abmelden vergessen + + + + Remember &forever + Passwort &für immer merken + + + + QObject + + + + + + Error + Fehler + + + + Rename File + Datei umbenennen + + + + Please enter a new name: + Bitte geben Sie einen neuen Namen ein: + + + + Please enter a new file name: + Bitte geben Sie einen neuen Dateinamen ein: + + + + New text file + Neue Textdatei + + + + Please enter a new folder name: + Bitte geben Sie einen neuen Ordnernamen ein: + + + + New folder + Neuer Ordner + + + + Enter a name for the new %1: + Geben Sie einen Namen für %1 ein: + + + + Create File + Datei erstellen + + + + RenameDialog + + + Confirm to replace files + Überschreiben von Dateien bestätigen + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Es gibt bereits eine gleichnamige Datei an diesem Ort.</span></p><p>Möchten Sie die Datei ersetzen?</p></body></html> + + + + dest + Ziel + + + + with the following file? + Mit der folgenden Datei? + + + + src file info + Info über die Quelldatei + + + + dest file info + Info über die Zieldatei + + + + src + Quelle + + + + &File name: + &Dateiname: + + + + Apply this option to all existing files + Diese Aktion auf alle existierenden Dateien anwenden + + + diff --git a/libfm-qt/translations/libfm-qt_es.ts b/libfm-qt/translations/libfm-qt_es.ts new file mode 100644 index 0000000..65f3729 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_es.ts @@ -0,0 +1,1031 @@ + + + + + AppChooserDialog + + + Choose an Application + Seleccione una Aplicación + + + + Installed Applications + Aplicaciones Instaladas + + + + Custom Command + Comando Personalizado + + + + Command line to execute: + Línea de comandos a ejecutar: + + + + Application name: + Nombre de la aplicación: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>Estos códigos pueden ser usados en la línea de comando:</b> +<ul> +<li><b>%f</b>: Representa un nombre de archivo</li> +<li><b>%F</b>: Representa múltiples nombres de archivos</li> +<li><b>%u</b>: Representa una URI para el archivo</li> +<li><b>%U</b>: Representa múltiples URIs</li> +</ul> + + + + Keep terminal window open after command execution + Mantener la terminal abierta luego de la ejecución del comando + + + + Execute in terminal emulator + Ejecutar en un emulador de terminal + + + + Set selected application as default action of this file type + Configurar la aplicación seleccionada como por defecto para este tipo de archivo + + + + EditBookmarksDialog + + + Edit Bookmarks + Editar marcadores + + + + Name + Nombre + + + + Location + Localización + + + + &Add Item + &Agregar elemento + + + + &Remove Item + &Eliminar elemento + + + + Use drag and drop to reorder the items + Arrastre y suelte para reordenar los elementos + + + + ExecFileDialog + + + Execute file + Ejecutar archivo + + + + &Open + &Abrir + + + + E&xecute + &Ejecutar + + + + Execute in &Terminal + Ejecutar en &Terminal + + + + Cancel + Cancelar + + + + FileOperationDialog + + + Destination: + Destino: + + + + Processing: + Procesando: + + + + Preparing... + Preparando... + + + + Progress + Progreso + + + + Time remaining: + Tiempo restante: + + + + FilePropsDialog + + + File Properties + Propiedades de Archivo + + + + General + General + + + + Location: + Localización: + + + + File type: + Tipo de archivo: + + + + Mime type: + Tipo Mime: + + + + File size: + Tamaño del archivo: + + + + On-disk size: + Tamaño en disco: + + + + Last modified: + Última modificación: + + + + Link target: + Destino del enlace: + + + + Open With: + Abrir con: + + + + Last accessed: + Último acceso: + + + + Permissions + Permisos + + + + Ownership + Propiedad + + + + + + Group: + Grupo: + + + + + + Owner: + Dueño: + + + + Access Control + Control de acceso + + + + + Other: + Otro: + + + + Make the file executable + Marcar como ejecutable + + + + + + Read + Lectura + + + + + + Write + Escritura + + + + + + Execute + Ejecución + + + + Sticky + Sticky + + + + SetUID + SetUID + + + + SetGID + SetGID + + + + Advanced Mode + Modo avanzado + + + + Fm::AppChooserComboBox + + + Customize + Personalizar + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + Seleccione una aplicación para abrir archivos "%1" + + + + Fm::DirTreeModel + + + Loading... + Cargando... + + + + <No sub folders> + <No hay subdirectorios> + + + + Fm::DndActionMenu + + + Copy here + Copiar aquí + + + + Move here + Mover aquí + + + + Create symlink here + Crear enlace simbólico aquí + + + + Cancel + Cancelar + + + + Fm::EditBookmarksDialog + + + New bookmark + Nuevo marcador + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + El archivo de texto '%1' parece ser un script ejecutable. +¿Qué desea hacer con él? + + + + This file '%1' is executable. Do you want to execute it? + El archivo '%1' es ejecutable. ¿Quiere ejecutarlo? + + + + Fm::FileMenu + + + Open + Abrir + + + + Open With... + Abrir con... + + + + Other Applications + Otras Aplicaciones + + + + &Restore + &Restaurar + + + + Cut + Cortar + + + + Copy + Copiar + + + + Paste + Pegar + + + + + &Move to Trash + &Mover a la Papelera + + + + Rename + Renombrar + + + + Extract to... + Extraer en... + + + + Extract Here + Extraer aquí + + + + Compress + Comprimir + + + + Properties + Propiedades + + + + Output + Salida + + + + &Delete + &Borrar + + + + Fm::FileOperation + + + Error + Error + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Algunos archivos no pueden moverse a la papelera porque el subsistema de archivos no permite esta operación. +¿Quiere eliminarlos en su lugar? + + + + + Confirm + Confirmación + + + + Do you want to delete the selected files? + ¿Quiere borrar los archivos seleccionados? + + + + Do you want to move the selected files to trash can? + ¿Quiere mover los archivos seleccionados a la papelera? + + + + Fm::FileOperationDialog + + + Move files + Mover archivos + + + + Moving the following files to destination folder: + Moviendo los siguientes archivos al directorio destino: + + + + Copy Files + Copiar archivos + + + + Copying the following files to destination folder: + Copiando los siguientes archivos al directorio destino: + + + + Trash Files + Enviar archivos a la papelera + + + + Moving the following files to trash can: + Moviendo los siguientes archivos a la papelera: + + + + Delete Files + Borrar archivos + + + + Deleting the following files + Borrando los siguientes archivos + + + + Create Symlinks + Crear enlaces simbólicos + + + + Creating symlinks for the following files: + Creando enlaces simbólicos para los siguientes archivos: + + + + Change Attributes + Cambiar atributos + + + + Changing attributes of the following files: + Cambiando atributos para los siguientes archivos: + + + + Restore Trashed Files + Restaurar archivos borrados + + + + Restoring the following files from trash can: + Restaurando los siguientes archivos desde la papelera: + + + + Error + Error + + + + Fm::FilePropsDialog + + + View folder content + Ver contenido del directorio + + + + View and modify folder content + Ver y modificar el contenido del directorio + + + + Read + Lectura + + + + Read and write + Lectura y escritura + + + + Forbidden + Prohibido + + + + Files of different types + Archivos de diferentes tipos + + + + Multiple Files + Múltiples archivos + + + + Apply changes + Aplicar cambios + + + + Do you want to recursively apply these changes to all files and sub-folders? + ¿Quiere aplicar los cambios a todos los archivos y subdirectorios? + + + + Fm::FolderMenu + + + Create &New + Crear &Nuevo + + + + &Paste + &Pegar + + + + Select &All + Seleccion&ar todo + + + + Invert Selection + Invertir Selección + + + + Sorting + Ordenar + + + + Show Hidden + Mostrar Ocultos + + + + Folder Pr&operties + Pr&opiedades del directorio + + + + Folder + Directorio + + + + Blank File + Archivo Vacío + + + + By File Name + Por nombre de archivo + + + + By Modification Time + Por fecha de modificación + + + + By File Size + Por tamaño de archivo + + + + By File Type + Por tipo de archivo + + + + By File Owner + Por dueño del archivo + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + Folder First + Primero Directorios + + + + Case Sensitive + Coincidir mayúsculas + + + + Fm::FolderModel + + + Name + Nombre + + + + Type + Tipo + + + + Size + Tamaño + + + + Modified + Modificado + + + + Owner + Dueño + + + + Fm::FontButton + + + Bold + Negrita + + + + Italic + Itálica + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Conectar + + + + Fm::PlacesModel + + + Places + Lugares + + + + Desktop + Escritorio + + + + Computer + Sistema + + + + Applications + Aplicaciones + + + + Network + Red + + + + Devices + Dispositivos + + + + Bookmarks + Marcadores + + + + Trash + Papelera + + + + Fm::PlacesView + + + Empty Trash + Vaciar Papelera + + + + Rename + Renombrar + + + + Delete + Borrar + + + + + Unmount + Desmontar + + + + Mount + Montar + + + + Eject + Expulsar + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Tipo: %1 +Tamaño: %2 +Modificado: %3 + + + + Type: %1 +Modified: %2 + Tipo: %1 +Modificado: %2 + + + + Type: %1 +Modified: %3 + Tipo: %1 +Modificado: %3 + + + + &Overwrite + &Sobreescribir + + + + &Rename + &Renombrar + + + + Fm::SidePane + + + + Places + Lugares + + + + + Directory Tree + Árbol de Directorios + + + + Shows list of common places, devices, and bookmarks in sidebar + Muestra lista de lugares comunes, dispositivos y marcadores en la barra lateral + + + + Shows tree of directories in sidebar + Muestra árbol de directorios en barra lateral + + + + MountOperationPasswordDialog + + + Mount + Montar + + + + Connect &anonymously + Conectar &anonimamente + + + + Connect as u&ser: + Conectar como u&suario: + + + + &Username: + &Usuario: + + + + &Password: + &Contraseña: + + + + &Domain: + &Dominio: + + + + Forget password &immediately + Descartar contraseña &inmediatamente + + + + Remember password until you &logout + &Recordar contraseña hasta cerrar sesión + + + + Remember &forever + Recordar &para siempre + + + + QObject + + + + + + Error + Error + + + + Rename File + Renombrar Archivo + + + + Please enter a new name: + Introduzca un nuevo nombre: + + + + Please enter a new file name: + Introduzca un nuevo nombre de archivo: + + + + New text file + Nuevo archivo de texto + + + + Please enter a new folder name: + Ingrese un nuevo nombre de directorio: + + + + New folder + Nuevo directorio + + + + Enter a name for the new %1: + Ingresar un nombre para el nuevo %1: + + + + Create File + Crear Archivo + + + + RenameDialog + + + Confirm to replace files + Confirmación de sustitución + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Ya existe un archivo con el mismo nombre en este lugar.</span></p><p>¿Quiere reemplazar el archivo existente?</p></body></html> + + + + dest + destino + + + + with the following file? + con el siguiente archivo? + + + + src file info + información del archivo de origen + + + + dest file info + información del archivo de destino + + + + src + origen + + + + &File name: + Nombre de &archivo: + + + + Apply this option to all existing files + Aplicar esta opción a todos los archivos + + + diff --git a/libfm-qt/translations/libfm-qt_fr.ts b/libfm-qt/translations/libfm-qt_fr.ts new file mode 100644 index 0000000..93c926b --- /dev/null +++ b/libfm-qt/translations/libfm-qt_fr.ts @@ -0,0 +1,1032 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + Modifier les signets + + + + Name + Nom + + + + Location + Emplacement + + + + &Add Item + &Ajouter un élément + + + + &Remove Item + &Supprimer un élément + + + + Use drag and drop to reorder the items + Utiliser le glisser-déposer pour trier à nouveau les éléments + + + + ExecFileDialog + + + Execute file + + + + + &Open + + + + + E&xecute + + + + + Execute in &Terminal + + + + + Cancel + Annuler + + + + FileOperationDialog + + + Destination: + Destination : + + + + Processing: + Traitement : + + + + Preparing... + Préparation... + + + + Progress + Progression + + + + Time remaining: + Temps restant : + + + + FilePropsDialog + + + File Properties + Propriétés du fichier + + + + General + Général + + + + Location: + Emplacement : + + + + File type: + Type de fichier : + + + + Mime type: + Type Mime : + + + + File size: + Taille du fichier : + + + + On-disk size: + Taille sur le disque : + + + + Last modified: + Date de dernière modification : + + + + Link target: + Cible du lien : + + + + Open With: + Ouvrir avec : + + + + Last accessed: + Date de dernier accès : + + + + Permissions + Droits d'accès + + + + Ownership + Propriété + + + + + + Group: + Groupe : + + + + + + Owner: + Propriétaire : + + + + Access Control + Contrôle d'accès + + + + + Other: + Autre : + + + + Make the file executable + Rendre le fichier exécutable + + + + + + Read + Lecture + + + + + + Write + Écriture + + + + + + Execute + Exécution + + + + Sticky + Permanent + + + + SetUID + SetUID + + + + SetGID + SetGID + + + + Advanced Mode + Mode avancé + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + Copier ici + + + + Move here + Déplacer ici + + + + Create symlink here + Créer un lien symbolique ici + + + + Cancel + Annuler + + + + Fm::EditBookmarksDialog + + + New bookmark + Nouveau signet + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + Ouvrir + + + OpenWith + OpenWith + + + + Cut + Couper + + + + Copy + Copier + + + + Paste + Coller + + + + + &Move to Trash + &Mettre à la corbeille + + + + Output + + + + + &Delete + &Supprimer + + + + Rename + Renommer + + + + Open With... + + + + + Other Applications + + + + + &Restore + + + + + Extract to... + Extraire vers... + + + + Extract Here + Extraire ici + + + + Compress + Compresser + + + + Properties + Propriétés + + + + Fm::FileOperation + + + Error + Erreur + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Certains fichiers ne peuvent pas être mis à la corbeille car les systèmes de fichiers sous-jacents ne prennent pas en charge cette opération. +Voulez-vous plutôt les supprimer ? + + + + + Confirm + Confirmer + + + + Do you want to delete the selected files? + Voulez-vous supprimer les fichiers sélectionnés ? + + + + Do you want to move the selected files to trash can? + Voulez-vous mettre les fichiers sélectionnés à la corbeille ? + + + + Fm::FileOperationDialog + + + Move files + Déplacer les fichiers + + + + Moving the following files to destination folder: + Déplacement des fichiers suivants vers le dossier de destination en cours : + + + + Copy Files + Copier les fichiers + + + + Copying the following files to destination folder: + Copie des fichiers suivants vers le dossier de destination en cours : + + + + Trash Files + Mettre les fichiers de la corbeille + + + + Moving the following files to trash can: + Déplacement des fichiers suivants vers la corbeille en cours : + + + + Delete Files + Supprimer les fichiers + + + + Deleting the following files + Suppression des fichiers suivants + + + + Create Symlinks + Créer des liens symboliques + + + + Creating symlinks for the following files: + Création de liens symboliques avec les fichiers suivants en cours : + + + + Change Attributes + Modifier les attributs + + + + Changing attributes of the following files: + Modification des attributs des fichiers suivants en cours : + + + + Restore Trashed Files + Restaurer les fichiers de la corbeille + + + + Restoring the following files from trash can: + Restauration des fichiers suivants depuis la corbeille en cours : + + + + Error + Erreur + + + + Fm::FilePropsDialog + + + View folder content + Voir le contenu du dossier + + + + View and modify folder content + Voir et modifier le contenu du dossier + + + + Read + Lecture + + + + Read and write + Lecture et écriture + + + + Forbidden + Interdit + + + + Files of different types + Fichiers de différents types + + + + Multiple Files + Fichiers multiples + + + + Apply changes + Appliquer les modifications + + + + Do you want to recursively apply these changes to all files and sub-folders? + Voulez-vous appliquer ces changements récursivement à tous les fichiers et sous-dossiers ? + + + + Fm::FolderMenu + + + Create &New + Créer un &nouveau + + + + &Paste + &Coller + + + + Select &All + Sélectionner &tous + + + + Invert Selection + Inverser la sélection + + + + Sorting + Tri en cours + + + + Show Hidden + Afficher les éléments cachés + + + + Folder Pr&operties + Pr&opriétés du dossier + + + + Folder + Dossier + + + File + Fichier + + + + Blank File + + + + + By File Name + Par nom de fichier + + + + By Modification Time + Par date de modification + + + + By File Size + Par taille de fichier + + + + By File Type + Par type de fichier + + + + By File Owner + Par propriétaire de fichier + + + + Ascending + Ascendant + + + + Descending + Descendant + + + + Folder First + Dossier en premier + + + + Case Sensitive + Sensible à la casse + + + + Fm::FolderModel + + + Name + Nom + + + + Type + Type + + + + Size + Taille + + + + Modified + Modifié + + + + Owner + Propriétaire + + + + Fm::FontButton + + + Bold + Gras + + + + Italic + Italique + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Connecter + + + + Fm::PlacesModel + + + Places + Emplacements + + + + Desktop + Bureau + + + + Trash + Corbeille + + + + Computer + Ordinateur + + + + Applications + Applications + + + + Network + Réseau + + + + Devices + Appareils + + + + Bookmarks + Signets + + + + Fm::PlacesView + + + Empty Trash + + + + + Rename + Renommer + + + + Delete + Supprimer + + + + + Unmount + Démonter + + + + Mount + Monter + + + + Eject + Éjecter + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Type : %1 +Taille : %2 +Modification : %3 + + + + Type: %1 +Modified: %2 + Type : %1 +Modification : %2 + + + + Type: %1 +Modified: %3 + Type : %1 +Modification : %3 + + + + &Overwrite + &Remplacer + + + + &Rename + &Renommer + + + + Fm::SidePane + + + + Places + Emplacements + + + + + Directory Tree + + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + Monter + + + + Connect &anonymously + Connecter &anonymement + + + + Connect as u&ser: + Connecter comme utilis&sateur : + + + + &Username: + Nom d'&utilisateur : + + + + &Password: + Mot de &passe : + + + + &Domain: + &Domaine : + + + + Forget password &immediately + Oublier le mot de passe &immédiatement + + + + Remember password until you &logout + Se souvenir du mot de passe jusqu'à &la déconnexion + + + + Remember &forever + &Toujours s'en souvenir + + + + QObject + + + + + + Error + Erreur + + + + Rename File + Renommer le fichier + + + + Please enter a new name: + Veuillez entrer un nouveau nom : + + + + Please enter a new file name: + Veuillez entrer un nouveau nom de fichier : + + + + New text file + Nouveau fichier texte + + + + Please enter a new folder name: + Veuillez entrer un nouveau nom de répertoire : + + + + New folder + Nouveau répertoire + + + + Enter a name for the new %1: + + + + + Create File + Créer un fichier + + + + RenameDialog + + + Confirm to replace files + Confirmer le remplacement des fichiers + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Il existe déjà un fichier avec le même nom à cet emplacement.</span></p><p>Voulez-vous replacer le fichier existant ?</p></body></html> + + + + dest + dest. + + + + with the following file? + avec le fichier suivant ? + + + + src file info + infos fichier src + + + + dest file info + infos fichier dest. + + + + src + src + + + + &File name: + Nom de &fichier : + + + + Apply this option to all existing files + Appliquer cette option à tous les fichiers existants + + + diff --git a/libfm-qt/translations/libfm-qt_gl.ts b/libfm-qt/translations/libfm-qt_gl.ts new file mode 100644 index 0000000..588d8eb --- /dev/null +++ b/libfm-qt/translations/libfm-qt_gl.ts @@ -0,0 +1,1032 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + Editar marcadores + + + + Name + Nome + + + + Location + Localización + + + + &Add Item + &Engadir un elemento + + + + &Remove Item + &Retirar o elemento + + + + Use drag and drop to reorder the items + Usar arrastrar e soltar para ordenar elementos + + + + ExecFileDialog + + + Execute file + + + + + &Open + + + + + E&xecute + + + + + Execute in &Terminal + + + + + Cancel + Cancelar + + + + FileOperationDialog + + + Destination: + Destino: + + + + Processing: + Procesando: + + + + Preparing... + Preparando... + + + + Progress + Progreso + + + + Time remaining: + Tempo restante: + + + + FilePropsDialog + + + File Properties + Propiedades do ficheiro + + + + General + Xeral + + + + Location: + Localización + + + + File type: + Tipo de ficheiro: + + + + Mime type: + Tipo MIME: + + + + File size: + Tamaño do ficheiro: + + + + On-disk size: + Tamaño no disco: + + + + Last modified: + Última modificación: + + + + Link target: + Destino da ligazón: + + + + Open With: + Abrir con: + + + + Last accessed: + Último acceso: + + + + Permissions + Permisos + + + + Ownership + Dono + + + + + + Group: + Grupo: + + + + + + Owner: + Propietario: + + + + Access Control + Control de acceso + + + + + Other: + Outros: + + + + Make the file executable + Facer que o ficheiro sexa executábel + + + + + + Read + Lectura + + + + + + Write + Escritura + + + + + + Execute + Execución + + + + Sticky + Persistente + + + + SetUID + Estabelecer o UID + + + + SetGID + Estabelecer o GID + + + + Advanced Mode + Modo avanzado + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + Copiar para aquí + + + + Move here + Mover para aquí + + + + Create symlink here + Crear aquí unha ligazón simbólica + + + + Cancel + Cancelar + + + + Fm::EditBookmarksDialog + + + New bookmark + Novo marcador + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + Abrir + + + OpenWith + Abrir con + + + + Cut + Cortar + + + + Copy + Copiar + + + + Paste + Pegar + + + + + &Move to Trash + Deitar no lixo + + + + Output + + + + + &Delete + &Eliminar + + + + Rename + Renomear + + + + Open With... + + + + + Other Applications + + + + + &Restore + + + + + Extract to... + Extraer en… + + + + Extract Here + Extraer aquí + + + + Compress + Comprimir + + + + Properties + Propiedades + + + + Fm::FileOperation + + + Error + Erro + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Algúns ficheiros non poden enviarse ao cesto do lixo porque o subsistema de ficheiros non permite esta operación. +Desexa eliminalos no seu canto? + + + + + Confirm + Confirmar + + + + Do you want to delete the selected files? + Quere eliminar os ficheiros seleccionados? + + + + Do you want to move the selected files to trash can? + Quere mover os ficheiros seleccionados ao cesto do lixo? + + + + Fm::FileOperationDialog + + + Move files + Mover os ficheiros + + + + Moving the following files to destination folder: + Movendo os seguintes ficheiros ao cartafol de destino: + + + + Copy Files + Copiar os ficheiros + + + + Copying the following files to destination folder: + Copiando os seguintes ficheiros ao cartafol de destino: + + + + Trash Files + Deitar no lixo os ficheiros + + + + Moving the following files to trash can: + Movendo os seguintes ficheiros ao lixo: + + + + Delete Files + Eliminar os ficheiros + + + + Deleting the following files + Eliminando os seguintes ficheiros + + + + Create Symlinks + Crear ligazóns simbólicas + + + + Creating symlinks for the following files: + Creando ligazóns simbólicas para os seguintes ficheiros: + + + + Change Attributes + Cambiar os atributos + + + + Changing attributes of the following files: + Cambiando os atributos dos seguintes ficheiros: + + + + Restore Trashed Files + Restaurar os ficheiro do lixo + + + + Restoring the following files from trash can: + Restaurando os seguintes ficheiros do lixo: + + + + Error + Erro + + + + Fm::FilePropsDialog + + + View folder content + Ver o contido do cartafol + + + + View and modify folder content + Ver e modificar o contido do cartafol + + + + Read + Lectura + + + + Read and write + Lectura e escritura + + + + Forbidden + Prohibido + + + + Files of different types + Ficheiros de tipos diferentes + + + + Multiple Files + Múltiplos ficheiros + + + + Apply changes + Aplicar os cambios + + + + Do you want to recursively apply these changes to all files and sub-folders? + Quere aplicar recursivamente estes cambios a todos os ficheiros e subcartafoles? + + + + Fm::FolderMenu + + + Create &New + Crear &novo + + + + &Paste + &Pegar + + + + Select &All + Seleccionar &todo + + + + Invert Selection + Inverter a selección + + + + Sorting + Ordenación + + + + Show Hidden + Amosar agochados + + + + Folder Pr&operties + Pr&opiedades do cartafol + + + + Folder + Cartafol + + + File + Ficheiro + + + + Blank File + + + + + By File Name + Polo nome do ficheiro + + + + By Modification Time + Pola data de modificación + + + + By File Size + Polo tamaño do ficheiro + + + + By File Type + Polo tipo do ficheiro + + + + By File Owner + Polo propietario do ficheiro + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + Folder First + Primeiro os cartafoles + + + + Case Sensitive + Distinguindo maiúsculas de minúsculas + + + + Fm::FolderModel + + + Name + Nome + + + + Type + Tipo + + + + Size + Tamaño + + + + Modified + Modificado + + + + Owner + Propietario + + + + Fm::FontButton + + + Bold + Negra + + + + Italic + Itálica + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Conectar + + + + Fm::PlacesModel + + + Places + Lugares + + + + Desktop + Escritorio + + + + Trash + Lixo + + + + Computer + Computador + + + + Applications + Aplicacións + + + + Network + Rede + + + + Devices + Dispositivos + + + + Bookmarks + Marcadores + + + + Fm::PlacesView + + + Empty Trash + + + + + Rename + Renomear + + + + Delete + Eliminar + + + + + Unmount + Desmontar + + + + Mount + Montar + + + + Eject + Expulsar + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Tipo: %1 +Tamaño: %2 +Modificado: %3 + + + + Type: %1 +Modified: %2 + Tipo: %1 +Modificado: %2 + + + + Type: %1 +Modified: %3 + Tipo: %1 +Modificado: %3 + + + + &Overwrite + &Sobrescribir + + + + &Rename + &Renomear + + + + Fm::SidePane + + + + Places + Lugares + + + + + Directory Tree + + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + Montar + + + + Connect &anonymously + Conectar &anonimamente + + + + Connect as u&ser: + Conectar como u&suario + + + + &Username: + Nome de &usuario: + + + + &Password: + &Contrasinal: + + + + &Domain: + &Dominio: + + + + Forget password &immediately + Esquecer o contrasinal &inmediatamente + + + + Remember password until you &logout + Lembrar o contrasinal ata &saír da sesión + + + + Remember &forever + &Lemprar para sempre + + + + QObject + + + + + + Error + Erro + + + + Rename File + Renomear o ficheiro + + + + Please enter a new name: + Introduza un nome novo: + + + + Please enter a new file name: + Introduza un novo nome de ficheiro: + + + + New text file + Novo ficheiro de texto + + + + Please enter a new folder name: + Introduza un nome novo para o cartafol: + + + + New folder + Novo cartafol + + + + Enter a name for the new %1: + + + + + Create File + Crear un ficheiro + + + + RenameDialog + + + Confirm to replace files + Confirmar a substitución de ficheiros + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Xa existe un ficheiro con este mesmo nome neste lugar.</span></p><p>Quere substituír o ficheiro existente?</p></body></html> + + + + dest + dest + + + + with the following file? + co seguinte ficheiro? + + + + src file info + Ficheiro de información «src» + + + + dest file info + Ficheiro de información «dest» + + + + src + src + + + + &File name: + Nome do &ficheiro: + + + + Apply this option to all existing files + Aplicar esta opción a todos os ficheiros existentes + + + diff --git a/libfm-qt/translations/libfm-qt_it.ts b/libfm-qt/translations/libfm-qt_it.ts new file mode 100644 index 0000000..328315b --- /dev/null +++ b/libfm-qt/translations/libfm-qt_it.ts @@ -0,0 +1,1032 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + Modifica segnalibri + + + + Name + Nome + + + + Location + Posizione + + + + &Add Item + &Aggiungi elemento + + + + &Remove Item + &Rimuovi elemento + + + + Use drag and drop to reorder the items + Trascina per riordinare gli elementi + + + + ExecFileDialog + + + Execute file + + + + + &Open + + + + + E&xecute + + + + + Execute in &Terminal + + + + + Cancel + Annulla + + + + FileOperationDialog + + + Destination: + Destinazione: + + + + Processing: + Elaborazione: + + + + Preparing... + Preparazione... + + + + Progress + Avanzamento + + + + Time remaining: + Tempo rimanente: + + + + FilePropsDialog + + + File Properties + Proprietà file + + + + General + Generali + + + + Location: + Posizione: + + + + File type: + Tipo file: + + + + Mime type: + Tipo MIME: + + + + File size: + Dimensione file: + + + + On-disk size: + Dimensione sul disco: + + + + Last modified: + Ultima modifica: + + + + Link target: + Collegamento a: + + + + Open With: + Apri con: + + + + Last accessed: + Ultimo accesso: + + + + Permissions + Permessi + + + + Ownership + Proprietario + + + + + + Group: + Gruppo: + + + + + + Owner: + Proprietario: + + + + Access Control + Controllo accessi + + + + + Other: + Altri: + + + + Make the file executable + Rendi il file eseguibile + + + + + + Read + Lettura + + + + + + Write + Scrittura + + + + + + Execute + Esecuzione + + + + Sticky + Sticky + + + + SetUID + SetUID + + + + SetGID + SetGID + + + + Advanced Mode + Modalità avanzata + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + Copia qui + + + + Move here + Sposta qui + + + + Create symlink here + Crea collegamento qui + + + + Cancel + Annulla + + + + Fm::EditBookmarksDialog + + + New bookmark + Nuovo segnalibro + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + Apri + + + OpenWith + ApriCon + + + + Cut + Taglia + + + + Copy + Copia + + + + Paste + Incolla + + + + + &Move to Trash + Cestin&a + + + + Output + + + + + &Delete + &Rimuovi + + + + Rename + Rinomina + + + + Open With... + + + + + Other Applications + + + + + &Restore + + + + + Extract to... + Estrai in... + + + + Extract Here + Estrai qui + + + + Compress + Comprimi + + + + Properties + Proprietà + + + + Fm::FileOperation + + + Error + Errore + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Alcuni file non possono essere spostati nel cestino perché il file system su cui si trovano non supporta questa operazione. +Vuoi invece eliminarli? + + + + + Confirm + Conferma + + + + Do you want to delete the selected files? + Rimuovere i file selezionati? + + + + Do you want to move the selected files to trash can? + Spostare nel cestino i file selezionati? + + + + Fm::FileOperationDialog + + + Move files + Sposta file + + + + Moving the following files to destination folder: + Spostamento dei file seguenti nella cartella di destinazione: + + + + Copy Files + Copia file + + + + Copying the following files to destination folder: + Copia dei file seguenti nella cartella di destinazione: + + + + Trash Files + Cestina file + + + + Moving the following files to trash can: + Spostamento dei file seguenti nel cestino: + + + + Delete Files + Rimuovi file + + + + Deleting the following files + Rimozione dei file seguenti + + + + Create Symlinks + Crea collegamenti simbolici + + + + Creating symlinks for the following files: + Creazione collegamenti simbolici per i seguenti file: + + + + Change Attributes + Cambia attributi + + + + Changing attributes of the following files: + Cambiamento attributi per i seguenti file: + + + + Restore Trashed Files + Ripristina file cestinati + + + + Restoring the following files from trash can: + Ripristino dei file seguenti dal cestino: + + + + Error + Errore + + + + Fm::FilePropsDialog + + + View folder content + Visualizza contenuti cartella + + + + View and modify folder content + Visualizza e modifica contenuti cartella + + + + Read + Lettura + + + + Read and write + Lettura e scrittura + + + + Forbidden + Vietato + + + + Files of different types + File di tipi diversi + + + + Multiple Files + File multipli + + + + Apply changes + Applica modifiche + + + + Do you want to recursively apply these changes to all files and sub-folders? + Applicare ricorsivamente queste modifiche a tutti i file e a tutte le sotto-cartelle? + + + + Fm::FolderMenu + + + Create &New + Crea &nuovo + + + + &Paste + &Incolla + + + + Select &All + Seleziona t&utto + + + + Invert Selection + Inverti selezione + + + + Sorting + Ordinamento + + + + Show Hidden + Mostra nascosti + + + + Folder Pr&operties + Pr&oprietà cartella + + + + Folder + Cartella + + + File + File + + + + Blank File + + + + + By File Name + Per nome file + + + + By Modification Time + Per data modifica + + + + By File Size + Per dimensione file + + + + By File Type + Per tipo file + + + + By File Owner + Per proprietario file + + + + Ascending + Crescente + + + + Descending + Decrescente + + + + Folder First + Prima le cartelle + + + + Case Sensitive + Distingui MAIUSCOLE/minuscole + + + + Fm::FolderModel + + + Name + Nome + + + + Type + Tipo + + + + Size + Dimensione + + + + Modified + Modificato + + + + Owner + Proprietario + + + + Fm::FontButton + + + Bold + Grassetto + + + + Italic + Corsivo + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Connetti + + + + Fm::PlacesModel + + + Places + Luoghi + + + + Desktop + Scrivania + + + + Trash + Cestino + + + + Computer + Computer + + + + Applications + Applicazioni + + + + Network + Rete + + + + Devices + Periferiche + + + + Bookmarks + Segnalibri + + + + Fm::PlacesView + + + Empty Trash + + + + + Rename + Rinomina + + + + Delete + Rimuovi + + + + + Unmount + Smonta + + + + Mount + Monta + + + + Eject + Espelli + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Tipo: %1 +Dimensione: %2 +Ultima modifica: %3 + + + + Type: %1 +Modified: %2 + Tipo: %1 +Ultima modifica: %2 + + + + Type: %1 +Modified: %3 + Tipo: %1 +Ultima modifica: %3 + + + + &Overwrite + S&ovrascrivi + + + + &Rename + &Rinomina + + + + Fm::SidePane + + + + Places + Luoghi + + + + + Directory Tree + + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + Monta + + + + Connect &anonymously + Connetti _anonimamente + + + + Connect as u&ser: + Connetti come &utente: + + + + &Username: + &Nome utente: + + + + &Password: + &Password: + + + + &Domain: + &Dominio: + + + + Forget password &immediately + Dimentica la password &immediatamente + + + + Remember password until you &logout + Ricorda &la password fino al termine sessione + + + + Remember &forever + Ricorda per &sempre + + + + QObject + + + + + + Error + Errore + + + + Rename File + Rinomina file + + + + Please enter a new name: + Inserire il nuovo nome: + + + + Please enter a new file name: + Inserire il nuovo nome del file: + + + + New text file + Nuovo file di testo + + + + Please enter a new folder name: + Inserire il nuovo nome della cartella: + + + + New folder + Nuova cartella + + + + Enter a name for the new %1: + + + + + Create File + Crea file + + + + RenameDialog + + + Confirm to replace files + Conferma sostituzione dei file + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">C'è già un file con lo stesso nome in questa posizione.</span></p><p>Sostituire il file esistente?</p></body></html> + + + + dest + dest + + + + with the following file? + con il file seguente? + + + + src file info + info file sorg + + + + dest file info + info file dest + + + + src + sorg + + + + &File name: + Nome &file: + + + + Apply this option to all existing files + Applica questa opzione a tutti i file esistenti + + + diff --git a/libfm-qt/translations/libfm-qt_ja.ts b/libfm-qt/translations/libfm-qt_ja.ts new file mode 100644 index 0000000..0d4f349 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_ja.ts @@ -0,0 +1,1040 @@ + + + + + AppChooserDialog + + + Choose an Application + アプリケーションを選ぶ + + + + Installed Applications + インストール済アプリケーション + + + + Custom Command + カスタムコマンド + + + + Command line to execute: + 実行するコマンドライン: + + + + Application name: + アプリケーション名 + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>コマンドラインには、次の特別なコードを使用することができます:</b> +<ul> +<li><b>%f</b>: 単一のファイル名を表す</li> +<li><b>%F</b>: 複数のファイル名を表す</li> +<li><b>%u</b>: 単一のファイルのURIを表す</li> +<li><b>%U</b>: 複数のURIを表す</li> +</ul> + + + + Keep terminal window open after command execution + コマンド実行後も端末のウィンドウを閉じない + + + + Execute in terminal emulator + 端末エミュレーター内で実行 + + + + Set selected application as default action of this file type + 選択したアプリケーションをこのファイルの種類に関連付ける + + + + EditBookmarksDialog + + + Edit Bookmarks + ブックマークを編集 + + + + Name + 名前 + + + + Location + 場所 + + + + &Add Item + アイテムを追加(&A) + + + + &Remove Item + アイテムを削除(&R) + + + + Use drag and drop to reorder the items + アイテムを並べ替えるにはドラッグアンドドロップ + + + + ExecFileDialog + + + Execute file + ファイルを実行 + + + + &Open + 開く(&O) + + + + E&xecute + 実行(&E) + + + + Execute in &Terminal + 端末内で実行(&T) + + + + Cancel + キャンセル + + + + FileOperationDialog + + + Destination: + 送り先: + + + + Processing: + 処理中: + + + + Preparing... + 準備中... + + + + Progress + 進行状況 + + + + Time remaining: + 残り時間: + + + + FilePropsDialog + + + File Properties + ファイルのプロパティー + + + + General + 一般 + + + + Location: + 場所: + + + + File type: + 種類: + + + + Mime type: + MIMEタイプ: + + + + File size: + サイズ: + + + + On-disk size: + ディスク上のサイズ: + + + + Last modified: + 最終更新日時: + + + + Link target: + リンク先: + + + + Open With: + 関連付け: + + + + Last accessed: + 最終アクセス日時: + + + + Permissions + パーミッション + + + + Ownership + 所有権 + + + + + + Group: + グループ: + + + + + + Owner: + 所有者: + + + + Access Control + アクセス制限 + + + + + Other: + その他: + + + + Make the file executable + ファイルを実行可能にする + + + + + + Read + 読取り + + + + + + Write + 書込み + + + + + + Execute + 実行 + + + + Sticky + スティッキー + + + + SetUID + UIDを設定 + + + + SetGID + GIDを設定 + + + + Advanced Mode + 高度なモード + + + + Fm::AppChooserComboBox + + + Customize + カスタマイズ + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + ファイルを開くアプリケーションを選択 + + + + Fm::DirTreeModel + + + Loading... + ロード中... + + + + <No sub folders> + <サブフォルダーなし> + + + + Fm::DndActionMenu + + + Copy here + ここへコピー + + + + Move here + ここへ移動 + + + + Create symlink here + シンボリックリンクを作成 + + + + Cancel + キャンセル + + + + Fm::EditBookmarksDialog + + + New bookmark + 新規ブックマーク + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + このテキストファイル '%1' は実行可能スクリプトです。 +どうしますか? + + + + This file '%1' is executable. Do you want to execute it? + このファイル '%1' は実行可能です。 +実行しますか? + + + + Fm::FileMenu + + + Open + 開く + + + OpenWith + アプリケーションで開く + + + + Cut + 切り取り + + + + Copy + コピー + + + + Paste + 貼り付け + + + + + &Move to Trash + ゴミ箱へ移動(&M) + + + + Output + 出力 + + + + &Delete + 削除(&D) + + + + Rename + 名前を変更する + + + + Open With... + アプリケーションで開く + + + + Other Applications + その他のアプリケーション + + + + &Restore + + + + + Extract to... + 展開する + + + + Extract Here + ここへ展開する + + + + Compress + 圧縮する + + + + Properties + プロパティー + + + + Fm::FileOperation + + + Error + エラー + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + ファイルシステムのサポートがないため、ゴミ箱へ移動できないファイルがあります。 +かわりにこれらを削除しますか? + + + + + Confirm + 確認 + + + + Do you want to delete the selected files? + 選択したファイルを削除しますか? + + + + Do you want to move the selected files to trash can? + 選択したファイルをゴミ箱に移しますか? + + + + Fm::FileOperationDialog + + + Move files + ファイルを移動 + + + + Moving the following files to destination folder: + 次のファイルを対象のフォルダーへ移動: + + + + Copy Files + ファイルをコピー + + + + Copying the following files to destination folder: + 次のファイルを対象のフォルダーへコピー: + + + + Trash Files + ファイルをゴミ箱へ入れる + + + + Moving the following files to trash can: + 次のファイルをゴミ箱へ入れる: + + + + Delete Files + ファイルを削除 + + + + Deleting the following files + 以下のファイルを削除 + + + + Create Symlinks + シンボリックリンク作成 + + + + Creating symlinks for the following files: + 以下のファイルのシンボリックリンクを作成: + + + + Change Attributes + 属性を変更 + + + + Changing attributes of the following files: + 以下のファイルの属性を変更: + + + + Restore Trashed Files + ゴミ箱から戻す + + + + Restoring the following files from trash can: + 以下のファイルをゴミ箱から戻す: + + + + Error + エラー + + + + Fm::FilePropsDialog + + + View folder content + フォルダーの内容を表示 + + + + View and modify folder content + フォルダーの内容を表示・変更 + + + + Read + 読取り + + + + Read and write + 読取りおよび書込み + + + + Forbidden + 禁止 + + + + Files of different types + 異なる種類のファイル + + + + Multiple Files + 複数のファイル + + + + Apply changes + 変更を適用 + + + + Do you want to recursively apply these changes to all files and sub-folders? + 変更をすべてのファイルとサブフォルダーにも再帰的に適用しますか? + + + + Fm::FolderMenu + + + Create &New + 新規作成 (&N) + + + + &Paste + ペースト(&P) + + + + Select &All + すべてを選択(&A) + + + + Invert Selection + 選択を反転 + + + + Sorting + ソート + + + + Show Hidden + 隠しファイルの表示 + + + + Folder Pr&operties + フォルダのプロパティー(&O) + + + + Folder + フォルダー + + + File + ファイル + + + + Blank File + 空のファイル + + + + By File Name + 名前 + + + + By Modification Time + 更新時刻 + + + + By File Size + サイズ + + + + By File Type + 種類 + + + + By File Owner + 所有者 + + + + Ascending + 昇順 + + + + Descending + 降順 + + + + Folder First + フォルダーを先に + + + + Case Sensitive + 大文字小文字を区別 + + + + Fm::FolderModel + + + Name + 名前 + + + + Type + 種類 + + + + Size + サイズ + + + + Modified + 更新日時 + + + + Owner + 所有者 + + + + Fm::FontButton + + + Bold + 太字 + + + + Italic + 斜体 + + + + Fm::MountOperationPasswordDialog + + + &Connect + 接続&(C) + + + + Fm::PlacesModel + + + Places + 場所 + + + + Desktop + デスクトップ + + + + Trash + ゴミ箱 + + + + Computer + コンピューター + + + + Applications + アプリケーション + + + + Network + ネットワーク + + + + Devices + デバイス + + + + Bookmarks + ブックマーク + + + + Fm::PlacesView + + + Empty Trash + ゴミ箱を空にする + + + + Rename + 名前を変更 + + + + Delete + 削除 + + + + + Unmount + アンマウント + + + + Mount + マウント + + + + Eject + 取出し + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + 種類: %1 +サイズ: %2 +更新日時: %3 + + + + Type: %1 +Modified: %2 + 種類: %1 +更新日時: %2 + + + + Type: %1 +Modified: %3 + 種類: %1 +更新日時: %3 + + + + &Overwrite + 上書き(&O) + + + + &Rename + 名前を変更(&R) + + + + Fm::SidePane + + + + Places + 場所 + + + + + Directory Tree + ディレクトリーツリー + + + + Shows list of common places, devices, and bookmarks in sidebar + サイドバーに、一般的な場所およびデバイス、ブックマークのリストを表示 + + + + Shows tree of directories in sidebar + サイドバーにディレクトリーツリーを表示 + + + + MountOperationPasswordDialog + + + Mount + マウント + + + + Connect &anonymously + 匿名で接続(&A) + + + + Connect as u&ser: + ユーザーとして接続(&U) + + + + &Username: + ユーザー名(&U): + + + + &Password: + &パスワード(&P): + + + + &Domain: + &ドメイン(&D): + + + + Forget password &immediately + パスワードを記憶させない + + + + Remember password until you &logout + パスワードをログアウトするまで記憶させる + + + + Remember &forever + パスワードを恒久的に記憶させる + + + + QObject + + + + + + Error + エラー + + + + Rename File + ファイル名を変更 + + + + Please enter a new name: + 新しい名前を入力してください: + + + + Please enter a new file name: + 新規ファイルの名前を入力してください: + + + + New text file + 新規テキストファイル + + + + Please enter a new folder name: + 新規フォルダの名前を入力してください: + + + + New folder + 新規フォルダー + + + + Enter a name for the new %1: + 新しい %1 の名前を入力してください: + + + + Create File + ファイル作成 + + + + RenameDialog + + + Confirm to replace files + ファイルの置換えを確認 + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">この場所にはすでに、同じ名前のファイルがあります。</span></p><p>既存のファイルを置き換えますか?</p></body></html> + + + + dest + 送り先 + + + + with the following file? + 以下のファイルと置き換えますか? + + + + src file info + + + + + dest file info + 送り先のファイルの情報 + + + + src + 送り元のファイルの情報 + + + + &File name: + ファイル名(&F): + + + + Apply this option to all existing files + 既存のすべてのファイルにも適用する + + + diff --git a/libfm-qt/translations/libfm-qt_lt_LT.ts b/libfm-qt/translations/libfm-qt_lt_LT.ts new file mode 100644 index 0000000..efbb8c2 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_lt_LT.ts @@ -0,0 +1,842 @@ + + + + + AppChooserDialog + + Choose an Application + + + + Installed Applications + + + + Custom Command + + + + Command line to execute: + + + + Application name: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + Keep terminal window open after command execution + + + + Execute in terminal emulator + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + Edit Bookmarks + Redaguoti žymeles + + + Name + Pavadinimas + + + Location + Vieta + + + &Add Item + &Pridėti elementą + + + &Remove Item + &Pašalinti elementą + + + Use drag and drop to reorder the items + Failų tvarkai pakeisti naudokite vilkimą + + + + ExecFileDialog + + Execute file + + + + &Open + + + + E&xecute + + + + Execute in &Terminal + + + + Cancel + Atšaukti + + + + FileOperationDialog + + Destination: + Paskirties vieta: + + + Processing: + Apdorojama: + + + Preparing... + Ruošiamasi... + + + Progress + Eiga + + + Time remaining: + Liko laiko: + + + + FilePropsDialog + + File Properties + Failo savybės + + + General + Bendra + + + Location: + Vieta: + + + File type: + Failo tipas: + + + Mime type: + Mime tipas: + + + File size: + Failo dydis: + + + On-disk size: + Dydis diske: + + + Last modified: + Paskutinis pakeitimas: + + + Link target: + Nuorodos tikslas: + + + Open With: + Atverti su: + + + Last accessed: + Paskutinį kartą naudota: + + + Permissions + Leidimai + + + Ownership + Nuosavybė + + + Group: + Grupė: + + + Owner: + Savininkas: + + + Access Control + Prieigos kontrolė + + + Other: + Kita: + + + Make the file executable + Padaryti failą vykdomu + + + Read + Skaityti + + + Write + Rašyti + + + Execute + Vykdyti + + + Sticky + Lipnus + + + SetUID + Nustatyti UID + + + SetGID + Nustatyti GID + + + Advanced Mode + Išsamus režimas + + + + Fm::AppChooserComboBox + + Customize + + + + + Fm::AppChooserDialog + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + Loading... + + + + <No sub folders> + + + + + Fm::DndActionMenu + + Copy here + Kopijuoti čia + + + Move here + Perkelti čia + + + Create symlink here + symlink=symbolic link + Sukurti simbolinę nuorodą + + + Cancel + Atšaukti + + + Create symlink here + Sukurti simbolinę nuorodą + + + + Fm::EditBookmarksDialog + + New bookmark + Nauja žymelė + + + + Fm::ExecFileDialog + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + Open + Atverti + + + OpenWith + Atverti su + + + Cut + Iškirpti + + + Copy + Kopijuoti + + + Paste + Įklijuoti + + + &Move to Trash + &Perkelti į šiukšlinę + + + &Delete + &Pašalinti + + + Rename + Pervadinti + + + Extract to... + Išskleisti į... + + + Extract Here + Išskleisti čia + + + Compress + Archyvuoti + + + Properties + Savybės + + + Open With... + + + + Other Applications + + + + Output + + + + &Restore + + + + + Fm::FileOperation + + Confirm + Patvirtinti + + + Do you want to delete the selected files? + Ar norite ištrinti pasirinktus failus? + + + Do you want to move the selected files to trash can? + Ar norite perkelti pasirinktus failus į šiukšlinę? + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Kai kurie failai negali būti išmesti į šiukšlinę, nes failų sistema to nepalaiko. +Ar norite vietoje to juos pašalinti visam laikui? + + + Error + Klaida + + + + Fm::FileOperationDialog + + Move files + Perkelti failus + + + Moving the following files to destination folder: + Šie failai perkeliami į paskirties aplanką: + + + Copy Files + Kopijuoti failus + + + Copying the following files to destination folder: + Šie failai kopijuojami į paskirties aplanką: + + + Trash Files + Išmesti failus į šiukšliadėžę + + + Moving the following files to trash can: + Failai perkeliami į šiukšliadėžę: + + + Delete Files + Pašalinti failus + + + Deleting the following files + Šalinami šie failai + + + Create Symlinks + symlink=symbolic link + Sukurti simbolinę nuorodą + + + Creating symlinks for the following files: + Šiems failams kuriamos simbolinės nuorodos: + + + Change Attributes + Keisti atributus + + + Changing attributes of the following files: + Keičiami šių failų atributai: + + + Restore Trashed Files + Atstatyti ištrintus failus + + + Restoring the following files from trash can: + Šie failai atstatomi iš šiukšliadėžės: + + + Error + Klaida + + + Create Symlinks + Sukurti simbolinę nuorodą + + + + Fm::FilePropsDialog + + View folder content + Žiūrėti aplanko turinį + + + View and modify folder content + Žiūrėti ir keisti aplanko turinį + + + Read + Skaityti + + + Read and write + Skaityti ir rašyti + + + Forbidden + Uždrausta + + + Files of different types + Skirtingų tipų failai + + + Multiple Files + Keli failai + + + Apply changes + Pritaikyti pakeitimus + + + Do you want to recursively apply these changes to all files and sub-folders? + Ar norite rekursyviai pritaikyti šiuos pakeitimus visiems failams ir poaplankiams? + + + + Fm::FolderMenu + + Create &New + &Kurti naują + + + &Paste + Į&klijuoti + + + Select &All + Pasirinkti &viską + + + Invert Selection + Invertuoti pasirinkimą + + + Sorting + Rikiavimas + + + Show Hidden + Rodyti paslėptus + + + Folder Pr&operties + Failo &savybės + + + Folder + Aplankas + + + File + Failas + + + By File Name + Pagal failo vardą + + + By Modification Time + Pagal keitimo datą + + + By File Size + Pagal failo dydį + + + By File Type + Pagal failo tipą + + + By File Owner + Pagal failo savininką + + + Ascending + Didėjančiai + + + Descending + Mažėjančiai + + + Folder First + Pirmiausia aplankai + + + Case Sensitive + Skirti raidžių dydį + + + Blank File + + + + + Fm::FolderModel + + Name + Pavadinimas + + + Type + Tipas + + + Size + Dydis + + + Modified + Pakeista + + + Owner + Savininkas + + + + Fm::FontButton + + Bold + Paryškintas + + + Italic + Kursyvinis + + + + Fm::MountOperationPasswordDialog + + &Connect + &Prisijungti + + + + Fm::PlacesModel + + Desktop + Darbastalis + + + Trash + Šiukšlinė + + + Computer + Kompiuteris + + + Applications + Programos + + + Network + Tinklas + + + Places + + + + Devices + + + + Bookmarks + + + + + Fm::PlacesView + + Rename + Pervadinti + + + Delete + Šalinami failai + + + Unmount + Atjungti + + + Mount + Prijungti + + + Eject + Išstumti + + + Empty Trash + + + + + Fm::RenameDialog + + Type: %1 +Size: %2 +Modified: %3 + Tipas: %1 +Dydis: %2 +Keista: %3 + + + Type: %1 +Modified: %3 + Tipas: %1 +Keista: %3 + + + &Overwrite + &Perrašyti + + + &Rename + Pe&rvadinti + + + Type: %1 +Modified: %2 + Tipas: %1 +Keista: %2 {1 +?} + + + + Fm::SidePane + + Places + + + + Directory Tree + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + Mount + Prijungti + + + Connect &anonymously + Prisijungti &anonimiškai + + + Connect as u&ser: + Prisijungti kaip nau&dotojui: + + + &Username: + &Naudotojo vardas: + + + &Password: + &Slaptažodis: + + + &Domain: + &Domenas: + + + Forget password &immediately + &Neįsiminti slaptažodžio + + + Remember password until you &logout + &Atsiminti slaptažodį iki atsijungsite + + + Remember &forever + Prisiminti &visam laikui + + + + QObject + + Error + Klaida + + + Rename File + Pervadinti failą + + + Please enter a new name: + Įveskite naują pavadinimą: + + + Please enter a new file name: + Įveskite naują failo pavadinimą: + + + New text file + Naujas tekstinis failas + + + Please enter a new folder name: + Įveskite naują failo pavadinimą: + + + New folder + Naujas aplankas + + + Create File + Sukurti failą + + + Enter a name for the new %1: + + + + + RenameDialog + + Confirm to replace files + Patvirtinti failų pakeitimą + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Šiame aplanke jau yra failas tokiu pačiu pavadinimu.</span></p><p>Ar norite pakeisti esamą failą?</p></body></html> + + + dest + paskirtis + + + with the following file? + šiuo failu? + + + src file info + šaltinio failo informacija + + + dest file info + paskirties failo informacija + + + src + šaltinis + + + &File name: + &Failo pavadinimas: + + + Apply this option to all existing files + Pritaikyti šią nuostatą visiems failams + + + diff --git a/libfm-qt/translations/libfm-qt_pt.ts b/libfm-qt/translations/libfm-qt_pt.ts new file mode 100644 index 0000000..329a549 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_pt.ts @@ -0,0 +1,1039 @@ + + + + + AppChooserDialog + + + Choose an Application + Escolha uma aplicação + + + + Installed Applications + Aplicações instaladas + + + + Custom Command + Comando personalizado + + + + Command line to execute: + Linha de comandos a executar: + + + + Application name: + Nome da aplicação: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>Pode utilizar os seguintes códigos na linha de comandos:</b> +<ul> +<li><b>%f</b>: é o nome de um ficheiro</li> +<li><b>%F</b>: é o nome de vários ficheiros</li> +<li><b>%u</b>: é o URI do ficheiro</li> +<li><b>%U</b>: é o URI de vários ficheiros</li> +</ul> + + + + Keep terminal window open after command execution + Manter janela de terminal aberta depois de executar o comando + + + + Execute in terminal emulator + Executar no emulador de terminal + + + + Set selected application as default action of this file type + Utilizar a aplicação selecionada como pré-definida para este tipo de ficheiro + + + + EditBookmarksDialog + + + Edit Bookmarks + Editar marcadores + + + + Name + Nome + + + + Location + Localização + + + + &Add Item + &Adicionar item + + + + &Remove Item + &Remover item + + + + Use drag and drop to reorder the items + Arraste e largue para organizar itens + + + + ExecFileDialog + + + Execute file + Executar ficheiro + + + + &Open + &Abrir + + + + E&xecute + E&xecutar + + + + Execute in &Terminal + Executar no &terminal + + + + Cancel + Cancelar + + + + FileOperationDialog + + + Destination: + Destino: + + + + Processing: + Processamento: + + + + Preparing... + Preparação... + + + + Progress + Evolução + + + + Time remaining: + Tempo restante: + + + + FilePropsDialog + + + File Properties + Propriedades do ficheiro + + + + General + Geral + + + + Location: + Localização: + + + + File type: + Tipo de ficheiro: + + + + Mime type: + Tipo MIME: + + + + File size: + Tamanho do ficheiro: + + + + On-disk size: + Tamanho no disco: + + + + Last modified: + Última modificação: + + + + Link target: + Destino da ligação: + + + + Open With: + Abrir com: + + + + Last accessed: + Último acesso: + + + + Permissions + Pemissões + + + + Ownership + Propriedade + + + + + + Group: + Grupo: + + + + + + Owner: + Dono: + + + + Access Control + Controlo de acesso + + + + + Other: + Outro: + + + + Make the file executable + Marcar como executável + + + + + + Read + Leitura + + + + + + Write + Escrita + + + + + + Execute + Execução + + + + Sticky + Fixo + + + + SetUID + Definir UID + + + + SetGID + Definir GID + + + + Advanced Mode + Modo avançado + + + + Fm::AppChooserComboBox + + + Customize + Personalizar + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + Selecione uma aplicação para abrir os ficheiros %1 + + + + Fm::DirTreeModel + + + Loading... + A carregar... + + + + <No sub folders> + <Não existem subpastas> + + + + Fm::DndActionMenu + + + Copy here + Copiar para aqui + + + + Move here + Mover para aqui + + + + Create symlink here + Criar ligação simbólica aqui + + + + Cancel + Cancelar + + + + Fm::EditBookmarksDialog + + + New bookmark + Novo marcador + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + Parece que o ficheiro de texto %1 é um script executável. +O que pretende fazer com o ficheiro? + + + + This file '%1' is executable. Do you want to execute it? + O ficheiro %1 é um executável. Pretende executar o ficheiro? + + + + Fm::FileMenu + + + Open + Abrir + + + OpenWith + Abrir com + + + + Cut + Cortar + + + + Copy + Copiar + + + + Paste + Colar + + + + + &Move to Trash + &Mover para o lixo + + + + Output + Destino + + + + &Delete + &Eliminar + + + + Rename + Mudar nome + + + + Open With... + Abrir com... + + + + Other Applications + Outras aplicações + + + + &Restore + &Restaurar + + + + Extract to... + Extrair para... + + + + Extract Here + Extrair aqui + + + + Compress + Comprimir + + + + Properties + Propriedades + + + + Fm::FileOperation + + + Error + Erro + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Alguns ficheiros não podem ser movidos para o lixo porque o sistema de ficheiros não suporta esta operação. +Eliminar permanentemente? + + + + + Confirm + Confirmação + + + + Do you want to delete the selected files? + Quer mesmo eliminar o(s) ficheiro(s) selecionado(s)? + + + + Do you want to move the selected files to trash can? + Quer mesmo mover o(s) ficheiro(s) selecionado(s) para o lixo? + + + + Fm::FileOperationDialog + + + Move files + Mover ficheiros + + + + Moving the following files to destination folder: + A mover os ficheiros para a pasta de destino: + + + + Copy Files + Copiar ficheiros + + + + Copying the following files to destination folder: + A copiar os ficheiros para a pasta de destino: + + + + Trash Files + Destruir ficheiros + + + + Moving the following files to trash can: + A mover os ficheiros para o lixo: + + + + Delete Files + Eliminar ficheiros + + + + Deleting the following files + A eliminar estes ficheiros + + + + Create Symlinks + Criar ligações simbólicas + + + + Creating symlinks for the following files: + A criar ligações simbólicas a estes ficheiros: + + + + Change Attributes + Alterar atributos + + + + Changing attributes of the following files: + A alterar os atributos destes ficheiros: + + + + Restore Trashed Files + Restaurar ficheiros eliminados + + + + Restoring the following files from trash can: + Restaurar estes ficheiros do lixo: + + + + Error + Erro + + + + Fm::FilePropsDialog + + + View folder content + Ver conteúdo da pasta + + + + View and modify folder content + Ver e modificar conteúdo da pasta + + + + Read + Leitura + + + + Read and write + Leitura e escrita + + + + Forbidden + Proibido + + + + Files of different types + Ficheiros de outro tipo + + + + Multiple Files + Vários ficheiros + + + + Apply changes + Aplicar alterações + + + + Do you want to recursively apply these changes to all files and sub-folders? + Pretende aplicar as alterações a todos os ficheiros e subpastas? + + + + Fm::FolderMenu + + + Create &New + Criar &novo(a) + + + + &Paste + Co&lar + + + + Select &All + Selecion&ar tudo + + + + Invert Selection + Inverter seleção + + + + Sorting + Ordenação + + + + Show Hidden + Mostrar ocultos + + + + Folder Pr&operties + Pr&opriedades da pasta + + + + Folder + Pasta + + + File + Ficheiro + + + + Blank File + Ficheiro vazio + + + + By File Name + Por nome de ficheiro + + + + By Modification Time + Por data de modificação + + + + By File Size + Por tamanho de ficheiro + + + + By File Type + Por tipo de ficheiro + + + + By File Owner + Por dono de ficheiro + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + Folder First + Pastas no início + + + + Case Sensitive + Diferenciar capitalização + + + + Fm::FolderModel + + + Name + Nome + + + + Type + Tipo + + + + Size + Tamanho + + + + Modified + Modificado + + + + Owner + Dono + + + + Fm::FontButton + + + Bold + Negrito + + + + Italic + Itálico + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Ligar + + + + Fm::PlacesModel + + + Places + Locais + + + + Desktop + Área de trabalho + + + + Trash + Lixo + + + + Computer + Computador + + + + Applications + Aplicações + + + + Network + Rede + + + + Devices + Dispositivos + + + + Bookmarks + Marcadores + + + + Fm::PlacesView + + + Empty Trash + Esvaziar lixo + + + + Rename + Mudar nome + + + + Delete + Eliminar + + + + + Unmount + Desmontar + + + + Mount + Montar + + + + Eject + Ejetar + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Tipo: %1 +Tamanho: %2 +Modificado: %3 + + + + Type: %1 +Modified: %2 + Tipo: %1 +Modificado: %2 + + + + Type: %1 +Modified: %3 + Tipo: %1 +Modificado: %3 + + + + &Overwrite + &Substituir + + + + &Rename + &Mudar nome + + + + Fm::SidePane + + + + Places + Locais + + + + + Directory Tree + Árvore de diretórios + + + + Shows list of common places, devices, and bookmarks in sidebar + Mostra a lista de locais, dispositivos e marcadores na barra lateral + + + + Shows tree of directories in sidebar + Mostra a árvore de diretórios na barra lateral + + + + MountOperationPasswordDialog + + + Mount + Montar + + + + Connect &anonymously + Ligar &anonimamente + + + + Connect as u&ser: + Ligar com utili&zador: + + + + &Username: + Nome de &utilizador: + + + + &Password: + &Senha: + + + + &Domain: + &Domínio: + + + + Forget password &immediately + Esquecer senha &imediatamente + + + + Remember password until you &logout + Memorizar sen&ha até fechar a sessão + + + + Remember &forever + Memorizar &eternamente + + + + QObject + + + + + + Error + Erro + + + + Rename File + Mudar nome do ficheiro + + + + Please enter a new name: + Introduza o novo nome: + + + + Please enter a new file name: + Introduza o nome do ficheiro: + + + + New text file + Novo ficheiro de texto + + + + Please enter a new folder name: + Introduza o nome da pasta: + + + + New folder + Nova pasta + + + + Enter a name for the new %1: + Introduza o nome para %1: + + + + Create File + Criar ficheiro + + + + RenameDialog + + + Confirm to replace files + Confirmação de substituição + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Já existe um ficheiro com o mesmo nome nesta localização.</span></p><p>Pretende substituir o ficheiro existente</p></body></html> + + + + dest + destino + + + + with the following file? + por este? + + + + src file info + informações do ficheiro de origem + + + + dest file info + informações do ficheiro de destino + + + + src + origem + + + + &File name: + Nome do &ficheiro: + + + + Apply this option to all existing files + Aplicar opção a todos os ficheiros existentes + + + diff --git a/libfm-qt/translations/libfm-qt_ru.ts b/libfm-qt/translations/libfm-qt_ru.ts new file mode 100644 index 0000000..fae2232 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_ru.ts @@ -0,0 +1,1031 @@ + + + + + AppChooserDialog + + + Choose an Application + Выбрать приложение + + + + Installed Applications + Установленные приложения + + + + Custom Command + Своя команда + + + + Command line to execute: + Выполняемая командная строка: + + + + Application name: + Имя приложения: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>Эти спец. коды могут быть использованы в командной строке:</b> +<ul> +<li><b>%f</b>: Означает имя одного файла</li> +<li><b>%F</b>: Означает имена нескольких файлов</li> +<li><b>%u</b>: Означает один URI файла</li> +<li><b>%U</b>: Означает несколько URI файлов</li> +</ul> + + + + Keep terminal window open after command execution + Держать окно терминала открытым после выполнения команды + + + + Execute in terminal emulator + Запустить в эмуляторе терминала + + + + Set selected application as default action of this file type + Использовать выбранное приложение как действие по умолчанию для файлов этого типа + + + + EditBookmarksDialog + + + Edit Bookmarks + Изменить закладки + + + + Name + Имя + + + + Location + Расположение + + + + &Add Item + &Добавить пункт + + + + &Remove Item + &Удалить пункт + + + + Use drag and drop to reorder the items + Используйте перетаскивание и отпускание для переупорядочивания пунктов + + + + ExecFileDialog + + + Execute file + Выполнить файл + + + + &Open + &Открыть + + + + E&xecute + В&ыполнить + + + + Execute in &Terminal + Выполнить в &терминале + + + + Cancel + Отмена + + + + FileOperationDialog + + + Destination: + Назначение: + + + + Processing: + Обработка: + + + + Preparing... + Подготовка... + + + + Progress + Прогресс + + + + Time remaining: + Времени осталось: + + + + FilePropsDialog + + + File Properties + Свойства файла + + + + General + Общие + + + + Location: + Расположение: + + + + File type: + Тип файла: + + + + Mime type: + Тип Mime: + + + + File size: + Размер файла: + + + + On-disk size: + Размер на диске: + + + + Last modified: + Последнее изменение: + + + + Link target: + Цель ссылки: + + + + Open With: + Открыть с помощью: + + + + Last accessed: + Последний доступ: + + + + Permissions + Разрешения + + + + Ownership + Владение + + + + + + Group: + Группа: + + + + + + Owner: + Владелец: + + + + Access Control + Контроль доступа + + + + + Other: + Остальные: + + + + Make the file executable + Сделать файл исполняемым + + + + + + Read + Чтение + + + + + + Write + Запись + + + + + + Execute + Выполнение + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + Расширенный режим + + + + Fm::AppChooserComboBox + + + Customize + Настроить + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + Выберите приложение, чтобы открыть "%1" файлов + + + + Fm::DirTreeModel + + + Loading... + Загрузка... + + + + <No sub folders> + <Нет подпапок> + + + + Fm::DndActionMenu + + + Copy here + Копировать сюда + + + + Move here + Переместить сюда + + + + Create symlink here + Создать здесь ссылку + + + + Cancel + Отмена + + + + Fm::EditBookmarksDialog + + + New bookmark + Новая закладка + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + Этот текстовый файл '%1' похож на исполняемый скрипт. +Что вы хотите с ним сделать? + + + + This file '%1' is executable. Do you want to execute it? + Это исполняемый файл '%1' . Вы хотите выполнить его? + + + + Fm::FileMenu + + + Open + Открыть + + + + Open With... + Открыть с помощью... + + + + Other Applications + Другие приложения + + + + &Restore + + + + + Cut + Вырезать + + + + Copy + Копировать + + + + Paste + Вставить + + + + + &Move to Trash + &Переместить в корзину + + + + Rename + Переименовать + + + + Extract to... + Распаковать в ... + + + + Extract Here + Распаковать здесь + + + + Compress + Сжать + + + + Properties + Свойства + + + + Output + Вывод + + + + &Delete + &Удалить + + + + Fm::FileOperation + + + Error + Ошибка + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Некоторые файлы не могут быть помещены в корзину, поскольку файловая система не поддерживает эту операцию. +Вы всё равно хотите их удалить? + + + + + Confirm + Подтвердить + + + + Do you want to delete the selected files? + Вы действительно хотите удалить выбранные файлы? + + + + Do you want to move the selected files to trash can? + Переместить выбранные файлы в корзину? + + + + Fm::FileOperationDialog + + + Move files + Перемещение файлов + + + + Moving the following files to destination folder: + Перемещение следующих файлов в папку назначения: + + + + Copy Files + Копирование файлов + + + + Copying the following files to destination folder: + Копирование следующих файлов в папку назначения: + + + + Trash Files + Перемещение в корзину файлов + + + + Moving the following files to trash can: + Перемещение следующих файлов в корзину: + + + + Delete Files + Удалить файлы + + + + Deleting the following files + Удаление следующих файлов + + + + Create Symlinks + Создание ссылок + + + + Creating symlinks for the following files: + Создание ссылок на следующие файлы: + + + + Change Attributes + Изменение атрибутов + + + + Changing attributes of the following files: + Изменение атрибутов следующих файлов: + + + + Restore Trashed Files + Восстановить файлы из корзины + + + + Restoring the following files from trash can: + Восстановление следующих файлов из корзины: + + + + Error + Ошибка + + + + Fm::FilePropsDialog + + + View folder content + Просмотр содержимого папки + + + + View and modify folder content + Просмотр и изменение содержимого папки + + + + Read + Чтение + + + + Read and write + Чтение и запись + + + + Forbidden + Запрет + + + + Files of different types + Файлы разного типа + + + + Multiple Files + Несколько файлов + + + + Apply changes + Применить изменения + + + + Do you want to recursively apply these changes to all files and sub-folders? + Применить изменения рекурсивно ко всем файлам и подпапкам? + + + + Fm::FolderMenu + + + Create &New + &Создать + + + + &Paste + &Вставить + + + + Select &All + Выбрать &всё + + + + Invert Selection + Инвертировать выделение + + + + Sorting + Сортировка + + + + Show Hidden + Показать скрытые + + + + Folder Pr&operties + &Свойства папки + + + + Folder + Папку + + + + Blank File + Пустой файл + + + + By File Name + По имени + + + + By Modification Time + По времени изменения + + + + By File Size + По размеру + + + + By File Type + По типу + + + + By File Owner + По владельцу + + + + Ascending + Возрастающая + + + + Descending + Убывающая + + + + Folder First + Сначала папки + + + + Case Sensitive + Регистрочувствительность + + + + Fm::FolderModel + + + Name + Имя + + + + Type + Тип + + + + Size + Размер + + + + Modified + Изменён + + + + Owner + Владелец + + + + Fm::FontButton + + + Bold + Жирный + + + + Italic + Курсив + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Соединить + + + + Fm::PlacesModel + + + Places + Места + + + + Desktop + Рабочий стол + + + + Computer + Компьютер + + + + Applications + Программы + + + + Network + Сеть + + + + Devices + Устройства + + + + Bookmarks + Закладки + + + + Trash + Корзина + + + + Fm::PlacesView + + + Empty Trash + Очистить корзину + + + + Rename + Переименовать + + + + Delete + Удалить + + + + + Unmount + Отключить + + + + Mount + Подключить + + + + Eject + Извлечь + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Тип: %1 +Размер: %2 +Изменён: %3 + + + + Type: %1 +Modified: %2 + Тип: %1 +Изменён: %2 + + + + Type: %1 +Modified: %3 + Тип: %1 +Изменён: %3 + + + + &Overwrite + &Перезаписать + + + + &Rename + &Переименовать + + + + Fm::SidePane + + + + Places + Места + + + + + Directory Tree + Дерево папок + + + + Shows list of common places, devices, and bookmarks in sidebar + Показывает список обычных мест, устройств и закладок в боковой панели + + + + Shows tree of directories in sidebar + Показывает дерево папок в боковой панели + + + + MountOperationPasswordDialog + + + Mount + Подключить + + + + Connect &anonymously + Подсоединить &анонимно + + + + Connect as u&ser: + Подсоединить как &пользователь: + + + + &Username: + &Имя пользователя: + + + + &Password: + &Пароль: + + + + &Domain: + &Домен: + + + + Forget password &immediately + Забыть пароль &сразу + + + + Remember password until you &logout + Запомнить пароль пока вы не &вышли + + + + Remember &forever + Запомнить &навсегда + + + + QObject + + + + + + Error + Ошибка + + + + Rename File + Переименовать файл + + + + Please enter a new name: + Введите новое имя: + + + + Please enter a new file name: + Введите имя нового файла: + + + + New text file + Новый текстовый файл + + + + Please enter a new folder name: + Введите имя новой папки: + + + + New folder + Новая папка + + + + Enter a name for the new %1: + Введите имя для нового %1: + + + + Create File + Создать файл + + + + RenameDialog + + + Confirm to replace files + Подтвердить замену файлов + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">В этом месте назначения уже есть файл с таким именем.</span></p><p>Вы хотите заменить существующий файл?</p></body></html> + + + + dest + + + + + with the following file? + следующим файлом? + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + &Имя файла: + + + + Apply this option to all existing files + Запомнить выбор для всех уже существующих файлов + + + diff --git a/libfm-qt/translations/libfm-qt_ru_RU.ts b/libfm-qt/translations/libfm-qt_ru_RU.ts new file mode 100644 index 0000000..89fab1d --- /dev/null +++ b/libfm-qt/translations/libfm-qt_ru_RU.ts @@ -0,0 +1,1031 @@ + + + + + AppChooserDialog + + + Choose an Application + Выбрать приложение + + + + Installed Applications + Установленные приложения + + + + Custom Command + Своя команда + + + + Command line to execute: + Выполняемая командная строка: + + + + Application name: + Имя приложения: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>Эти спец. коды могут быть использованы в командной строке:</b> +<ul> +<li><b>%f</b>: Означает имя одного файла</li> +<li><b>%F</b>: Означает имена нескольких файлов</li> +<li><b>%u</b>: Означает один URI файла</li> +<li><b>%U</b>: Означает несколько URI файлов</li> +</ul> + + + + Keep terminal window open after command execution + Держать окно терминала открытым после выполнения команды + + + + Execute in terminal emulator + Запустить в эмуляторе терминала + + + + Set selected application as default action of this file type + Использовать выбранное приложение как действие по умолчанию для файлов этого типа + + + + EditBookmarksDialog + + + Edit Bookmarks + Изменить закладки + + + + Name + Имя + + + + Location + Расположение + + + + &Add Item + &Добавить пункт + + + + &Remove Item + &Удалить пункт + + + + Use drag and drop to reorder the items + Используйте перетаскивание и отпускание для переупорядочивания пунктов + + + + ExecFileDialog + + + Execute file + Выполнить файл + + + + &Open + &Открыть + + + + E&xecute + В&ыполнить + + + + Execute in &Terminal + Выполнить в &терминале + + + + Cancel + Отмена + + + + FileOperationDialog + + + Destination: + Назначение: + + + + Processing: + Обработка: + + + + Preparing... + Подготовка... + + + + Progress + Прогресс + + + + Time remaining: + Времени осталось: + + + + FilePropsDialog + + + File Properties + Свойства файла + + + + General + Общие + + + + Location: + Расположение: + + + + File type: + Тип файла: + + + + Mime type: + Тип Mime: + + + + File size: + Размер файла: + + + + On-disk size: + Размер на диске: + + + + Last modified: + Последнее изменение: + + + + Link target: + Цель ссылки: + + + + Open With: + Открыть с помощью: + + + + Last accessed: + Последний доступ: + + + + Permissions + Разрешения + + + + Ownership + Владение + + + + + + Group: + Группа: + + + + + + Owner: + Владелец: + + + + Access Control + Контроль доступа + + + + + Other: + Остальные: + + + + Make the file executable + Сделать файл исполняемым + + + + + + Read + Чтение + + + + + + Write + Запись + + + + + + Execute + Выполнение + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + Расширенный режим + + + + Fm::AppChooserComboBox + + + Customize + Настроить + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + Выберите приложение, чтобы открыть "%1" файлов + + + + Fm::DirTreeModel + + + Loading... + Загрузка... + + + + <No sub folders> + <Нет подпапок> + + + + Fm::DndActionMenu + + + Copy here + Копировать сюда + + + + Move here + Переместить сюда + + + + Create symlink here + Создать здесь ссылку + + + + Cancel + Отмена + + + + Fm::EditBookmarksDialog + + + New bookmark + Новая закладка + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + Этот текстовый файл '%1' похож на исполняемый скрипт. +Что вы хотите с ним сделать? + + + + This file '%1' is executable. Do you want to execute it? + Это исполняемый файл '%1' . Вы хотите выполнить его? + + + + Fm::FileMenu + + + Open + Открыть + + + + Open With... + Открыть с помощью... + + + + Other Applications + Другие приложения + + + + &Restore + + + + + Cut + Вырезать + + + + Copy + Копировать + + + + Paste + Вставить + + + + + &Move to Trash + &Переместить в корзину + + + + Rename + Переименовать + + + + Extract to... + Распаковать в ... + + + + Extract Here + Распаковать здесь + + + + Compress + Сжать + + + + Properties + Свойства + + + + Output + Вывод + + + + &Delete + &Удалить + + + + Fm::FileOperation + + + Error + Ошибка + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + Некоторые файлы не могут быть помещены в корзину, поскольку файловая система не поддерживает эту операцию. +Вы всё равно хотите их удалить? + + + + + Confirm + Подтвердить + + + + Do you want to delete the selected files? + Вы действительно хотите удалить выбранные файлы? + + + + Do you want to move the selected files to trash can? + Переместить выбранные файлы в корзину? + + + + Fm::FileOperationDialog + + + Move files + Перемещение файлов + + + + Moving the following files to destination folder: + Перемещение следующих файлов в папку назначения: + + + + Copy Files + Копирование файлов + + + + Copying the following files to destination folder: + Копирование следующих файлов в папку назначения: + + + + Trash Files + Перемещение в корзину файлов + + + + Moving the following files to trash can: + Перемещение следующих файлов в корзину: + + + + Delete Files + Удалить файлы + + + + Deleting the following files + Удаление следующих файлов + + + + Create Symlinks + Создание ссылок + + + + Creating symlinks for the following files: + Создание ссылок на следующие файлы: + + + + Change Attributes + Изменение атрибутов + + + + Changing attributes of the following files: + Изменение атрибутов следующих файлов: + + + + Restore Trashed Files + Восстановить файлы из корзины + + + + Restoring the following files from trash can: + Восстановление следующих файлов из корзины: + + + + Error + Ошибка + + + + Fm::FilePropsDialog + + + View folder content + Просмотр содержимого папки + + + + View and modify folder content + Просмотр и изменение содержимого папки + + + + Read + Чтение + + + + Read and write + Чтение и запись + + + + Forbidden + Запрет + + + + Files of different types + Файлы разного типа + + + + Multiple Files + Несколько файлов + + + + Apply changes + Применить изменения + + + + Do you want to recursively apply these changes to all files and sub-folders? + Применить изменения рекурсивно ко всем файлам и подпапкам? + + + + Fm::FolderMenu + + + Create &New + &Создать + + + + &Paste + &Вставить + + + + Select &All + Выбрать &всё + + + + Invert Selection + Инвертировать выделение + + + + Sorting + Сортировка + + + + Show Hidden + Показать скрытые + + + + Folder Pr&operties + &Свойства папки + + + + Folder + Папку + + + + Blank File + Пустой файл + + + + By File Name + По имени + + + + By Modification Time + По времени изменения + + + + By File Size + По размеру + + + + By File Type + По типу + + + + By File Owner + По владельцу + + + + Ascending + Возрастающая + + + + Descending + Убывающая + + + + Folder First + Сначала папки + + + + Case Sensitive + Регистрочувствительность + + + + Fm::FolderModel + + + Name + Имя + + + + Type + Тип + + + + Size + Размер + + + + Modified + Изменён + + + + Owner + Владелец + + + + Fm::FontButton + + + Bold + Жирный + + + + Italic + Курсив + + + + Fm::MountOperationPasswordDialog + + + &Connect + &Соединить + + + + Fm::PlacesModel + + + Places + Места + + + + Desktop + Рабочий стол + + + + Computer + Компьютер + + + + Applications + Программы + + + + Network + Сеть + + + + Devices + Устройства + + + + Bookmarks + Закладки + + + + Trash + Корзина + + + + Fm::PlacesView + + + Empty Trash + Очистить корзину + + + + Rename + Переименовать + + + + Delete + Удалить + + + + + Unmount + Отключить + + + + Mount + Подключить + + + + Eject + Извлечь + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + Тип: %1 +Размер: %2 +Изменён: %3 + + + + Type: %1 +Modified: %2 + Тип: %1 +Изменён: %2 + + + + Type: %1 +Modified: %3 + Тип: %1 +Изменён: %3 + + + + &Overwrite + &Перезаписать + + + + &Rename + &Переименовать + + + + Fm::SidePane + + + + Places + Места + + + + + Directory Tree + Дерево папок + + + + Shows list of common places, devices, and bookmarks in sidebar + Показывает список обычных мест, устройств и закладок в боковой панели + + + + Shows tree of directories in sidebar + Показывает дерево папок в боковой панели + + + + MountOperationPasswordDialog + + + Mount + Подключить + + + + Connect &anonymously + Подсоединить &анонимно + + + + Connect as u&ser: + Подсоединить как &пользователь: + + + + &Username: + &Имя пользователя: + + + + &Password: + &Пароль: + + + + &Domain: + &Домен: + + + + Forget password &immediately + Забыть пароль &сразу + + + + Remember password until you &logout + Запомнить пароль пока вы не &вышли + + + + Remember &forever + Запомнить &навсегда + + + + QObject + + + + + + Error + Ошибка + + + + Rename File + Переименовать файл + + + + Please enter a new name: + Введите новое имя: + + + + Please enter a new file name: + Введите имя нового файла: + + + + New text file + Новый текстовый файл + + + + Please enter a new folder name: + Введите имя новой папки: + + + + New folder + Новая папка + + + + Enter a name for the new %1: + Введите имя для нового %1: + + + + Create File + Создать файл + + + + RenameDialog + + + Confirm to replace files + Подтвердить замену файлов + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">В этом месте назначения уже есть файл с таким именем.</span></p><p>Вы хотите заменить существующий файл?</p></body></html> + + + + dest + + + + + with the following file? + следующим файлом? + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + &Имя файла: + + + + Apply this option to all existing files + Запомнить выбор для всех уже существующих файлов + + + diff --git a/libfm-qt/translations/libfm-qt_template.ts b/libfm-qt/translations/libfm-qt_template.ts new file mode 100644 index 0000000..7adcf06 --- /dev/null +++ b/libfm-qt/translations/libfm-qt_template.ts @@ -0,0 +1,1019 @@ + + + + + AppChooserDialog + + + Choose an Application + + + + + Installed Applications + + + + + Custom Command + + + + + Command line to execute: + + + + + Application name: + + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + + + + + Keep terminal window open after command execution + + + + + Execute in terminal emulator + + + + + Set selected application as default action of this file type + + + + + EditBookmarksDialog + + + Edit Bookmarks + + + + + Name + + + + + Location + + + + + &Add Item + + + + + &Remove Item + + + + + Use drag and drop to reorder the items + + + + + ExecFileDialog + + + Execute file + + + + + &Open + + + + + E&xecute + + + + + Execute in &Terminal + + + + + Cancel + + + + + FileOperationDialog + + + Destination: + + + + + Processing: + + + + + Preparing... + + + + + Progress + + + + + Time remaining: + + + + + FilePropsDialog + + + File Properties + + + + + General + + + + + Location: + + + + + File type: + + + + + Mime type: + + + + + File size: + + + + + On-disk size: + + + + + Last modified: + + + + + Link target: + + + + + Open With: + + + + + Last accessed: + + + + + Permissions + + + + + Ownership + + + + + + + Group: + + + + + + + Owner: + + + + + Access Control + + + + + + Other: + + + + + Make the file executable + + + + + + + Read + + + + + + + Write + + + + + + + Execute + + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + + + + + Fm::AppChooserComboBox + + + Customize + + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + + + + + Fm::DirTreeModel + + + Loading... + + + + + <No sub folders> + + + + + Fm::DndActionMenu + + + Copy here + + + + + Move here + + + + + Create symlink here + + + + + Cancel + + + + + Fm::EditBookmarksDialog + + + New bookmark + + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + + + + + This file '%1' is executable. Do you want to execute it? + + + + + Fm::FileMenu + + + Open + + + + + &Restore + + + + + Cut + + + + + Copy + + + + + Paste + + + + + + &Move to Trash + + + + + Output + + + + + &Delete + + + + + Rename + + + + + Open With... + + + + + Other Applications + + + + + Extract to... + + + + + Extract Here + + + + + Compress + + + + + Properties + + + + + Fm::FileOperation + + + Error + + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + + + + + + Confirm + + + + + Do you want to delete the selected files? + + + + + Do you want to move the selected files to trash can? + + + + + Fm::FileOperationDialog + + + Move files + + + + + Moving the following files to destination folder: + + + + + Copy Files + + + + + Copying the following files to destination folder: + + + + + Trash Files + + + + + Moving the following files to trash can: + + + + + Delete Files + + + + + Deleting the following files + + + + + Create Symlinks + + + + + Creating symlinks for the following files: + + + + + Change Attributes + + + + + Changing attributes of the following files: + + + + + Restore Trashed Files + + + + + Restoring the following files from trash can: + + + + + Error + + + + + Fm::FilePropsDialog + + + View folder content + + + + + View and modify folder content + + + + + Read + + + + + Read and write + + + + + Forbidden + + + + + Files of different types + + + + + Multiple Files + + + + + Apply changes + + + + + Do you want to recursively apply these changes to all files and sub-folders? + + + + + Fm::FolderMenu + + + Create &New + + + + + &Paste + + + + + Select &All + + + + + Invert Selection + + + + + Sorting + + + + + Show Hidden + + + + + Folder Pr&operties + + + + + Folder + + + + + Blank File + + + + + By File Name + + + + + By Modification Time + + + + + By File Size + + + + + By File Type + + + + + By File Owner + + + + + Ascending + + + + + Descending + + + + + Folder First + + + + + Case Sensitive + + + + + Fm::FolderModel + + + Name + + + + + Type + + + + + Size + + + + + Modified + + + + + Owner + + + + + Fm::FontButton + + + Bold + + + + + Italic + + + + + Fm::MountOperationPasswordDialog + + + &Connect + + + + + Fm::PlacesModel + + + Places + + + + + Desktop + + + + + Trash + + + + + Computer + + + + + Applications + + + + + Network + + + + + Devices + + + + + Bookmarks + + + + + Fm::PlacesView + + + Empty Trash + + + + + Rename + + + + + Delete + + + + + + Unmount + + + + + Mount + + + + + Eject + + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + + + + + Type: %1 +Modified: %2 + + + + + Type: %1 +Modified: %3 + + + + + &Overwrite + + + + + &Rename + + + + + Fm::SidePane + + + + Places + + + + + + Directory Tree + + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + + + + + Connect &anonymously + + + + + Connect as u&ser: + + + + + &Username: + + + + + &Password: + + + + + &Domain: + + + + + Forget password &immediately + + + + + Remember password until you &logout + + + + + Remember &forever + + + + + QObject + + + + + + Error + + + + + Rename File + + + + + Please enter a new name: + + + + + Please enter a new file name: + + + + + New text file + + + + + Please enter a new folder name: + + + + + New folder + + + + + Enter a name for the new %1: + + + + + Create File + + + + + RenameDialog + + + Confirm to replace files + + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + + + + + dest + + + + + with the following file? + + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + + + + + Apply this option to all existing files + + + + diff --git a/libfm-qt/translations/libfm-qt_zh_TW.ts b/libfm-qt/translations/libfm-qt_zh_TW.ts new file mode 100644 index 0000000..82f6e0c --- /dev/null +++ b/libfm-qt/translations/libfm-qt_zh_TW.ts @@ -0,0 +1,1043 @@ + + + + + AppChooserDialog + + + Choose an Application + 選擇一個應用程式 + + + + Installed Applications + 安裝的應用程式 + + + + Custom Command + 自訂指令 + + + + Command line to execute: + 要執行的命令列: + + + + Application name: + 應用程式名稱: + + + + <b>These special codes can be used in the command line:</b> +<ul> +<li><b>%f</b>: Represents a single file name</li> +<li><b>%F</b>: Represents multiple file names</li> +<li><b>%u</b>: Represents a single URI of the file</li> +<li><b>%U</b>: Represents multiple URIs</li> +</ul> + <b>這些特殊代號可以在指令列參數使用:</b> +<ul> +<li><b>%f</b>:代表單一檔案名稱</li> +<li><b>%F</b>:代表多個檔案名稱</li> +<li><b>%u</b>:代表單一檔案 URI</li> +<li><b>%U</b>:代表多個 URI</li> +</ul> + + + + Keep terminal window open after command execution + 執行指令後保持終端機視窗開啟 + + + + Execute in terminal emulator + 在終端機模擬器執行 + + + + Set selected application as default action of this file type + 將所選應用程式設定為此類型檔案的預設處理程式 + + + + EditBookmarksDialog + + + Edit Bookmarks + 編輯書籤 + + + + Name + 名稱 + + + + Location + 位置 + + + + &Add Item + 新增項目(&A) + + + + &Remove Item + 移除項目(&R) + + + + Use drag and drop to reorder the items + 使用拖放重新排序項目 + + + + ExecFileDialog + + + Execute file + 執行檔案 + + + + &Open + 開啟(&) + + + + E&xecute + 執行(&X) + + + + Execute in &Terminal + 在終端機內執行(&T) + + + + Cancel + 取消 + + + + FileOperationDialog + + + Destination: + 目的地: + + + + Processing: + 正在處理: + + + + Preparing... + 準備中... + + + + Progress + 進度 + + + + Time remaining: + 剩餘時間: + + + + FilePropsDialog + + + File Properties + 檔案屬性 + + + + General + 一般 + + + + Location: + 位置: + + + + File type: + 檔案類型: + + + + Mime type: + Mime 類型: + + + + File size: + 檔案大小: + + + + On-disk size: + 磁碟上大小: + + + + Last modified: + 最後修改: + + + + Link target: + 連結目標: + + + + Open With: + 開啟: + + + + Last accessed: + 最後存取: + + + + Permissions + 權限 + + + + Ownership + 所有權 + + + + + + Group: + 群組: + + + + + + Owner: + 擁有者: + + + + Access Control + 存取控制 + + + + + Other: + 其他: + + + + Make the file executable + 使檔案可執行 + + + + + + Read + 讀取 + + + + + + Write + 寫入 + + + + + + Execute + 執行 + + + + Sticky + + + + + SetUID + + + + + SetGID + + + + + Advanced Mode + 進階模式 + + + + Fm::AppChooserComboBox + + + Customize + 自訂 + + + + Fm::AppChooserDialog + + + Select an application to open "%1" files + 選取用來開啟「%1」檔案的應用程式 + + + + Fm::DirTreeModel + + + Loading... + 載入中... + + + + <No sub folders> + <沒有子資料夾> + + + + Fm::DndActionMenu + + + Copy here + 複製到這裡 + + + + Move here + 移動到這裡 + + + + Create symlink here + 建立符號連結到這裡 + + + + Cancel + 取消 + + + + Fm::EditBookmarksDialog + + + New bookmark + 新書籤 + + + + Fm::ExecFileDialog + + + This text file '%1' seems to be an executable script. +What do you want to do with it? + 這個文字檔 '%1' 似乎是可執行的 script。 +想要進行什麼操作? + + + + This file '%1' is executable. Do you want to execute it? + 這個檔案 '%1' 是可執行檔,是否想要執行? + + + + Fm::FileMenu + + + Open + 開啟 + + + OpenWith + 用其他程式開啟 + + + + Open With... + 用其他程式開啟... + + + + Other Applications + 其他應用程式 + + + + &Restore + 恢復(&R) + + + + Cut + 剪下 + + + + Copy + 複製 + + + + Paste + 貼上 + + + + + &Move to Trash + 移動到垃圾桶(&M) + + + + Output + 輸出 + + + + &Delete + 刪除(&D) + + + Delete + 刪除 + + + + Rename + 重新命名 + + + + Extract to... + 解壓縮到... + + + + Extract Here + 在此解壓縮 + + + + Compress + 壓縮 + + + + Properties + 屬性 + + + + Fm::FileOperation + + + Error + 錯誤 + + + + Some files cannot be moved to trash can because the underlying file systems don't support this operation. +Do you want to delete them instead? + 因為檔案系統不支援,有些檔案無法丟到垃圾桶 +是否直接刪除這些檔案? + + + + + Confirm + 確認 + + + + Do you want to delete the selected files? + 你確定要刪除選取的檔案嗎? + + + + Do you want to move the selected files to trash can? + 你確定要把選取的檔案移到垃圾桶嗎? + + + + Fm::FileOperationDialog + + + Move files + 移動檔案 + + + + Moving the following files to destination folder: + 正在移動下列檔案到目的資料夾: + + + + Copy Files + 複製檔案 + + + + Copying the following files to destination folder: + 正在複製下列檔案到目的資料夾: + + + + Trash Files + 將檔案丟到垃圾桶 + + + + Moving the following files to trash can: + 正在將下列檔案移動到垃圾桶: + + + + Delete Files + 刪除檔案 + + + + Deleting the following files + 正在刪除下列檔案 + + + + Create Symlinks + 建立符號連結 + + + + Creating symlinks for the following files: + 正在建立下列檔案的符號連結: + + + + Change Attributes + 改變屬性 + + + + Changing attributes of the following files: + 正在更改下列檔案的屬性: + + + + Restore Trashed Files + 恢復被刪除的檔案 + + + + Restoring the following files from trash can: + 正在恢復下列被刪除的檔案 + + + + Error + 錯誤 + + + + Fm::FilePropsDialog + + + View folder content + 檢視資料夾內容 + + + + View and modify folder content + 檢視及修改資料夾內容 + + + + Read + 讀取 + + + + Read and write + 讀取及寫入 + + + + Forbidden + 禁止 + + + + Files of different types + 不同類型的檔案 + + + + Multiple Files + 多個檔案 + + + + Apply changes + 套用變更 + + + + Do you want to recursively apply these changes to all files and sub-folders? + 你是否想將這些變更套用到所有子資料夾和其內的檔案? + + + + Fm::FolderMenu + + + Create &New + 新建(&N) + + + + &Paste + 貼上(&P) + + + + Select &All + 全選(&A) + + + + Invert Selection + 反向選取 + + + + Sorting + 排序 + + + + Show Hidden + 顯示隱藏檔 + + + + Folder Pr&operties + 資料夾屬性(&O) + + + + Folder + 資料夾 + + + File + 檔案 + + + + Blank File + 空白檔案 + + + + By File Name + 依照檔名 + + + + By Modification Time + 依照修改時間 + + + + By File Size + 依照檔案大小 + + + + By File Type + 依照檔案型態 + + + + By File Owner + 依照檔案所有者 + + + + Ascending + 升冪排列 + + + + Descending + 降冪排列 + + + + Folder First + 資料夾優先 + + + + Case Sensitive + 區分大小寫 + + + + Fm::FolderModel + + + Name + 名稱 + + + + Type + 類型 + + + + Size + 大小 + + + + Modified + 修改 + + + + Owner + 所有者 + + + + Fm::FontButton + + + Bold + 粗體 + + + + Italic + 斜體 + + + + Fm::MountOperationPasswordDialog + + + &Connect + 連接(&C) + + + + Fm::PlacesModel + + + Places + 位置 + + + + Desktop + 桌面 + + + + Trash + 垃圾桶 + + + + Computer + 電腦 + + + + Applications + 應用程式 + + + + Network + 網路 + + + + Devices + 裝置 + + + + Bookmarks + 書籤 + + + + Fm::PlacesView + + + Empty Trash + 清空垃圾桶 + + + + Rename + 重新命名 + + + + Delete + 刪除 + + + + + Unmount + 卸載 + + + + Mount + 掛載 + + + + Eject + 退出 + + + + Fm::RenameDialog + + + + Type: %1 +Size: %2 +Modified: %3 + 類型: %1 +大小: %2 +最後修改: %3 + + + + Type: %1 +Modified: %2 + 類型: %1 +最後修改: %2 + + + + Type: %1 +Modified: %3 + 類型: %1 +最後修改: %3 + + + + &Overwrite + 覆蓋(&O) + + + + &Rename + 重新命名(&R) + + + + Fm::SidePane + + + + Places + 位置 + + + + + Directory Tree + 目錄樹 + + + + Shows list of common places, devices, and bookmarks in sidebar + + + + + Shows tree of directories in sidebar + + + + + MountOperationPasswordDialog + + + Mount + 掛載 + + + + Connect &anonymously + 匿名連線(&A) + + + + Connect as u&ser: + 以使用者帳號連線(&S): + + + + &Username: + 使用者名稱(&U): + + + + &Password: + 密碼(&P): + + + + &Domain: + + + + + Forget password &immediately + 立刻忘記密碼(&I) + + + + Remember password until you &logout + 記住密碼直到登出(&L) + + + + Remember &forever + 永遠記住密碼(&F) + + + + QObject + + + + + + Error + 錯誤 + + + + Rename File + 重新命名 + + + + Please enter a new name: + 請輸入一個新名稱: + + + + Please enter a new file name: + 請輸入一個新檔名: + + + + Please enter a new folder name: + 請輸入一個新資料夾名稱: + + + + New folder + 新資料夾 + + + + New text file + 新文字檔 + + + + Enter a name for the new %1: + 幫新的 %1 輸入一個名稱: + + + + Create File + 建立檔案 + + + + RenameDialog + + + Confirm to replace files + 確認取代檔案 + + + + <html><head/><body><p><span style=" font-weight:600;">There is already a file with the same name in this location.</span></p><p>Do you want to replace the existing file?</p></body></html> + + + + + dest + + + + + with the following file? + + + + + src file info + + + + + dest file info + + + + + src + + + + + &File name: + 檔名(&F): + + + + Apply this option to all existing files + 套用這個選項到所有已存在的檔案 + + + diff --git a/libfm-qt/utilities.cpp b/libfm-qt/utilities.cpp new file mode 100644 index 0000000..59e634f --- /dev/null +++ b/libfm-qt/utilities.cpp @@ -0,0 +1,304 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "utilities.h" +#include "utilities_p.h" +#include +#include +#include +#include +#include +#include +#include +#include "fileoperation.h" +#include + +#include +#include +#include +#include + +using namespace Fm; + +namespace Fm { + +FmPathList* pathListFromQUrls(QList urls) { + QList::const_iterator it; + FmPathList* pathList = fm_path_list_new(); + + for(it = urls.begin(); it != urls.end(); ++it) { + QUrl url = *it; + FmPath* path = fm_path_new_for_uri(url.toString().toUtf8()); + fm_path_list_push_tail(pathList, path); + fm_path_unref(path); + } + + return pathList; +} + +void pasteFilesFromClipboard(FmPath* destPath, QWidget* parent) { + QClipboard* clipboard = QApplication::clipboard(); + const QMimeData* data = clipboard->mimeData(); + bool isCut = false; + FmPathList* paths = NULL; + + if(data->hasFormat("x-special/gnome-copied-files")) { + // Gnome, LXDE, and XFCE + QByteArray gnomeData = data->data("x-special/gnome-copied-files"); + char* pdata = gnomeData.data(); + char* eol = strchr(pdata, '\n'); + + if(eol) { + *eol = '\0'; + isCut = (strcmp(pdata, "cut") == 0 ? true : false); + paths = fm_path_list_new_from_uri_list(eol + 1); + } + } + + if(!paths && data->hasUrls()) { + // The KDE way + paths = Fm::pathListFromQUrls(data->urls()); + QByteArray cut = data->data("x-kde-cut-selection"); + + if(!cut.isEmpty() && cut.at(0) == '1') + isCut = true; + } + + if(paths) { + if(isCut) + FileOperation::moveFiles(paths, destPath, parent); + else + FileOperation::copyFiles(paths, destPath, parent); + + fm_path_list_unref(paths); + } +} + +void copyFilesToClipboard(FmPathList* files) { + QClipboard* clipboard = QApplication::clipboard(); + QMimeData* data = new QMimeData(); + char* urilist = fm_path_list_to_uri_list(files); + // Gnome, LXDE, and XFCE + data->setData("x-special/gnome-copied-files", (QString("copy\n") + urilist).toUtf8()); + // The KDE way + data->setData("text/uri-list", urilist); + // data.setData("x-kde-cut-selection", "0"); + g_free(urilist); + clipboard->setMimeData(data); +} + +void cutFilesToClipboard(FmPathList* files) { + QClipboard* clipboard = QApplication::clipboard(); + QMimeData* data = new QMimeData(); + char* urilist = fm_path_list_to_uri_list(files); + // Gnome, LXDE, and XFCE + data->setData("x-special/gnome-copied-files", (QString("cut\n") + urilist).toUtf8()); + // The KDE way + data->setData("text/uri-list", urilist); + data->setData("x-kde-cut-selection", "1"); + g_free(urilist); + clipboard->setMimeData(data); +} + +void renameFile(FmFileInfo *file, QWidget *parent) { + FmPath* path = fm_file_info_get_path(file); + FilenameDialog dlg(parent); + dlg.setWindowTitle(QObject::tr("Rename File")); + dlg.setLabelText(QObject::tr("Please enter a new name:")); + // FIXME: what's the best way to handle non-UTF8 filename encoding here? + QString old_name = QString::fromLocal8Bit(fm_path_get_basename(path)); + dlg.setTextValue(old_name); + + if(fm_file_info_is_dir(file)) // select filename extension for directories + dlg.setSelectExtension(true); + + if(dlg.exec() != QDialog::Accepted) + return; + + QString new_name = dlg.textValue(); + + if(new_name == old_name) + return; + + GFile* gf = fm_path_to_gfile(path); + GFile* parent_gf = g_file_get_parent(gf); + GFile* dest = g_file_get_child(G_FILE(parent_gf), new_name.toLocal8Bit().data()); + g_object_unref(parent_gf); + + GError* err = NULL; + if(!g_file_move(gf, dest, + GFileCopyFlags(G_FILE_COPY_ALL_METADATA | + G_FILE_COPY_NO_FALLBACK_FOR_MOVE | + G_FILE_COPY_NOFOLLOW_SYMLINKS), + NULL, /* make this cancellable later. */ + NULL, NULL, &err)) { + QMessageBox::critical(parent, QObject::tr("Error"), err->message); + g_error_free(err); + } + + g_object_unref(dest); + g_object_unref(gf); +} + +// templateFile is a file path used as a template of the new file. +void createFile(CreateFileType type, FmPath* parentDir, FmTemplate* templ, QWidget* parent) { + QString defaultNewName; + QString prompt; + + switch(type) { + case CreateNewTextFile: + prompt = QObject::tr("Please enter a new file name:"); + defaultNewName = QObject::tr("New text file"); + break; + + case CreateNewFolder: + prompt = QObject::tr("Please enter a new folder name:"); + defaultNewName = QObject::tr("New folder"); + break; + + case CreateWithTemplate: { + FmMimeType* mime = fm_template_get_mime_type(templ); + prompt = QObject::tr("Enter a name for the new %1:").arg(QString::fromUtf8(fm_mime_type_get_desc(mime))); + defaultNewName = QString::fromUtf8(fm_template_get_name(templ, NULL)); + } + break; + } + +_retry: + // ask the user to input a file name + bool ok; + QString new_name = QInputDialog::getText(parent, QObject::tr("Create File"), + prompt, + QLineEdit::Normal, + defaultNewName, + &ok); + + if(!ok) + return; + + GFile* parent_gf = fm_path_to_gfile(parentDir); + GFile* dest_gf = g_file_get_child(G_FILE(parent_gf), new_name.toLocal8Bit().data()); + g_object_unref(parent_gf); + + GError* err = NULL; + switch(type) { + case CreateNewTextFile: { + GFileOutputStream* f = g_file_create(dest_gf, G_FILE_CREATE_NONE, NULL, &err); + if(f) { + g_output_stream_close(G_OUTPUT_STREAM(f), NULL, NULL); + g_object_unref(f); + } + break; + } + case CreateNewFolder: + g_file_make_directory(dest_gf, NULL, &err); + break; + case CreateWithTemplate: + fm_template_create_file(templ, dest_gf, &err, false); + break; + } + g_object_unref(dest_gf); + + if(err) { + if(err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS) { + g_error_free(err); + err = NULL; + goto _retry; + } + + QMessageBox::critical(parent, QObject::tr("Error"), err->message); + g_error_free(err); + } +} + +uid_t uidFromName(QString name) { + uid_t ret; + + if(name.at(0).digitValue() != -1) { + ret = uid_t(name.toUInt()); + } + else { + struct passwd* pw = getpwnam(name.toLatin1()); + // FIXME: use getpwnam_r instead later to make it reentrant + ret = pw ? pw->pw_uid : -1; + } + + return ret; +} + +QString uidToName(uid_t uid) { + QString ret; + struct passwd* pw = getpwuid(uid); + + if(pw) + ret = pw->pw_name; + + return ret; +} + +gid_t gidFromName(QString name) { + gid_t ret; + + if(name.at(0).digitValue() != -1) { + ret = gid_t(name.toUInt()); + } + else { + // FIXME: use getgrnam_r instead later to make it reentrant + struct group* grp = getgrnam(name.toLatin1()); + ret = grp ? grp->gr_gid : -1; + } + + return ret; +} + +QString gidToName(gid_t gid) { + QString ret; + struct group* grp = getgrgid(gid); + + if(grp) + ret = grp->gr_name; + + return ret; +} + +int execModelessDialog(QDialog* dlg) { + // FIXME: this does much less than QDialog::exec(). Will this work flawlessly? + QEventLoop loop; + QObject::connect(dlg, &QDialog::finished, &loop, &QEventLoop::quit); + // DialogExec does not seem to be documented in the Qt API doc? + // However, in the source code of QDialog::exec(), it's used so let's use it too. + dlg->show(); + (void)loop.exec(QEventLoop::DialogExec); + return dlg->result(); +} + +// check if GVFS can support this uri scheme (lower case) +bool isUriSchemeSupported(const char* uriScheme) { + const gchar * const * schemes = g_vfs_get_supported_uri_schemes(g_vfs_get_default()); + if(Q_UNLIKELY(schemes == NULL)) + return false; + for(const gchar * const * scheme = schemes; *scheme; ++scheme) + if(strcmp(uriScheme, *scheme) == 0) + return true; + return false; +} + + +}; diff --git a/libfm-qt/utilities.h b/libfm-qt/utilities.h new file mode 100644 index 0000000..0322252 --- /dev/null +++ b/libfm-qt/utilities.h @@ -0,0 +1,67 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_UTILITIES_H +#define FM_UTILITIES_H + +#include "libfmqtglobals.h" +#include +#include +#include +#include +#include + +class QDialog; + +namespace Fm { + +LIBFM_QT_API FmPathList* pathListFromQUrls(QList urls); + +LIBFM_QT_API void pasteFilesFromClipboard(FmPath* destPath, QWidget* parent = 0); + +LIBFM_QT_API void copyFilesToClipboard(FmPathList* files); + +LIBFM_QT_API void cutFilesToClipboard(FmPathList* files); + +LIBFM_QT_API void renameFile(FmFileInfo* file, QWidget* parent = 0); + +enum CreateFileType { + CreateNewFolder, + CreateNewTextFile, + CreateWithTemplate +}; + +LIBFM_QT_API void createFile(CreateFileType type, FmPath* parentDir, FmTemplate* templ = NULL, QWidget* parent = 0); + +LIBFM_QT_API uid_t uidFromName(QString name); + +LIBFM_QT_API QString uidToName(uid_t uid); + +LIBFM_QT_API gid_t gidFromName(QString name); + +LIBFM_QT_API QString gidToName(gid_t gid); + +LIBFM_QT_API int execModelessDialog(QDialog* dlg); + +LIBFM_QT_API bool isUriSchemeSupported(const char* uriScheme); + +} + +#endif // FM_UTILITIES_H diff --git a/libfm-qt/utilities_p.h b/libfm-qt/utilities_p.h new file mode 100644 index 0000000..630e2e6 --- /dev/null +++ b/libfm-qt/utilities_p.h @@ -0,0 +1,79 @@ +/* + + Copyright (C) 2014 Hong Jen Yee (PCMan) + + 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 __UTILITS_P_H__ +#define __UTILITS_P_H__ + +#include +#include +#include + +namespace Fm { + +// private class used in internal implementation +class FilenameDialog : public QInputDialog { + Q_OBJECT +public: + FilenameDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0): + QInputDialog(parent, flags), + selectExtension_(false) { + } + + virtual void showEvent(QShowEvent * event) { + QWidget::showEvent(event); + if(!selectExtension_) // dot not select filename extension + QTimer::singleShot(0, this, SLOT(initSelection())); + } + + bool selectExtension() const { + return selectExtension_; + } + + void setSelectExtension(bool value) { + selectExtension_ = value; + } + +private Q_SLOTS: + // do not select filename extensions + void initSelection() { + // find the QLineEdit child widget + QLineEdit* lineEdit = findChild(); + if(lineEdit) { + QString filename = lineEdit->text(); + if(!filename.isEmpty()) { + // only select filename part without extension name. + int ext = filename.lastIndexOf('.'); + if(ext != -1) { + // add special cases for tar.gz, tar.bz2, and other tar.* files + if(filename.leftRef(ext).endsWith(".tar")) + ext -= 4; + // FIXME: should we also handle other special cases? + lineEdit->setSelection(0, ext); + } + } + } + } + +private: + bool selectExtension_; +}; + +} // namespace Fm + +#endif diff --git a/pcmanfm-qt.1.in b/pcmanfm-qt.1.in new file mode 100644 index 0000000..6cd499e --- /dev/null +++ b/pcmanfm-qt.1.in @@ -0,0 +1,51 @@ +.TH PCManFM-Qt "1" "September 2014" "@CMAKE_PROJECT_NAME@ @PCMANFM_QT_VERSION@" "User Commands" +.SH NAME +PCManFM-Qt \- A lightweight Qt based file manager for X Window. +.SH SYNOPSIS +pcmanfm\-qt [OPTION...] [FILE1, FILE2,...] +.SH DESCRIPTION +PCMan File Manager Qt (\fBPCManFM-Qt\fP) is an extremly fast, lightweight, yet +feature-rich file manager with tabbed browsing. It is the default file manager +for the lightweight desktop environment, \fBLXQt\fP. +.SH OPTIONS +.SS "Help Options:" +.TP +\fB\-h\fR, \fB\-\-help\fR +Show help options +.SS "Application Options:" +.TP +\fB\-p\fR, \fB\-\-profile\fR=\fI\,PROFILE\/\fR +Name of configuration profile +.TP +\fB\-d\fR, \fB\-\-daemon\-mode\fR +Run PCManFM as a daemon +.TP +\fB\-\-quit\fR +Quit PCManFM +.TP +\fB\-\-desktop\fR +Launch desktop manager +.TP +\fB\-\-desktop\-off\fR +Turn off desktop manager if it's running +.TP +\fB\-\-desktop\-pref\fR=\fI\,NAME\/\fR +Open desktop preference dialog on the page with the specified name +.TP +\fB\-w\fR, \fB\-\-set\-wallpaper\fR=\fI\,FILE\/\fR +Set desktop wallpaper from image FILE +.TP +\fB\-\-wallpaper\-mode\fR=\fI\,MODE\/\fR +Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) +.TP +\fB\-\-show\-pref\fR=\fI\,NAME\/\fR +Open Preferences dialog on the page with the specified name +.TP +\fB\-n\fR, \fB\-\-new\-window\fR +Open new window +.TP +\fB\-f\fR, \fB\-\-find\-files\fR +Open Find Files utility +.SH "AUTHORS" +.B pcmanfm-qt +was primarily written by Hong Jen Yee (PCMan) . diff --git a/pcmanfm-qt.kdev4 b/pcmanfm-qt.kdev4 new file mode 100644 index 0000000..4588e29 --- /dev/null +++ b/pcmanfm-qt.kdev4 @@ -0,0 +1,4 @@ +[Project] +Manager=KDevCMakeManager +Name=pcmanfm-qt +VersionControl= diff --git a/pcmanfm/CMakeLists.txt b/pcmanfm/CMakeLists.txt new file mode 100644 index 0000000..3f657a1 --- /dev/null +++ b/pcmanfm/CMakeLists.txt @@ -0,0 +1,99 @@ +set(LIBFM_LIBRARY "fm-qt5") +set(QTX_INCLUDE_DIRS "") +set(QTX_LIBRARIES Qt5::Widgets Qt5::DBus Qt5::X11Extras) + +include_directories( + ${QTX_INCLUDE_DIRS} + ${LIBFM_INCLUDE_DIRS} + ${LIBMENUCACHE_INCLUDE_DIRS} + ${SYSTEM_LIBS_INCLUDE_DIRS} + "${CMAKE_CURRENT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/libfm-qt" +) + +link_directories( + ${LIBFM_LIBRARY_DIRS} + ${LIBMENUCACHE_LIBRARY_DIRS} + ${SYSTEM_LIBS_LIBRARY_DIRS} +) + +set(pcmanfm_SRCS + application.cpp + pcmanfm.cpp + mainwindow.cpp + tabpage.cpp + tabbar.cpp + view.cpp + launcher.cpp + preferencesdialog.cpp + desktoppreferencesdialog.cpp + desktopwindow.cpp + desktopitemdelegate.cpp + autorundialog.cpp + settings.cpp +) + +qt5_add_dbus_adaptor(pcmanfm_SRCS + org.pcmanfm.Application.xml + application.h + PCManFM::Application + applicationadaptor + ApplicationAdaptor +) + +set(pcmanfm_UIS + main-win.ui + about.ui + preferences.ui + desktop-preferences.ui + autorun.ui +) + +qt5_wrap_ui(pcmanfm_UIS_H ${pcmanfm_UIS}) + +add_executable(pcmanfm-qt + ${pcmanfm_SRCS} + ${pcmanfm_UIS_H} +) +set_property( + TARGET pcmanfm-qt APPEND + PROPERTY COMPILE_DEFINITIONS + LIBFM_QT_API=Q_DECL_IMPORT + PCMANFM_DATA_DIR="${CMAKE_INSTALL_PREFIX}/share/pcmanfm-qt" + LIBFM_DATA_DIR="${LIBFM_PREFIX}/share/libfm" # This is a little bit dirty + PCMANFM_QT_VERSION="${PCMANFM_QT_VERSION}" +) + +target_link_libraries(pcmanfm-qt + ${QTX_LIBRARIES} + ${LIBFM_LIBRARIES} + ${LIBMENUCACHE_LIBRARIES} + ${SYSTEM_LIBS_LIBRARIES} + ${LIBFM_LIBRARY} +) + +install(TARGETS pcmanfm-qt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +# install a desktop entry file for pcmanfm-qt and desktop preferences +configure_file(pcmanfm-qt.desktop.in pcmanfm-qt.desktop @ONLY) +configure_file(pcmanfm-qt-desktop-pref.desktop.in pcmanfm-qt-desktop-pref.desktop @ONLY) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/pcmanfm-qt.desktop" + "${CMAKE_CURRENT_BINARY_DIR}/pcmanfm-qt-desktop-pref.desktop" + DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" +) + +# add translation for pcmanfm-qt +# See http://www.cmake.org/Wiki/CMake:How_To_Build_Qt4_Software +file(GLOB TS_FILES translations/*.ts) + +qt5_create_translation(QM_FILES ${pcmanfm_SRCS} ${pcmanfm_UIS_H} ${TS_FILES}) +qt5_add_translation(QM_FILES ${TS_FILES}) + +add_custom_target(pcmanfm_translations DEPENDS ${QM_FILES}) +install(FILES ${QM_FILES} DESTINATION "${CMAKE_INSTALL_DATADIR}/pcmanfm-qt/translations") + +# prevent the generated files from being deleted during make clean +set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM true) + +qt5_use_modules(pcmanfm-qt Widgets DBus) diff --git a/pcmanfm/about.ui b/pcmanfm/about.ui new file mode 100644 index 0000000..c844417 --- /dev/null +++ b/pcmanfm/about.ui @@ -0,0 +1,180 @@ + + + AboutDialog + + + + 0 + 0 + 430 + 325 + + + + About + + + + + + + + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + + Qt::AlignCenter + + + + + + + Lightweight file manager + + + Qt::AlignCenter + + + + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + 0 + + + false + + + + Authors + + + + + + true + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + false + + + + + + + + License + + + + + + true + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/pcmanfm/application.cpp b/pcmanfm/application.cpp new file mode 100644 index 0000000..66a495a --- /dev/null +++ b/pcmanfm/application.cpp @@ -0,0 +1,708 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "application.h" +#include "mainwindow.h" +#include "desktopwindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "applicationadaptor.h" +#include "preferencesdialog.h" +#include "desktoppreferencesdialog.h" +#include "mountoperation.h" +#include "autorundialog.h" +#include "launcher.h" + +#include +#include + +#include + +using namespace PCManFM; +static const char* serviceName = "org.pcmanfm.PCManFM"; +static const char* ifaceName = "org.pcmanfm.Application"; + +int ProxyStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const { + Application* app = static_cast(qApp); + if(hint == QStyle::SH_ItemView_ActivateItemOnSingleClick) + return app->settings().singleClick(); + return QProxyStyle::styleHint(hint, option, widget, returnData); +} + +Application::Application(int& argc, char** argv): + QApplication(argc, argv), + libFm_(), + settings_(), + profileName_("default"), + daemonMode_(false), + desktopWindows_(), + enableDesktopManager_(false), + preferencesDialog_(), + volumeMonitor_(NULL), + editBookmarksialog_() { + + argc_ = argc; + argv_ = argv; + + // QDBusConnection::sessionBus().registerObject("/org/pcmanfm/Application", this); + QDBusConnection dbus = QDBusConnection::sessionBus(); + if(dbus.registerService(serviceName)) { + // we successfully registered the service + isPrimaryInstance = true; + setStyle(new ProxyStyle()); + desktop()->installEventFilter(this); + + new ApplicationAdaptor(this); + dbus.registerObject("/Application", this); + + connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit); + settings_.load(profileName_); + + // decrease the cache size to reduce memory usage + QPixmapCache::setCacheLimit(2048); + + if(settings_.useFallbackIconTheme()) { + QIcon::setThemeName(settings_.fallbackIconThemeName()); + Fm::IconTheme::checkChanged(); + } + } + else { + // an service of the same name is already registered. + // we're not the first instance + isPrimaryInstance = false; + } +} + +Application::~Application() { + desktop()->removeEventFilter(this); + + if(volumeMonitor_) { + g_signal_handlers_disconnect_by_func(volumeMonitor_, gpointer(onVolumeAdded), this); + g_object_unref(volumeMonitor_); + } + + if(enableDesktopManager_) + removeNativeEventFilter(this); +} + +bool Application::parseCommandLineArgs() { + bool keepRunning = false; + QCommandLineParser parser; + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption profileOption(QStringList() << "p" << "profile", tr("Name of configuration profile"), tr("PROFILE")); + parser.addOption(profileOption); + + QCommandLineOption daemonOption(QStringList() << "d" << "daemon-mode", tr("Run PCManFM as a daemon")); + parser.addOption(daemonOption); + + QCommandLineOption quitOption(QStringList() << "q" << "quit", tr("Quit PCManFM")); + parser.addOption(quitOption); + + QCommandLineOption desktopOption("desktop", tr("Launch desktop manager")); + parser.addOption(desktopOption); + + QCommandLineOption desktopOffOption("desktop-off", tr("Turn off desktop manager if it's running")); + parser.addOption(desktopOffOption); + + QCommandLineOption desktopPrefOption("desktop-pref", tr("Open desktop preference dialog on the page with the specified name"), tr("NAME")); + parser.addOption(desktopPrefOption); + + QCommandLineOption newWindowOption(QStringList() << "n" << "new-window", tr("Open new window")); + parser.addOption(newWindowOption); + + QCommandLineOption findFilesOption(QStringList() << "f" << "find-files", tr("Open Find Files utility")); + parser.addOption(findFilesOption); + + QCommandLineOption setWallpaperOption(QStringList() << "w" << "set-wallpaper", tr("Set desktop wallpaper from image FILE"), tr("FILE")); + parser.addOption(setWallpaperOption); + + // don't translate list of modes in description, please + QCommandLineOption wallpaperModeOption("wallpaper-mode", tr("Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile)"), tr("MODE")); + parser.addOption(wallpaperModeOption); + + QCommandLineOption showPrefOption("show-pref", tr("Open Preferences dialog on the page with the specified name"), tr("NAME")); + parser.addOption(showPrefOption); + + parser.addPositionalArgument("files", tr("Files or directories to open"), tr("[FILE1, FILE2,...]")); + + parser.process(arguments()); + + if(isPrimaryInstance) { + qDebug("isPrimaryInstance"); + + if(parser.isSet(daemonOption)) + daemonMode_ = true; + if(parser.isSet(profileOption)) + profileName_ = parser.value(profileOption); + + // load settings + settings_.load(profileName_); + + // desktop icon management + if(parser.isSet(desktopOption)) { + desktopManager(true); + keepRunning = true; + } + else if(parser.isSet(desktopOffOption)) + desktopManager(false); + + if(parser.isSet(desktopPrefOption)) { // desktop preference dialog + desktopPrefrences(parser.value(desktopPrefOption)); + keepRunning = true; + } + else if(parser.isSet(findFilesOption)) { // file searching utility + findFiles(parser.positionalArguments()); + keepRunning = true; + } + else if(parser.isSet(showPrefOption)) { // preferences dialog + preferences(parser.value(showPrefOption)); + keepRunning = true; + } + else if(parser.isSet(setWallpaperOption) || parser.isSet(wallpaperModeOption)) // set wall paper + setWallpaper(parser.value(setWallpaperOption), parser.value(wallpaperModeOption)); + else { + if(!parser.isSet(desktopOption) && !parser.isSet(desktopOffOption)) { + QStringList paths = parser.positionalArguments(); + if(paths.isEmpty()) { + // if no path is specified and we're using daemon mode, + // don't open current working directory + if(!daemonMode_) + paths.push_back(QDir::currentPath()); + } + if(!paths.isEmpty()) + launchFiles(paths, parser.isSet(newWindowOption)); + keepRunning = true; + } + } + } + else { + QDBusConnection dbus = QDBusConnection::sessionBus(); + QDBusInterface iface(serviceName, "/Application", ifaceName, dbus, this); + if(parser.isSet(quitOption)) { + iface.call("quit"); + return false; + } + + if(parser.isSet(desktopOption)) + iface.call("desktopManager", true); + else if(parser.isSet(desktopOffOption)) + iface.call("desktopManager", false); + + if(parser.isSet(desktopPrefOption)) { // desktop preference dialog + iface.call("desktopPrefrences", parser.value(desktopPrefOption)); + } + else if(parser.isSet(findFilesOption)) { // file searching utility + iface.call("findFiles", parser.positionalArguments()); + } + else if(parser.isSet(showPrefOption)) { // preferences dialog + iface.call("preferences", parser.value(showPrefOption)); + } + else if(parser.isSet(setWallpaperOption) || parser.isSet(wallpaperModeOption)) { // set wall paper + iface.call("setWallpaper", parser.value(setWallpaperOption), parser.value(wallpaperModeOption)); + } + else { + if(!parser.isSet(desktopOption) && !parser.isSet(desktopOffOption)) { + QStringList paths = parser.positionalArguments(); + if(paths.isEmpty()) { + paths.push_back(QDir::currentPath()); + } + iface.call("launchFiles", paths, parser.isSet(newWindowOption)); + } + } + } + return keepRunning; +} + +void Application::init() { + + // install the translations built-into Qt itself + qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + installTranslator(&qtTranslator); + + // install libfm-qt translator + installTranslator(libFm_.translator()); + + // install our own tranlations + translator.load("pcmanfm-qt_" + QLocale::system().name(), PCMANFM_DATA_DIR "/translations"); + installTranslator(&translator); +} + +int Application::exec() { + + if(!parseCommandLineArgs()) + return 0; + + if(daemonMode_) // keep running even when there is no window opened. + setQuitOnLastWindowClosed(false); + + volumeMonitor_ = g_volume_monitor_get(); + // delay the volume manager a little because in newer versions of glib/gio there's a problem. + // when the first volume monitor object is created, it discovers volumes asynchonously. + // g_volume_monitor_get() immediately returns while the monitor is still discovering devices. + // So initially g_volume_monitor_get_volumes() returns nothing, but shortly after that + // we get volume-added signals for all of the volumes. This is not what we want. + // So, we wait for 3 seconds here to let it finish device discovery. + QTimer::singleShot(3000, this, SLOT(initVolumeManager())); + + return QCoreApplication::exec(); +} + +void Application::onAboutToQuit() { + qDebug("aboutToQuit"); + settings_.save(); +} + +bool Application::eventFilter(QObject* watched, QEvent* event) { + if(watched == desktop()) { + switch(event->type()) { + case QEvent::StyleChange: + case QEvent::ThemeChange: + setStyle(new ProxyStyle()); + }; + } + return QObject::eventFilter(watched, event); +} + +void Application::onLastWindowClosed() { + +} + +void Application::onSaveStateRequest(QSessionManager& manager) { + +} + +void Application::desktopManager(bool enabled) { + // TODO: turn on or turn off desktpo management (desktop icons & wallpaper) + qDebug("desktopManager: %d", enabled); + QDesktopWidget* desktopWidget = desktop(); + if(enabled) { + if(!enableDesktopManager_) { + installNativeEventFilter(this); + Q_FOREACH(QScreen* screen, screens()) { + connect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); + connect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); + } + connect(this, &QApplication::screenAdded, this, &Application::onScreenAdded); + connect(desktopWidget, &QDesktopWidget::resized, this, &Application::onScreenResized); + connect(desktopWidget, &QDesktopWidget::screenCountChanged, this, &Application::onScreenCountChanged); + + // NOTE: there are two modes + // When virtual desktop is used (all screens are combined to form a large virtual desktop), + // we only create one DesktopWindow. Otherwise, we create one for each screen. + if(desktopWidget->isVirtualDesktop()) { + DesktopWindow* window = createDesktopWindow(-1); + desktopWindows_.push_back(window); + } + else { + int n = desktopWidget->numScreens(); + desktopWindows_.reserve(n); + for(int i = 0; i < n; ++i) { + DesktopWindow* window = createDesktopWindow(i); + desktopWindows_.push_back(window); + } + } + } + } + else { + if(enableDesktopManager_) { + disconnect(desktopWidget, &QDesktopWidget::resized, this, &Application::onScreenResized); + disconnect(desktopWidget, &QDesktopWidget::screenCountChanged, this, &Application::onScreenCountChanged); + int n = desktopWindows_.size(); + for(int i = 0; i < n; ++i) { + DesktopWindow* window = desktopWindows_.at(i); + delete window; + } + desktopWindows_.clear(); + Q_FOREACH(QScreen* screen, screens()) { + disconnect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); + disconnect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); + } + disconnect(this, &QApplication::screenAdded, this, &Application::onScreenAdded); + removeNativeEventFilter(this); + } + } + enableDesktopManager_ = enabled; +} + +void Application::desktopPrefrences(QString page) { + // show desktop preference window + if(!desktopPreferencesDialog_) { + desktopPreferencesDialog_ = new DesktopPreferencesDialog(); + } + desktopPreferencesDialog_.data()->selectPage(page); + desktopPreferencesDialog_.data()->show(); + desktopPreferencesDialog_.data()->raise(); + desktopPreferencesDialog_.data()->activateWindow(); +} + +void Application::findFiles(QStringList paths) { + // TODO: add a file searching utility here. + qDebug("findFiles"); +} + +void Application::launchFiles(QStringList paths, bool inNewWindow) { + FmPathList* pathList = fm_path_list_new(); + QStringList::iterator it; + for(it = paths.begin(); it != paths.end(); ++it) { + QString& pathName = *it; + FmPath* path = fm_path_new_for_commandline_arg(pathName.toLocal8Bit().constData()); + fm_path_list_push_tail(pathList, path); + fm_path_unref(path); + } + Launcher(NULL).launchPaths(NULL, pathList); + fm_path_list_unref(pathList); +} + +void Application::openFolders(FmFileInfoList* files) { + Launcher(NULL).launchFiles(NULL, files); +} + +void Application::openFolderInTerminal(FmPath* path) { + if(!settings_.terminal().isEmpty()) { + char* cwd_str; + if(fm_path_is_native(path)) + cwd_str = fm_path_to_str(path); + else { // gio will map remote filesystems to local FUSE-mounted paths here. + GFile* gf = fm_path_to_gfile(path); + cwd_str = g_file_get_path(gf); + g_object_unref(gf); + } + GError* err = NULL; + if(!fm_terminal_launch(cwd_str, &err)) { + QMessageBox::critical(NULL, tr("Error"), QString::fromUtf8(err->message)); + g_error_free(err); + } + g_free(cwd_str); + } + else { + // show an error message and ask the user to set the command + QMessageBox::critical(NULL, tr("Error"), tr("Terminal emulator is not set.")); + preferences("advanced"); + } +} + +void Application::preferences(QString page) { + // open preference dialog + if(!preferencesDialog_) { + preferencesDialog_ = new PreferencesDialog(page); + } + else { + // TODO: set page + } + preferencesDialog_.data()->show(); + preferencesDialog_.data()->raise(); + preferencesDialog_.data()->activateWindow(); +} + +void Application::setWallpaper(QString path, QString modeString) { + static const char* valid_wallpaper_modes[] = {"color", "stretch", "fit", "center", "tile"}; + DesktopWindow::WallpaperMode mode = settings_.wallpaperMode(); + bool changed = false; + + if(!path.isEmpty() && path != settings_.wallpaper()) { + if(QFile(path).exists()) { + settings_.setWallpaper(path); + changed = true; + } + } + // convert mode string to value + for(int i = 0; i < G_N_ELEMENTS(valid_wallpaper_modes); ++i) { + if(modeString == valid_wallpaper_modes[i]) { + mode = (DesktopWindow::WallpaperMode)i; + if(mode != settings_.wallpaperMode()) + changed = true; + break; + } + } + // FIXME: support different wallpapers on different screen. + // update wallpaper + if(changed) { + if(enableDesktopManager_) { + Q_FOREACH(DesktopWindow * desktopWindow, desktopWindows_) { + if(!path.isEmpty()) + desktopWindow->setWallpaperFile(path); + if(mode != settings_.wallpaperMode()) + desktopWindow->setWallpaperMode(mode); + desktopWindow->updateWallpaper(); + } + settings_.save(); // save the settings to the config file + } + } +} + +void Application::onScreenResized(int num) { + if(desktop()->isVirtualDesktop()) { + // in virtual desktop mode, we only have one desktop window. that is the first one. + DesktopWindow* window = desktopWindows_.at(0); + window->setGeometry(desktop()->geometry()); + } + else { + DesktopWindow* window = desktopWindows_.at(num); + QRect rect = desktop()->screenGeometry(num); + window->setGeometry(rect); + } +} + +DesktopWindow* Application::createDesktopWindow(int screenNum) { + DesktopWindow* window = new DesktopWindow(screenNum); + if(screenNum == -1) { // one large virtual desktop only + QRect rect = desktop()->geometry(); + window->setGeometry(rect); + } + else { + QRect rect = desktop()->screenGeometry(screenNum); + window->setGeometry(rect); + } + window->updateFromSettings(settings_); + window->show(); + return window; +} + +void Application::onScreenCountChanged(int newCount) { + QDesktopWidget* desktopWidget = desktop(); + bool oldVirtual = (desktopWindows_.size() == 1 && desktopWindows_.at(0)->screenNum() == -1); + bool isVirtual = desktopWidget->isVirtualDesktop(); + + if(oldVirtual && isVirtual) { + // if we are using virtual desktop mode previously, and the new mode is sitll virtual + // no further change is needed, only do relayout. + desktopWindows_.at(0)->queueRelayout(); + return; + } + + // we used non-virtual mode originally, but now we're switched to virtual mode + if(isVirtual) + newCount = 1; // we only want one desktop window for all screens in virtual mode + + if(newCount > desktopWindows_.size()) { + // add more desktop windows + for(int i = desktopWindows_.size(); i < newCount; ++i) { + DesktopWindow* desktop = createDesktopWindow(i); + desktopWindows_.push_back(desktop); + } + } + else if(newCount < desktopWindows_.size()) { + // delete excessive desktop windows + for(int i = newCount; i < desktopWindows_.size(); ++i) { + DesktopWindow* desktop = desktopWindows_.at(i); + delete desktop; + } + desktopWindows_.resize(newCount); + } + + if(newCount == 1) { // now only 1 screen is in use + DesktopWindow* desktop = desktopWindows_.at(0); + if(isVirtual) + desktop->setScreenNum(-1); + else // non-virtual mode, and we only have 1 screen + desktop->setScreenNum(0); + desktop->updateWallpaper(); + } +} + +// called when Settings is changed to update UI +void Application::updateFromSettings() { + // if(iconTheme.isEmpty()) + // Fm::IconTheme::setThemeName(settings_.fallbackIconThemeName()); + + // update main windows and desktop windows + QWidgetList windows = this->topLevelWidgets(); + QWidgetList::iterator it; + for(it = windows.begin(); it != windows.end(); ++it) { + QWidget* window = *it; + if(window->inherits("PCManFM::MainWindow")) { + MainWindow* mainWindow = static_cast(window); + mainWindow->updateFromSettings(settings_); + } + } + if(desktopManagerEnabled()) + updateDesktopsFromSettings(); +} + +void Application::updateDesktopsFromSettings() { + QVector::iterator it; + for(it = desktopWindows_.begin(); it != desktopWindows_.end(); ++it) { + DesktopWindow* desktopWindow = static_cast(*it); + desktopWindow->updateFromSettings(settings_); + } +} + +void Application::editBookmarks() { + if(!editBookmarksialog_) { + FmBookmarks* bookmarks = fm_bookmarks_dup(); + editBookmarksialog_ = new Fm::EditBookmarksDialog(bookmarks); + g_object_unref(bookmarks); + } + editBookmarksialog_.data()->show(); +} + +void Application::initVolumeManager() { + + g_signal_connect(volumeMonitor_, "volume-added", G_CALLBACK(onVolumeAdded), this); + + if(settings_.mountOnStartup()) { + /* try to automount all volumes */ + GList* vols = g_volume_monitor_get_volumes(volumeMonitor_); + for(GList* l = vols; l; l = l->next) { + GVolume* volume = G_VOLUME(l->data); + if(g_volume_should_automount(volume)) + autoMountVolume(volume, false); + g_object_unref(volume); + } + g_list_free(vols); + } +} + +bool Application::autoMountVolume(GVolume* volume, bool interactive) { + if(!g_volume_should_automount(volume) || !g_volume_can_mount(volume)) + return FALSE; + + GMount* mount = g_volume_get_mount(volume); + if(!mount) { // not mounted, automount is needed + // try automount + Fm::MountOperation* op = new Fm::MountOperation(interactive); + op->mount(volume); + if(!op->wait()) + return false; + if(!interactive) + return true; + mount = g_volume_get_mount(volume); + } + + if(mount) { + if(interactive && settings_.autoRun()) { // show autorun dialog + AutoRunDialog* dlg = new AutoRunDialog(volume, mount); + dlg->show(); + } + g_object_unref(mount); + } + return true; +} + +// static +void Application::onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, Application* pThis) { + if(pThis->settings_.mountRemovable()) + pThis->autoMountVolume(volume, true); +} + +bool Application::nativeEventFilter(const QByteArray & eventType, void * message, long * result) { + if(eventType == "xcb_generic_event_t") { // XCB event + // filter all native X11 events (xcb) + xcb_generic_event_t* generic_event = reinterpret_cast(message); + // qDebug("XCB event: %d", generic_event->response_type & ~0x80); + Q_FOREACH(DesktopWindow * window, desktopWindows_) { + window->xcbEvent(generic_event); + } + } + return false; +} + +void Application::onScreenAdded(QScreen* newScreen) { + if(enableDesktopManager_) { + connect(newScreen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); + connect(newScreen, &QObject::destroyed, this, &Application::onScreenDestroyed); + } +} + +void Application::onScreenDestroyed(QObject* screenObj) { + // NOTE by PCMan: This is a workaround for Qt 5 bug #40681. + // With this very dirty workaround, we can fix lxde/lxde-qt bug #204, #205, and #206. + // Qt 5 has two new regression bugs which breaks lxqt-panel in a multihead environment. + // #40681: Regression bug: QWidget::winId() returns old value and QEvent::WinIdChange event is not emitted sometimes. (multihead setup) + // #40791: Regression: QPlatformWindow, QWindow, and QWidget::winId() are out of sync. + // Explanations for the workaround: + // Internally, Qt mantains a list of QScreens and update it when XRandR configuration changes. + // When the user turn off an monitor with xrandr --output --off, this will destroy the QScreen + // object which represent the output. If the QScreen being destroyed contains our panel widget, + // Qt will call QWindow::setScreen(0) on the internal windowHandle() of our panel widget to move it + // to the primary screen. However, moving a window to a different screen is more than just changing + // its position. With XRandR, all screens are actually part of the same virtual desktop. However, + // this is not the case in other setups, such as Xinerama and moving a window to another screen is + // not possible unless you destroy the widget and create it again for a new screen. + // Therefore, Qt destroy the widget and re-create it when moving our panel to a new screen. + // Unfortunately, destroying the window also destroy the child windows embedded into it, + // using XEMBED such as the tray icons. (#206) + // Second, when the window is re-created, the winId of the QWidget is changed, but Qt failed to + // generate QEvent::WinIdChange event so we have no way to know that. We have to set + // some X11 window properties using the native winId() to make it a dock, but this stop working + // because we cannot get the correct winId(), so this causes #204 and #205. + // + // The workaround is very simple. Just completely destroy the window before Qt has a chance to do + // QWindow::setScreen() for it. Later, we recreate the window ourselves. So this can bypassing the Qt bugs. + QScreen* screen = static_cast(screenObj); + if(enableDesktopManager_) { + bool reloadNeeded = false; + // FIXME: add workarounds for Qt5 bug #40681 and #40791 here. + Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + if(desktop->windowHandle()->screen() == screenObj) { + desktop->destroy(); // destroy the underlying native window + reloadNeeded = true; + } + } + if(reloadNeeded) + QTimer::singleShot(0, this, SLOT(reloadDesktopsAsNeeded())); + } +} + +void Application::reloadDesktopsAsNeeded() { + if(enableDesktopManager_) { + // workarounds for Qt5 bug #40681 and #40791 here. + Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + if(!desktop->windowHandle()) { + desktop->create(); // re-create the underlying native window + desktop->queueRelayout(); + desktop->show(); + } + } + } +} + +// This slot is for Qt 5 onlt, but the stupid Qt moc cannot do conditional compilation +// so we have to define it for Qt 4 as well. +void Application::onVirtualGeometryChanged(const QRect& rect) { + // NOTE: the following is a workaround for Qt bug 32567. + // https://bugreports.qt-project.org/browse/QTBUG-32567 + // Though the status of the bug report is closed, it's not yet fixed for X11. + // In theory, QDesktopWidget should emit "workAreaResized()" signal when the work area + // of any screen is changed, but in fact it does not do it. + // However, QScreen provided since Qt5 does not have the bug and + // virtualGeometryChanged() is emitted correctly when the workAreas changed. + // So we use it in Qt5. + if(enableDesktopManager_) { + QScreen* screeb = static_cast(sender()); + // qDebug() << "onVirtualGeometryChanged"; + Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + desktop->queueRelayout(); + } + } +} diff --git a/pcmanfm/application.h b/pcmanfm/application.h new file mode 100644 index 0000000..766ba18 --- /dev/null +++ b/pcmanfm/application.h @@ -0,0 +1,138 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_APPLICATION_H +#define PCMANFM_APPLICATION_H + +#include +#include "settings.h" +#include "libfmqt.h" +#include "editbookmarksdialog.h" +#include +#include +#include +#include +#include +#include + + +class QScreen; + +namespace PCManFM { + +class DesktopWindow; +class PreferencesDialog; +class DesktopPreferencesDialog; + +class ProxyStyle: public QProxyStyle { + Q_OBJECT +public: + ProxyStyle() : QProxyStyle() {} + virtual ~ProxyStyle() {} + virtual int styleHint(StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0) const; +}; + +class Application : public QApplication, public QAbstractNativeEventFilter { + Q_OBJECT + Q_PROPERTY(bool desktopManagerEnabled READ desktopManagerEnabled) + +public: + Application(int& argc, char** argv); + virtual ~Application(); + + void init(); + int exec(); + + Settings& settings() { + return settings_; + } + + Fm::LibFmQt& libFm() { + return libFm_; + } + + // public interface exported via dbus + void launchFiles(QStringList paths, bool inNewWindow); + void setWallpaper(QString path, QString modeString); + void preferences(QString page); + void desktopPrefrences(QString page); + void editBookmarks(); + void desktopManager(bool enabled); + void findFiles(QStringList paths); + + bool desktopManagerEnabled() { + return enableDesktopManager_; + } + + void updateFromSettings(); + void updateDesktopsFromSettings(); + + void openFolderInTerminal(FmPath* path); + void openFolders(FmFileInfoList* files); + + QString profileName() { + return profileName_; + } + + virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result); + +protected Q_SLOTS: + void onAboutToQuit(); + + void onLastWindowClosed(); + void onSaveStateRequest(QSessionManager & manager); + void onScreenResized(int num); + void onScreenCountChanged(int newCount); + void initVolumeManager(); + + void onVirtualGeometryChanged(const QRect& rect); + void onScreenDestroyed(QObject* screenObj); + void onScreenAdded(QScreen* newScreen); + void reloadDesktopsAsNeeded(); + +protected: + virtual bool eventFilter(QObject* watched, QEvent* event); + bool parseCommandLineArgs(); + DesktopWindow* createDesktopWindow(int screenNum); + bool autoMountVolume(GVolume* volume, bool interactive = true); + + static void onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, Application* pThis); + +private: + bool isPrimaryInstance; + Fm::LibFmQt libFm_; + Settings settings_; + QString profileName_; + bool daemonMode_; + bool enableDesktopManager_; + QVector desktopWindows_; + QPointer preferencesDialog_; + QPointer desktopPreferencesDialog_; + QPointer editBookmarksialog_; + QTranslator translator; + QTranslator qtTranslator; + GVolumeMonitor* volumeMonitor_; + int argc_; + char** argv_; +}; + +} + +#endif // PCMANFM_APPLICATION_H diff --git a/pcmanfm/autorun.ui b/pcmanfm/autorun.ui new file mode 100644 index 0000000..e59a48a --- /dev/null +++ b/pcmanfm/autorun.ui @@ -0,0 +1,117 @@ + + + AutoRunDialog + + + + 0 + 0 + 334 + 312 + + + + Removable medium is inserted + + + + ../../../.designer/backup../../../.designer/backup + + + + + + + + + + + + + + + <b>Removable medium is inserted</b> + + + + + + + Type of medium: + + + + + + + Detecting... + + + + + + + + + Please select the action you want to perform: + + + + + + + + 0 + 1 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AutoRunDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AutoRunDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/pcmanfm/autorundialog.cpp b/pcmanfm/autorundialog.cpp new file mode 100644 index 0000000..1799653 --- /dev/null +++ b/pcmanfm/autorundialog.cpp @@ -0,0 +1,137 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "autorundialog.h" +#include "icontheme.h" +#include +#include "application.h" +#include "mainwindow.h" + +using namespace PCManFM; + +AutoRunDialog::AutoRunDialog(GVolume* volume, GMount* mount, QWidget* parent, Qt::WindowFlags f): + cancellable(g_cancellable_new()), + applications(NULL), + mount_(G_MOUNT(g_object_ref(mount))), + QDialog(parent, f) { + + setAttribute(Qt::WA_DeleteOnClose); + ui.setupUi(this); + + GIcon* gicon = g_volume_get_icon(volume); + QIcon icon = Fm::IconTheme::icon(gicon); + ui.icon->setPixmap(icon.pixmap(QSize(48, 48))); + + // add actions + QListWidgetItem* item = new QListWidgetItem(QIcon::fromTheme("system-file-manager"), tr("Open in file manager")); + ui.listWidget->addItem(item); + + g_mount_guess_content_type(mount, TRUE, cancellable, (GAsyncReadyCallback)onContentTypeFinished, this); +} + +AutoRunDialog::~AutoRunDialog() { + g_list_foreach(applications, (GFunc)g_object_unref, NULL); + g_list_free(applications); + + if(mount_) + g_object_unref(mount_); + + if(cancellable) { + g_cancellable_cancel(cancellable); + g_object_unref(cancellable); + } +} + +void AutoRunDialog::accept() { + QListWidgetItem* item = ui.listWidget->selectedItems().first(); + if(item) { + GFile* gf = g_mount_get_root(mount_); + void* p = item->data(Qt::UserRole).value(); + if(p) { // run the selected application + GAppInfo* app = G_APP_INFO(p); + GList* filelist = g_list_prepend(NULL, gf); + g_app_info_launch(app, filelist, NULL, NULL); + g_list_free(filelist); + } + else { + // the default action, open the mounted folder in the file manager + Application* app = static_cast(qApp); + Settings& settings = app->settings(); + FmPath* path = fm_path_new_for_gfile(gf); + // open the path in a new window + // FIXME: or should we open it in a new tab? Make this optional later + MainWindow* win = new MainWindow(path); + fm_path_unref(path); + win->resize(settings.windowWidth(), settings.windowHeight()); + if(settings.windowMaximized()) { + win->setWindowState(win->windowState() | Qt::WindowMaximized); + } + win->show(); + } + g_object_unref(gf); + } + QDialog::accept(); +} + +// static +void AutoRunDialog::onContentTypeFinished(GMount* mount, GAsyncResult* res, AutoRunDialog* pThis) { + if(pThis->cancellable) { + g_object_unref(pThis->cancellable); + pThis->cancellable = NULL; + } + + char** types = g_mount_guess_content_type_finish(mount, res, NULL); + char* desc = NULL; + + if(types) { + if(types[0]) { + for(char** type = types; *type; ++type) { + GList* l = g_app_info_get_all_for_type(*type); + if(l) + pThis->applications = g_list_concat(pThis->applications, l); + } + desc = g_content_type_get_description(types[0]); + } + g_strfreev(types); + + if(pThis->applications) { + int pos = 0; + for(GList* l = pThis->applications; l; l = l->next, ++pos) { + GAppInfo* app = G_APP_INFO(l->data); + GIcon* gicon = g_app_info_get_icon(app); + QIcon icon = Fm::IconTheme::icon(gicon); + QString text = QString::fromUtf8(g_app_info_get_name(app)); + QListWidgetItem* item = new QListWidgetItem(icon, text); + item->setData(Qt::UserRole, qVariantFromValue(app)); + pThis->ui.listWidget->insertItem(pos, item); + } + } + } + + if(desc) { + pThis->ui.mediumType->setText(QString::fromUtf8(desc)); + g_free(desc); + } + else + pThis->ui.mediumType->setText(tr("Removable Disk")); + + // select the first item + pThis->ui.listWidget->item(0)->setSelected(true); +} diff --git a/pcmanfm/autorundialog.h b/pcmanfm/autorundialog.h new file mode 100644 index 0000000..f34a92e --- /dev/null +++ b/pcmanfm/autorundialog.h @@ -0,0 +1,54 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_AUTORUNDIALOG_H +#define PCMANFM_AUTORUNDIALOG_H + +#include +#include "ui_autorun.h" +#include + +namespace PCManFM { + +class AutoRunDialog : public QDialog { +Q_OBJECT + +public: + explicit AutoRunDialog(GVolume* volume, GMount* mount, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~AutoRunDialog(); + + virtual void accept(); + +private Q_SLOTS: + +private: + + static void onContentTypeFinished(GMount* mount, GAsyncResult* res, AutoRunDialog* pThis); + +private: + Ui::AutoRunDialog ui; + GCancellable* cancellable; + GList* applications; + GMount* mount_; +}; + +} + +#endif // PCMANFM_AUTORUNDIALOG_H diff --git a/pcmanfm/desktop-preferences.ui b/pcmanfm/desktop-preferences.ui new file mode 100644 index 0000000..7182bd5 --- /dev/null +++ b/pcmanfm/desktop-preferences.ui @@ -0,0 +1,338 @@ + + + DesktopPreferencesDialog + + + + 0 + 0 + 473 + 428 + + + + Desktop Preferences + + + + + + 0 + + + + General + + + + + + Background + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Wallpaper mode: + + + + + + + + 0 + 0 + + + + Wallpaper image file: + + + + + + + + 0 + 0 + + + + + + + + + + + Select background color: + + + + + + + + + Image file + + + + + + Image file path + + + + + + + &Browse + + + + + + + + + + + + Label Text + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Select text color: + + + + + + + + 0 + 0 + + + + Select shadow color: + + + + + + + + 0 + 0 + + + + Select font: + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + Advanced + + + + + + Window Manager + + + + + + Show menus provided by window managers when desktop is clicked + + + + + + + + + + Desktop + + + + + + Desktop folder: + + + + + + + Image file + + + + + + Folder path + + + + + + + &Browse + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + Fm::ColorButton + QPushButton +
colorbutton.h
+
+ + Fm::FontButton + QPushButton +
fontbutton.h
+
+
+ + + + buttonBox + accepted() + DesktopPreferencesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DesktopPreferencesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/pcmanfm/desktopitemdelegate.cpp b/pcmanfm/desktopitemdelegate.cpp new file mode 100644 index 0000000..861dbfb --- /dev/null +++ b/pcmanfm/desktopitemdelegate.cpp @@ -0,0 +1,171 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "desktopitemdelegate.h" +#include "foldermodel.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace PCManFM; + +DesktopItemDelegate::DesktopItemDelegate(QListView* view, QObject* parent): + QStyledItemDelegate(parent ? parent : view), + view_(view), + symlinkIcon_(QIcon::fromTheme("emblem-symbolic-link")), + shadowColor_(0, 0, 0) { +} + +// FIXME: we need to figure out a way to derive from Fm::FolderItemDelegate to avoid code duplication. +void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { + Q_ASSERT(index.isValid()); + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + const QWidget* widget = opt.widget; + QStyle* style = widget ? widget->style() : QApplication::style(); + + painter->save(); + painter->setClipRect(option.rect); + + opt.decorationAlignment = Qt::AlignHCenter | Qt::AlignTop; + opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; + + // draw the icon + QIcon::Mode iconMode; + if(opt.state & QStyle::State_Enabled) { + if(opt.state & QStyle::State_Selected) + iconMode = QIcon::Selected; + else { + iconMode = QIcon::Normal; + } + } + else + iconMode = QIcon::Disabled; + QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y()); + QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode); + painter->drawPixmap(iconPos, pixmap); + + // draw some emblems for the item if needed + // we only support symlink emblem at the moment + FmFileInfo* file = static_cast(index.data(Fm::FolderModel::FileInfoRole).value()); + if(file) { + if(fm_file_info_is_symlink(file)) { + painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode)); + } + } + + // draw text + QRectF textRect(opt.rect.x(), opt.rect.y() + opt.decorationSize.height(), opt.rect.width(), opt.rect.height() - opt.decorationSize.height()); + QTextLayout layout(opt.text, opt.font); + + QTextOption textOption; + textOption.setAlignment(opt.displayAlignment); + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + textOption.setTextDirection(opt.direction); + layout.setTextOption(textOption); + qreal height = 0; + qreal width = 0; + int visibleLines = 0; + layout.beginLayout(); + QString elidedText; + + for(;;) { + QTextLine line = layout.createLine(); + if(!line.isValid()) + break; + line.setLineWidth(textRect.width()); + height += opt.fontMetrics.leading(); + line.setPosition(QPointF(0, height)); + if((height + line.height() + textRect.y()) > textRect.bottom()) { + // if part of this line falls outside the textRect, ignore it and quit. + QTextLine lastLine = layout.lineAt(visibleLines - 1); + elidedText = opt.text.mid(lastLine.textStart()); + elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); + break; + } + height += line.height(); + width = qMax(width, line.naturalTextWidth()); + ++ visibleLines; + } + layout.endLayout(); + QRectF boundRect = layout.boundingRect(); + boundRect.setWidth(width); + boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); + if(opt.state & QStyle::State_Selected) { + QPalette palette = widget->palette(); + // qDebug("w: %f, h:%f, m:%f", boundRect.width(), boundRect.height(), layout.minimumWidth()); + painter->fillRect(boundRect, palette.highlight()); + } + else { // only draw shadow for non-selected items + // draw shadow, FIXME: is it possible to use QGraphicsDropShadowEffect here? + QPen prevPen = painter->pen(); + painter->setPen(QPen(shadowColor_)); + for(int i = 0; i < visibleLines; ++i) { + QTextLine line = layout.lineAt(i); + if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text + QPointF pos(textRect.x() + line.position().x() + 1, textRect.y() + line.y() + line.ascent() + 1); + painter->drawText(pos, elidedText); + } + else { + line.draw(painter, textRect.topLeft() + QPointF(1, 1)); + } + } + painter->setPen(prevPen); + } + + // draw text + for(int i = 0; i < visibleLines; ++i) { + QTextLine line = layout.lineAt(i); + if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text + QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); + painter->drawText(pos, elidedText); + } + else { + line.draw(painter, textRect.topLeft()); + } + } + + if(opt.state & QStyle::State_HasFocus) { + // FIXME: draw focus rect + } + painter->restore(); +} + +QSize DesktopItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { + QVariant value = index.data(Qt::SizeHintRole); + if(value.isValid()) + return qvariant_cast(value); + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + const QWidget* widget = opt.widget; + QStyle* style = widget ? widget->style() : QApplication::style(); + + // use grid size as size hint + QSize gridSize = view_->gridSize(); + return QSize(gridSize.width() -2, gridSize.height() - 2); +} + +DesktopItemDelegate::~DesktopItemDelegate() { + +} diff --git a/pcmanfm/desktopitemdelegate.h b/pcmanfm/desktopitemdelegate.h new file mode 100644 index 0000000..e9a0d39 --- /dev/null +++ b/pcmanfm/desktopitemdelegate.h @@ -0,0 +1,57 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_DESKTOPITEMDELEGATE_H +#define PCMANFM_DESKTOPITEMDELEGATE_H + +#include +#include + +class QListView; +class QTextOption; +class QTextLayout; + +namespace PCManFM { + +class DesktopItemDelegate : public QStyledItemDelegate +{ +Q_OBJECT +public: + explicit DesktopItemDelegate(QListView* view, QObject* parent = 0); + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual ~DesktopItemDelegate(); + + void setShadowColor(const QColor& shadowColor) { + shadowColor_ = shadowColor; + } + const QColor& shadowColor() const { + return shadowColor_; + } + +private: + QListView* view_; + QIcon symlinkIcon_; + QColor shadowColor_; +}; + +} + +#endif // PCMANFM_DESKTOPITEMDELEGATE_H diff --git a/pcmanfm/desktoppreferencesdialog.cpp b/pcmanfm/desktoppreferencesdialog.cpp new file mode 100644 index 0000000..d582e69 --- /dev/null +++ b/pcmanfm/desktoppreferencesdialog.cpp @@ -0,0 +1,210 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "desktoppreferencesdialog.h" +#include "desktopwindow.h" +#include "settings.h" +#include "application.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PCManFM; + +static QString readUserDirsFile() { + QFile file(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/user-dirs.dirs")); + if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QByteArray data = file.readAll(); + file.close(); + return QString::fromLocal8Bit(data); + } + return QString(); +} + +static QString readDesktopDir() { + QString str = readUserDirsFile(); + if(str.isEmpty()) + return QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QStringLiteral("/Desktop"); + QRegExp reg(QStringLiteral("XDG_DESKTOP_DIR=\"([^\n]*)\"")); + if(reg.lastIndexIn(str) != -1) { + str = reg.cap(1); + if(str.startsWith(QStringLiteral("$HOME"))) + str = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + str.mid(5); + return str; + } + return QString(); +} + +static void setDesktopDir(QString path) { + QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); + if(path.startsWith(home)) + path = QStringLiteral("$HOME") + path.mid(home.length()); + QString str = readUserDirsFile(); + QRegExp reg(QStringLiteral("XDG_DESKTOP_DIR=\"([^\n]*)\"")); + QString line = QStringLiteral("XDG_DESKTOP_DIR=\"") + path + '\"'; + if(reg.indexIn(str) != -1) + str.replace(reg, line); + else { + if(!str.endsWith('\n')) + str += '\n'; + str += line + '\n'; + } + QString dir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); + if(QDir().mkpath(dir)) { // write the file + QSaveFile file(dir + QStringLiteral("/user-dirs.dirs")); + if(file.open(QIODevice::WriteOnly | QIODevice::Text)) { + file.write(str.toLocal8Bit()); + file.commit(); + } + } +} + +DesktopPreferencesDialog::DesktopPreferencesDialog(QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f) { + + setAttribute(Qt::WA_DeleteOnClose); + + Settings& settings = static_cast(qApp)->settings(); + ui.setupUi(this); + + // setup wallpaper modes + connect(ui.wallpaperMode, static_cast(&QComboBox::currentIndexChanged), this, &DesktopPreferencesDialog::onWallpaperModeChanged); + ui.wallpaperMode->addItem(tr("Fill with background color only"), DesktopWindow::WallpaperNone); + ui.wallpaperMode->addItem(tr("Stretch to fill the entire screen"), DesktopWindow::WallpaperStretch); + ui.wallpaperMode->addItem(tr("Stretch to fit the screen"), DesktopWindow::WallpaperFit); + ui.wallpaperMode->addItem(tr("Center on the screen"), DesktopWindow::WallpaperCenter); + ui.wallpaperMode->addItem(tr("Tile the image to fill the entire screen"), DesktopWindow::WallpaperTile); + int i; + switch(settings.wallpaperMode()) { + case DesktopWindow::WallpaperNone: + i = 0; + break; + case DesktopWindow::WallpaperStretch: + i = 1; + break; + case DesktopWindow::WallpaperFit: + i = 2; + break; + case DesktopWindow::WallpaperCenter: + i = 3; + break; + case DesktopWindow::WallpaperTile: + i = 4; + break; + default: + i = 0; + } + ui.wallpaperMode->setCurrentIndex(i); + + connect(ui.browse, &QPushButton::clicked, this, &DesktopPreferencesDialog::onBrowseClicked); + qDebug("wallpaper: %s", settings.wallpaper().toUtf8().data()); + ui.imageFile->setText(settings.wallpaper()); + + connect(ui.browseDesktopFolder, &QPushButton::clicked, this, &DesktopPreferencesDialog::onBrowseDesktopFolderClicked); + QString desktopFolder = readDesktopDir(); + qDebug("desktop folder: %s", desktopFolder.toStdString().c_str()); + ui.desktopFolder->setText(desktopFolder); + + ui.font->setFont(settings.desktopFont()); + + ui.backgroundColor->setColor(settings.desktopBgColor()); + ui.textColor->setColor(settings.desktopFgColor()); + ui.shadowColor->setColor(settings.desktopShadowColor()); + ui.showWmMenu->setChecked(settings.showWmMenu()); +} + +DesktopPreferencesDialog::~DesktopPreferencesDialog() { +} + +void DesktopPreferencesDialog::accept() { + Settings& settings = static_cast(qApp)->settings(); + + setDesktopDir(ui.desktopFolder->text()); + + settings.setWallpaper(ui.imageFile->text()); + int mode = ui.wallpaperMode->itemData(ui.wallpaperMode->currentIndex()).toInt(); + settings.setWallpaperMode(mode); + settings.setDesktopFont(ui.font->font()); + settings.setDesktopBgColor(ui.backgroundColor->color()); + settings.setDesktopFgColor(ui.textColor->color()); + settings.setDesktopShadowColor(ui.shadowColor->color()); + settings.setShowWmMenu(ui.showWmMenu->isChecked()); + + QDialog::accept(); + + static_cast(qApp)->updateDesktopsFromSettings(); + settings.save(); +} + +void DesktopPreferencesDialog::onWallpaperModeChanged(int index) { + int n = ui.wallpaperMode->count(); + int mode = ui.wallpaperMode->itemData(index).toInt(); + + bool enable = (mode != DesktopWindow::WallpaperNone); + ui.imageFile->setEnabled(enable); + ui.browse->setEnabled(enable); +} + +void DesktopPreferencesDialog::onBrowseClicked() { + QFileDialog dlg; + dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setFileMode(QFileDialog::ExistingFile); + // compose a name fileter from QImageReader + QString filter; + filter.reserve(256); + filter = tr("Image Files"); + filter += " ("; + QList formats = QImageReader::supportedImageFormats(); + Q_FOREACH(QByteArray format, formats) { + filter += "*."; + filter += format.toLower(); + filter += ' '; + } + filter += ')'; + dlg.setNameFilter(filter); + dlg.setNameFilterDetailsVisible(false); + if(dlg.exec() == QDialog::Accepted) { + QString filename; + filename = dlg.selectedFiles().first(); + ui.imageFile->setText(filename); + } +} + +void DesktopPreferencesDialog::onBrowseDesktopFolderClicked() +{ + QFileDialog dlg; + dlg.setAcceptMode(QFileDialog::AcceptOpen); + dlg.setFileMode(QFileDialog::DirectoryOnly); + if (dlg.exec() == QDialog::Accepted) { + QString dir; + dir = dlg.selectedFiles().first(); + ui.desktopFolder->setText(dir); + } +} + +void DesktopPreferencesDialog::selectPage(QString name) { + QWidget* page = findChild(name + "Page"); + if(page) + ui.tabWidget->setCurrentWidget(page); +} diff --git a/pcmanfm/desktoppreferencesdialog.h b/pcmanfm/desktoppreferencesdialog.h new file mode 100644 index 0000000..076e8b4 --- /dev/null +++ b/pcmanfm/desktoppreferencesdialog.h @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_DESKTOPPREFERENCESDIALOG_H +#define PCMANFM_DESKTOPPREFERENCESDIALOG_H + +#include +#include "ui_desktop-preferences.h" + +namespace PCManFM { + +class DesktopPreferencesDialog : public QDialog { +Q_OBJECT + +public: + explicit DesktopPreferencesDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~DesktopPreferencesDialog(); + + virtual void accept(); + + void selectPage(QString name); + +protected Q_SLOTS: + void onWallpaperModeChanged(int index); + void onBrowseClicked(); + void onBrowseDesktopFolderClicked(); + +private: + Ui::DesktopPreferencesDialog ui; +}; + +} + +#endif // PCMANFM_DESKTOPPREFERENCESDIALOG_H diff --git a/pcmanfm/desktopwindow.cpp b/pcmanfm/desktopwindow.cpp new file mode 100644 index 0000000..8e90c66 --- /dev/null +++ b/pcmanfm/desktopwindow.cpp @@ -0,0 +1,752 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "desktopwindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "./application.h" +#include "mainwindow.h" +#include "desktopitemdelegate.h" +#include "foldermenu.h" +#include "filemenu.h" +#include "cachedfoldermodel.h" +#include "folderview_p.h" +#include "fileoperation.h" +#include "filepropsdialog.h" +#include "utilities.h" +#include "path.h" + +#include +#include +#include +#include + +using namespace PCManFM; + +DesktopWindow::DesktopWindow(int screenNum): + View(Fm::FolderView::IconMode), + screenNum_(screenNum), + folder_(NULL), + model_(NULL), + proxyModel_(NULL), + fileLauncher_(NULL), + showWmMenu_(false), + wallpaperMode_(WallpaperNone), + relayoutTimer_(NULL) { + + QDesktopWidget* desktopWidget = QApplication::desktop(); + setWindowFlags(Qt::Window | Qt::FramelessWindowHint); + setAttribute(Qt::WA_X11NetWmWindowTypeDesktop); + setAttribute(Qt::WA_DeleteOnClose); + + // set our custom file launcher + View::setFileLauncher(&fileLauncher_); + + listView_ = static_cast(childView()); + listView_->setMovement(QListView::Free); + listView_->setResizeMode(QListView::Adjust); + listView_->setFlow(QListView::TopToBottom); + + // NOTE: When XRnadR is in use, the all screens are actually combined to form a + // large virtual desktop and only one DesktopWindow needs to be created and screenNum is -1. + // In some older multihead setups, such as xinerama, every physical screen + // is treated as a separate desktop so many instances of DesktopWindow may be created. + // In this case we only want to show desktop icons on the primary screen. + if(desktopWidget->isVirtualDesktop() || screenNum_ == desktopWidget->primaryScreen()) { + loadItemPositions(); + Settings& settings = static_cast(qApp)->settings(); + + model_ = Fm::CachedFolderModel::modelFromPath(fm_path_get_desktop()); + folder_ = reinterpret_cast(g_object_ref(model_->folder())); + + proxyModel_ = new Fm::ProxyFolderModel(); + proxyModel_->setSourceModel(model_); + proxyModel_->setShowThumbnails(settings.showThumbnails()); + proxyModel_->sort(Fm::FolderModel::ColumnFileMTime); + setModel(proxyModel_); + + connect(proxyModel_, &Fm::ProxyFolderModel::rowsInserted, this, &DesktopWindow::onRowsInserted); + connect(proxyModel_, &Fm::ProxyFolderModel::rowsAboutToBeRemoved, this, &DesktopWindow::onRowsAboutToBeRemoved); + connect(proxyModel_, &Fm::ProxyFolderModel::layoutChanged, this, &DesktopWindow::onLayoutChanged); + connect(listView_, &QListView::indexesMoved, this, &DesktopWindow::onIndexesMoved); + } + + // set our own delegate + delegate_ = new DesktopItemDelegate(listView_); + listView_->setItemDelegateForColumn(Fm::FolderModel::ColumnFileName, delegate_); + + // remove frame + listView_->setFrameShape(QFrame::NoFrame); + // inhibit scrollbars FIXME: this should be optional in the future + listView_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + listView_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + connect(this, &DesktopWindow::openDirRequested, this, &DesktopWindow::onOpenDirRequested); + + listView_->installEventFilter(this); + + // setup shortcuts + QShortcut* shortcut; + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_X), this); // cut + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCutActivated); + + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C), this); // copy + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCopyActivated); + + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this); // paste + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onPasteActivated); + + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this); // select all + connect(shortcut, &QShortcut::activated, listView_, &QListView::selectAll); + + shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this); // delete + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated); + + shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this); // rename + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onRenameActivated); + + shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); // rename + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onFilePropertiesActivated); + + shortcut = new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete), this); // force delete + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated); +} + +DesktopWindow::~DesktopWindow() { + listView_->removeEventFilter(this); + + if(relayoutTimer_) + delete relayoutTimer_; + + if(proxyModel_) + delete proxyModel_; + + if(model_) + model_->unref(); + + if(folder_) + g_object_unref(folder_); +} + +void DesktopWindow::setBackground(const QColor& color) { + bgColor_ = color; +} + +void DesktopWindow::setForeground(const QColor& color) { + QPalette p = listView_->palette(); + p.setBrush(QPalette::Text, color); + listView_->setPalette(p); + fgColor_ = color; +} + +void DesktopWindow::setShadow(const QColor& color) { + shadowColor_ = color; + delegate_->setShadowColor(color); +} + +void DesktopWindow::onOpenDirRequested(FmPath* path, int target) { + // open in new window unconditionally. + Application* app = static_cast(qApp); + MainWindow* newWin = new MainWindow(path); + // apply window size from app->settings + newWin->resize(app->settings().windowWidth(), app->settings().windowHeight()); + newWin->show(); +} + +void DesktopWindow::resizeEvent(QResizeEvent* event) { + QWidget::resizeEvent(event); + + // resize wall paper if needed + if(isVisible() && wallpaperMode_ != WallpaperNone && wallpaperMode_ != WallpaperTile) { + updateWallpaper(); + update(); + } + queueRelayout(100); // Qt use a 100 msec delay for relayout internally so we use it, too. +} + +void DesktopWindow::setDesktopFolder() { + model_ = Fm::CachedFolderModel::modelFromPath(fm_path_get_desktop()); + proxyModel_->setSourceModel(model_); +} + +void DesktopWindow::setWallpaperFile(QString filename) { + wallpaperFile_ = filename; +} + +void DesktopWindow::setWallpaperMode(WallpaperMode mode) { + wallpaperMode_ = mode; +} + +QImage DesktopWindow::loadWallpaperFile(QSize requiredSize) { + // NOTE: for ease of programming, we only use the cache for the primary screen. + bool useCache = (screenNum_ == -1 || screenNum_ == 0); + QFile info; + QString cacheFileName; + if(useCache) { + // see if we have a scaled version cached on disk + cacheFileName = QString::fromLocal8Bit(qgetenv("XDG_CACHE_HOME")); + if(cacheFileName.isEmpty()) + cacheFileName = QDir::homePath() % QLatin1String("/.cache"); + Application* app = static_cast(qApp); + cacheFileName += QLatin1String("/pcmanfm-qt/") % app->profileName(); + QDir().mkpath(cacheFileName); // ensure that the cache dir exists + cacheFileName += QLatin1String("/wallpaper.cache"); + + // read info file + QString origin; + info.setFileName(cacheFileName % ".info"); + if(info.open(QIODevice::ReadOnly)) { + // FIXME: we need to compare mtime to see if the cache is out of date + origin = QString::fromLocal8Bit(info.readLine()); + info.close(); + if(!origin.isEmpty()) { + // try to see if we can get the size of the cached image. + QImageReader reader(cacheFileName); + reader.setAutoDetectImageFormat(true); + QSize cachedSize = reader.size(); + qDebug() << "size of cached file" << cachedSize << ", requiredSize:" << requiredSize; + if(cachedSize.isValid()) { + if(cachedSize == requiredSize) { // see if the cached wallpaper has the size we want + QImage image = reader.read(); // return the loaded image + qDebug() << "origin" << origin; + if(origin == wallpaperFile_) + return image; + } + } + } + } + qDebug() << "no cached wallpaper. generate a new one!"; + } + + // we don't have a cached scaled image, load the original file + QImage image(wallpaperFile_); + qDebug() << "size of original image" << image.size(); + if(image.isNull() || image.size() == requiredSize) // if the original size is what we want + return image; + + // scale the original image + QImage scaled = image.scaled(requiredSize.width(), requiredSize.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + // FIXME: should we save the scaled image if its size is larger than the original image? + + if(useCache) { + // write the path of the original image to the .info file + if(info.open(QIODevice::WriteOnly)) { + info.write(wallpaperFile_.toLocal8Bit()); + info.close(); + + // write the scaled cache image to disk + const char* format; // we keep jpg format for *.jpg files, and use png format for others. + if(wallpaperFile_.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) || wallpaperFile_.endsWith(QLatin1String(".jpeg"), Qt::CaseInsensitive)) + format = "JPG"; + else + format = "PNG"; + scaled.save(cacheFileName, format); + } + qDebug() << "wallpaper cached saved to " << cacheFileName; + // FIXME: we might delay the write of the cached image? + } + return scaled; +} + +// really generate the background pixmap according to current settings and apply it. +void DesktopWindow::updateWallpaper() { + // reset the brush + // QPalette palette(listView_->palette()); + QPalette palette(Fm::FolderView::palette()); + + if(wallpaperMode_ == WallpaperNone) { // use background color only + palette.setBrush(QPalette::Base, bgColor_); + } + else { // use wallpaper + QPixmap pixmap; + QImage image; + if(wallpaperMode_ == WallpaperTile) { // use the original size + image = QImage(wallpaperFile_); + pixmap = QPixmap::fromImage(image); + } + else if(wallpaperMode_ == WallpaperStretch) { + image = loadWallpaperFile(size()); + pixmap = QPixmap::fromImage(image); + } + else { // WallpaperCenter || WallpaperFit + if(wallpaperMode_ == WallpaperCenter) { + image = QImage(wallpaperFile_); // load original image + } + else if(wallpaperMode_ == WallpaperFit) { + // calculate the desired size + QSize origSize = QImageReader(wallpaperFile_).size(); // get the size of the original file + if(origSize.isValid()) { + QSize desiredSize = origSize; + desiredSize.scale(width(), height(), Qt::KeepAspectRatio); + image = loadWallpaperFile(desiredSize); // load the scaled image + } + } + if(!image.isNull()) { + pixmap = QPixmap(size()); + QPainter painter(&pixmap); + pixmap.fill(bgColor_); + int x = (width() - image.width()) / 2; + int y = (height() - image.height()) / 2; + painter.drawImage(x, y, image); + } + } + wallpaperPixmap_ = pixmap; + if(!pixmap.isNull()) { + QBrush brush(pixmap); + palette.setBrush(QPalette::Base, brush); + } + else // if the image is not loaded, fallback to use background color only + palette.setBrush(QPalette::Base, bgColor_); + } + + //FIXME: we should set the pixmap to X11 root window? + setPalette(palette); +} + +void DesktopWindow::updateFromSettings(Settings& settings) { + setDesktopFolder(); + setWallpaperFile(settings.wallpaper()); + setWallpaperMode(settings.wallpaperMode()); + setFont(settings.desktopFont()); + setIconSize(Fm::FolderView::IconMode, QSize(settings.bigIconSize(), settings.bigIconSize())); + // setIconSize may trigger relayout of items by QListView, so we need to do the layout again. + queueRelayout(); + setForeground(settings.desktopFgColor()); + setBackground(settings.desktopBgColor()); + setShadow(settings.desktopShadowColor()); + showWmMenu_ = settings.showWmMenu(); + updateWallpaper(); + update(); +} + +void DesktopWindow::onFileClicked(int type, FmFileInfo* fileInfo) { + if(!fileInfo && showWmMenu_) + return; // do not show the popup if we want to use the desktop menu provided by the WM. + View::onFileClicked(type, fileInfo); +} + +void DesktopWindow::prepareFileMenu(Fm::FileMenu* menu) { + // qDebug("DesktopWindow::prepareFileMenu"); + PCManFM::View::prepareFileMenu(menu); + QAction* action = new QAction(tr("Stic&k to Current Position"), menu); + action->setCheckable(true); + menu->insertSeparator(menu->separator2()); + menu->insertAction(menu->separator2(), action); + + FmFileInfoList* files = menu->files(); + // select exactly one item + if(fm_file_info_list_get_length(files) == 1) { + FmFileInfo* file = menu->firstFile(); + if(customItemPos_.find(fm_file_info_get_name(file)) != customItemPos_.end()) { + // the file item has a custom position + action->setChecked(true); + } + } + connect(action, &QAction::toggled, this, &DesktopWindow::onStickToCurrentPos); +} + +void DesktopWindow::prepareFolderMenu(Fm::FolderMenu* menu) { + PCManFM::View::prepareFolderMenu(menu); + // remove file properties action + menu->removeAction(menu->propertiesAction()); + // add an action for desktop preferences instead + QAction* action = menu->addAction(tr("Desktop Preferences")); + connect(action, &QAction::triggered, this, &DesktopWindow::onDesktopPreferences); +} + +void DesktopWindow::xcbEvent(xcb_generic_event_t* generic_event) { + int event_type = generic_event->response_type & ~0x80; + if(showWmMenu_) { + // If we want to show the desktop menus provided by the window manager instead of ours, + // we have to forward the mouse events we received to the root window. + switch(event_type) { + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t* event = reinterpret_cast(generic_event); + if(event->event == effectiveWinId()) { + // check if the user click on blank area + QModelIndex index = listView_->indexAt(QPoint(event->event_x, event->event_y)); + if(!index.isValid()) { + xcb_ungrab_pointer(QX11Info::connection(), event->time); + // forward the event to the root window + xcb_button_press_event_t event2 = *event; + WId root = QX11Info::appRootWindow(QX11Info::appScreen()); + event2.event = root; + xcb_send_event(QX11Info::connection(), 0, root, XCB_EVENT_MASK_BUTTON_PRESS, (char*)&event2); + } + } + break; + } + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t* event = reinterpret_cast(generic_event); + if(event->event == effectiveWinId()) { + // check if the user click on blank area + QModelIndex index = listView_->indexAt(QPoint(event->event_x, event->event_y)); + if(!index.isValid()) { + // forward the event to the root window + xcb_button_release_event_t event2 = *event; + WId root = QX11Info::appRootWindow(QX11Info::appScreen()); + event2.event = root; + xcb_send_event(QX11Info::connection(), 0, root, XCB_EVENT_MASK_BUTTON_RELEASE, (char*)&event2); + } + } + break; + } + default: + break; + } + } +} + +void DesktopWindow::onDesktopPreferences() { + static_cast(qApp)->desktopPrefrences(QString()); +} + +void DesktopWindow::onRowsInserted(const QModelIndex& parent, int start, int end) { + queueRelayout(); +} + +void DesktopWindow::onRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { + if(!customItemPos_.isEmpty()) { + // also delete stored custom item positions for the items currently being removed. + bool changed = false; + for(int row = start; row <= end ;++row) { + QModelIndex index = parent.child(row, 0); + FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); + if(file) { // remove custom position for the item + if(customItemPos_.remove(fm_file_info_get_name(file))) + changed = true; + } + } + if(changed) + saveItemPositions(); + } + queueRelayout(); +} + +void DesktopWindow::onLayoutChanged() { + queueRelayout(); +} + +void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { + // remember the custom position for the items + Q_FOREACH(const QModelIndex& index, indexes) { + // Under some circumstances, Qt might emit indexMoved for + // every single cells in the same row. (when QAbstractItemView::SelectItems is set) + // So indexes list may contain several indixes for the same row. + // Since we only care about rows, not individual cells, + // let's handle column 0 of every row here. + if(index.column() == 0) { + FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); + QRect itemRect = listView_->rectForIndex(index); + QByteArray name = fm_file_info_get_name(file); + customItemPos_[name] = itemRect.topLeft(); + // qDebug() << "indexMoved:" << name << index << itemRect; + } + } + saveItemPositions(); + queueRelayout(); +} + +// QListView does item layout in a very inflexible way, so let's do our custom layout again. +// FIXME: this is very inefficient, but due to the design flaw of QListView, this is currently the only workaround. +void DesktopWindow::relayoutItems() { + // qDebug("relayoutItems()"); + if(relayoutTimer_) { + // this slot might be called from the timer, so we cannot delete it directly here. + relayoutTimer_->deleteLater(); + relayoutTimer_ = NULL; + } + + QDesktopWidget* desktop = qApp->desktop(); + int screen = 0; + int row = 0; + int rowCount = proxyModel_->rowCount(); + for(;;) { + if(desktop->isVirtualDesktop()) { + if(screen >= desktop->numScreens()) + break; + }else { + screen = screenNum_; + } + QRect workArea = desktop->availableGeometry(screen); + workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area + // qDebug() << "workArea" << screen << workArea; + // FIXME: we use an internal class declared in a private header here, which is pretty bad. + QSize grid = listView_->gridSize(); + QPoint pos = workArea.topLeft(); + for(; row < rowCount; ++row) { + QModelIndex index = proxyModel_->index(row, 0); + FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); + QByteArray name = fm_file_info_get_name(file); + QHash::iterator it = customItemPos_.find(name); + if(it != customItemPos_.end()) { // the item has a custom position + QPoint customPos = *it; + listView_->setPositionForIndex(customPos, index); + // qDebug() << "set custom pos:" << name << row << index << customPos; + continue; + } + // check if the current pos is alredy occupied by a custom item + bool used = false; + for(it = customItemPos_.begin(); it != customItemPos_.end(); ++it) { + QPoint customPos = *it; + if(QRect(customPos, grid).contains(pos)) { + used = true; + break; + } + } + if(used) { // go to next pos + --row; + } + else { + listView_->setPositionForIndex(pos, index); + // qDebug() << "set pos" << name << row << index << pos; + } + // move to next cell in the column + pos.setY(pos.y() + grid.height() + listView_->spacing()); + if(pos.y() + grid.height() > workArea.bottom()) { + // if the next position may exceed the bottom of work area, go to the top of next column + pos.setX(pos.x() + grid.width() + listView_->spacing()); + pos.setY(workArea.top()); + + // check if the new column exceeds the right margin of work area + if(pos.x() + grid.width() > workArea.right()) { + if(desktop->isVirtualDesktop()) { + // in virtual desktop mode, go to next screen + ++screen; + break; + } + } + } + } + if(row >= rowCount) + break; + } +} + +void DesktopWindow::loadItemPositions() { + // load custom item positions + Settings& settings = static_cast(qApp)->settings(); + QString configFile = QString("%1/desktop-items-%2.conf").arg(settings.profileDir(settings.profileName())).arg(screenNum_); + QSettings file(configFile, QSettings::IniFormat); + Q_FOREACH(const QString& name, file.childGroups()) { + file.beginGroup(name); + QVariant var = file.value("pos"); + if(var.isValid()) + customItemPos_[name.toUtf8()] = var.toPoint(); + file.endGroup(); + } +} + +void DesktopWindow::saveItemPositions() { + Settings& settings = static_cast(qApp)->settings(); + // store custom item positions + QString configFile = QString("%1/desktop-items-%2.conf").arg(settings.profileDir(settings.profileName())).arg(screenNum_); + // FIXME: using QSettings here is inefficient and it's not friendly to UTF-8. + QSettings file(configFile, QSettings::IniFormat); + file.clear(); // remove all existing entries + + // FIXME: we have to remove dead entries not associated to any files? + QHash::iterator it; + for(it = customItemPos_.begin(); it != customItemPos_.end(); ++it) { + const QByteArray& name = it.key(); + QPoint pos = it.value(); + file.beginGroup(QString::fromUtf8(name, name.length())); + file.setValue("pos", pos); + file.endGroup(); + } +} + +void DesktopWindow::onStickToCurrentPos(bool toggled) { + QAction* action = static_cast(sender()); + Fm::FileMenu* menu = static_cast(action->parent()); + + QModelIndexList indexes = listView_->selectionModel()->selectedIndexes(); + if(!indexes.isEmpty()) { + FmFileInfo* file = menu->firstFile(); + QByteArray name = fm_file_info_get_name(file); + QModelIndex index = indexes.first(); + if(toggled) { // remember to current custom position + QRect itemRect = listView_->rectForIndex(index); + customItemPos_[name] = itemRect.topLeft(); + saveItemPositions(); + } + else { // cancel custom position and perform relayout + QHash::iterator it = customItemPos_.find(name); + if(it != customItemPos_.end()) { + customItemPos_.erase(it); + saveItemPositions(); + relayoutItems(); + } + } + } +} + +void DesktopWindow::queueRelayout(int delay) { + // qDebug() << "queueRelayout"; + if(!relayoutTimer_) { + relayoutTimer_ = new QTimer(); + relayoutTimer_->setSingleShot(true); + connect(relayoutTimer_, &QTimer::timeout, this, &DesktopWindow::relayoutItems); + relayoutTimer_->start(delay); + } +} + +// slots for file operations + +void DesktopWindow::onCutActivated() { + if(FmPathList* paths = selectedFilePaths()) { + Fm::cutFilesToClipboard(paths); + fm_path_list_unref(paths); + } +} + +void DesktopWindow::onCopyActivated() { + if(FmPathList* paths = selectedFilePaths()) { + Fm::copyFilesToClipboard(paths); + fm_path_list_unref(paths); + } +} + +void DesktopWindow::onPasteActivated() { + Fm::pasteFilesFromClipboard(path()); +} + +void DesktopWindow::onDeleteActivated() { + if(FmPathList* paths = selectedFilePaths()) { + Settings& settings = static_cast(qApp)->settings(); + bool shiftPressed = (qApp->keyboardModifiers() & Qt::ShiftModifier ? true : false); + if(settings.useTrash() && !shiftPressed) + Fm::FileOperation::trashFiles(paths, settings.confirmDelete()); + else + Fm::FileOperation::deleteFiles(paths, settings.confirmDelete()); + fm_path_list_unref(paths); + } +} + +void DesktopWindow::onRenameActivated() { + if(FmFileInfoList* files = selectedFiles()) { + for(GList* l = fm_file_info_list_peek_head_link(files); l; l = l->next) { + FmFileInfo* info = FM_FILE_INFO(l->data); + Fm::renameFile(info, NULL); + fm_file_info_list_unref(files); + } + } +} + +void DesktopWindow::onFilePropertiesActivated() { + if(FmFileInfoList* files = selectedFiles()) { + Fm::FilePropsDialog::showForFiles(files); + fm_file_info_list_unref(files); + } +} + +bool DesktopWindow::event(QEvent* event) +{ + switch(event->type()) { + case QEvent::WinIdChange: { + qDebug() << "winid change:" << effectiveWinId(); + if(effectiveWinId() == 0) + break; + // set freedesktop.org EWMH hints properly + if(QX11Info::isPlatformX11() && QX11Info::connection()) { + xcb_connection_t* con = QX11Info::connection(); + const char* atom_name = "_NET_WM_WINDOW_TYPE_DESKTOP"; + xcb_atom_t atom = xcb_intern_atom_reply(con, xcb_intern_atom(con, 0, strlen(atom_name), atom_name), NULL)->atom; + const char* prop_atom_name = "_NET_WM_WINDOW_TYPE"; + xcb_atom_t prop_atom = xcb_intern_atom_reply(con, xcb_intern_atom(con, 0, strlen(prop_atom_name), prop_atom_name), NULL)->atom; + xcb_atom_t XA_ATOM = 4; + xcb_change_property(con, XCB_PROP_MODE_REPLACE, effectiveWinId(), prop_atom, XA_ATOM, 32, 1, &atom); + } + break; + } +#undef FontChange // FontChange is defined in the headers of XLib and clashes with Qt, let's undefine it. + case QEvent::StyleChange: + case QEvent::FontChange: + queueRelayout(); + break; + } + return QWidget::event(event); +} + +#undef FontChange // this seems to be defined in Xlib headers as a macro, undef it! + +bool DesktopWindow::eventFilter(QObject * watched, QEvent * event) { + if(watched == listView_) { + switch(event->type()) { + case QEvent::StyleChange: + case QEvent::FontChange: + if(model_) + queueRelayout(); + break; + default: + break; + } + } + return false; +} + +void DesktopWindow::childDropEvent(QDropEvent* e) { + bool moveItem = false; + if(e->source() == listView_ && e->keyboardModifiers() == Qt::NoModifier) { + // drag source is our list view, and no other modifier keys are pressed + // => we're dragging desktop items + const QMimeData *mimeData = e->mimeData(); + if(mimeData->hasFormat("application/x-qabstractitemmodeldatalist")) { + QModelIndex dropIndex = listView_->indexAt(e->pos()); + if(dropIndex.isValid()) { // drop on an item + QModelIndexList selected = selectedIndexes(); // the dragged items + if(selected.contains(dropIndex)) { // drop on self, ignore + moveItem = true; + } + } + else { // drop on a blank area + moveItem = true; + } + } + } + if(moveItem) + e->accept(); + else + Fm::FolderView::childDropEvent(e); +} + + +void DesktopWindow::setScreenNum(int num) { + if(screenNum_ != num) { + screenNum_ = num; + queueRelayout(); + } +} diff --git a/pcmanfm/desktopwindow.h b/pcmanfm/desktopwindow.h new file mode 100644 index 0000000..f1ad12b --- /dev/null +++ b/pcmanfm/desktopwindow.h @@ -0,0 +1,140 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_DESKTOPWINDOW_H +#define PCMANFM_DESKTOPWINDOW_H + +#include "view.h" +#include "launcher.h" +#include +#include +#include +#include + +namespace Fm { + class CachedFolderModel; + class ProxyFolderModel; + class FolderViewListView; +} + +namespace PCManFM { + +class DesktopItemDelegate; +class Settings; + +class DesktopWindow : public View { +Q_OBJECT +public: + friend class Application; + + enum WallpaperMode { + WallpaperNone, + WallpaperStretch, + WallpaperFit, + WallpaperCenter, + WallpaperTile + }; + + explicit DesktopWindow(int screenNum); + virtual ~DesktopWindow(); + + void setForeground(const QColor& color); + void setShadow(const QColor& color); + void setBackground(const QColor& color); + void setDesktopFolder(); + void setWallpaperFile(QString filename); + void setWallpaperMode(WallpaperMode mode = WallpaperStretch); + + // void setWallpaperAlpha(qreal alpha); + void updateWallpaper(); + void updateFromSettings(Settings& settings); + + void xcbEvent(xcb_generic_event_t* generic_event); + + void queueRelayout(int delay = 0); + + int screenNum() const { + return screenNum_; + } + + void setScreenNum(int num); + +protected: + virtual void prepareFolderMenu(Fm::FolderMenu* menu); + virtual void prepareFileMenu(Fm::FileMenu* menu); + virtual void resizeEvent(QResizeEvent* event); + virtual void onFileClicked(int type, FmFileInfo* fileInfo); + + void loadItemPositions(); + void saveItemPositions(); + + QImage loadWallpaperFile(QSize requiredSize); + + virtual bool event(QEvent* event); + virtual bool eventFilter(QObject * watched, QEvent * event); + + virtual void childDropEvent(QDropEvent* e); + +protected Q_SLOTS: + void onOpenDirRequested(FmPath* path, int target); + void onDesktopPreferences(); + + void onRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end); + void onRowsInserted(const QModelIndex& parent, int start, int end); + void onLayoutChanged(); + void onIndexesMoved(const QModelIndexList& indexes); + + void relayoutItems(); + void onStickToCurrentPos(bool toggled); + + // void updateWorkArea(); + + // file operations + void onCutActivated(); + void onCopyActivated(); + void onPasteActivated(); + void onRenameActivated(); + void onDeleteActivated(); + void onFilePropertiesActivated(); + +private: + Fm::ProxyFolderModel* proxyModel_; + Fm::CachedFolderModel* model_; + FmFolder* folder_; + Fm::FolderViewListView* listView_; + + QColor fgColor_; + QColor bgColor_; + QColor shadowColor_; + QString wallpaperFile_; + WallpaperMode wallpaperMode_; + QPixmap wallpaperPixmap_; + DesktopItemDelegate* delegate_; + Launcher fileLauncher_; + bool showWmMenu_; + + int screenNum_; + QHash customItemPos_; + QTimer* relayoutTimer_; +}; + +} + +#endif // PCMANFM_DESKTOPWINDOW_H diff --git a/pcmanfm/file-search.ui b/pcmanfm/file-search.ui new file mode 100644 index 0000000..a698eae --- /dev/null +++ b/pcmanfm/file-search.ui @@ -0,0 +1,508 @@ + + + FindFilesDialog + + + + 0 + 0 + 431 + 359 + + + + Find Files + + + + + + 0 + + + + Name/Location + + + + + + File name patterns + + + + + + Pattern: + + + + + + + + + + Case insensitive + + + + + + + Use regular expression + + + + + + + + + + Places to search + + + + + + + + + + + + + Add + + + + + + + + + + Remove + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Search in sub directories + + + + + + + Search hidden files + + + + + + + + buttonBox + groupBox + groupBox_2 + + + + File Type + + + + + + File Type + + + + + + Only search for files of following types: + + + + + + + Text files + + + + + + + Image files + + + + + + + Audio files + + + + + + + Video files + + + + + + + Documents + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Content + + + + + + File contains + + + + + + + + + Case insensitive + + + + + + + Use regular expression + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Properties + + + + + + File Size + + + + + + Bigger than: + + + + + + + false + + + + + + + false + + + + + + + Smaller than: + + + + + + + false + + + + + + + false + + + + + + + + + + Last Modified Time + + + + + + Earlier than: + + + + + + + Later than: + + + + + + + false + + + true + + + + + + + false + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FindFilesDialog + accept() + + + 222 + 344 + + + 157 + 274 + + + + + buttonBox + rejected() + FindFilesDialog + reject() + + + 290 + 350 + + + 286 + 274 + + + + + checkBox_14 + toggled(bool) + dateTimeEdit + setEnabled(bool) + + + 129 + 166 + + + 294 + 170 + + + + + checkBox_15 + toggled(bool) + dateTimeEdit_2 + setEnabled(bool) + + + 91 + 188 + + + 302 + 195 + + + + + checkBox_12 + toggled(bool) + spinBox + setEnabled(bool) + + + 102 + 73 + + + 184 + 77 + + + + + checkBox_12 + toggled(bool) + comboBox + setEnabled(bool) + + + 49 + 72 + + + 357 + 76 + + + + + checkBox_13 + toggled(bool) + spinBox_2 + setEnabled(bool) + + + 123 + 101 + + + 186 + 104 + + + + + checkBox_13 + toggled(bool) + comboBox_2 + setEnabled(bool) + + + 53 + 98 + + + 339 + 108 + + + + + diff --git a/pcmanfm/launcher.cpp b/pcmanfm/launcher.cpp new file mode 100644 index 0000000..c71d25d --- /dev/null +++ b/pcmanfm/launcher.cpp @@ -0,0 +1,62 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "launcher.h" +#include "mainwindow.h" +#include "application.h" + +namespace PCManFM { + +Launcher::Launcher(PCManFM::MainWindow* mainWindow): + Fm::FileLauncher(), + mainWindow_(mainWindow) { + +} + +Launcher::~Launcher() { + +} + +bool Launcher::openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err) { + GList* l = folder_infos; + FmFileInfo* fi = FM_FILE_INFO(l->data); + Application* app = static_cast(qApp); + MainWindow* mainWindow = mainWindow_; + if(!mainWindow) { + mainWindow = new MainWindow(fm_file_info_get_path(fi)); + mainWindow->resize(app->settings().windowWidth(), app->settings().windowHeight()); + + if(app->settings().windowMaximized()) { + mainWindow->setWindowState(mainWindow->windowState() | Qt::WindowMaximized); + } + } + else + mainWindow->chdir(fm_file_info_get_path(fi)); + l = l->next; + for(; l; l = l->next) { + fi = FM_FILE_INFO(l->data); + mainWindow->addTab(fm_file_info_get_path(fi)); + } + mainWindow->show(); + mainWindow->raise(); + return true; +} + +} //namespace PCManFM diff --git a/pcmanfm/launcher.h b/pcmanfm/launcher.h new file mode 100644 index 0000000..35e30ab --- /dev/null +++ b/pcmanfm/launcher.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef PCMANFM_LAUNCHER_H +#define PCMANFM_LAUNCHER_H + +#include "filelauncher.h" + +namespace PCManFM { + +class MainWindow; + +class Launcher : public Fm::FileLauncher { +public: + Launcher(MainWindow* mainWindow = NULL); + ~Launcher(); + +protected: + virtual bool openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err); + +private: + MainWindow* mainWindow_; +}; + +} + +#endif // PCMANFM_LAUNCHER_H diff --git a/pcmanfm/main-win.ui b/pcmanfm/main-win.ui new file mode 100644 index 0000000..1c550cb --- /dev/null +++ b/pcmanfm/main-win.ui @@ -0,0 +1,648 @@ + + + MainWindow + + + + 0 + 0 + 460 + 369 + + + + File Manager + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + 460 + 27 + + + + + &File + + + + + + + + + + + + + &Help + + + + + + &View + + + + &Sorting + + + + + + + + + + + + + + + + + + + + + + + + + + &Edit + + + + + + + + + + + + + + + &Bookmarks + + + + + + + &Go + + + + + + + + + + + + + + + &Tool + + + + + + + + + + + + + + + + Main Toolbar + + + false + + + false + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + + Go &Up + + + Go Up + + + Alt+Up + + + + + + + + + + Home + + + Alt+Home + + + + + + + + + + &Reload + + + F5 + + + + + + + + + + Go + + + + + + + + + + Quit + + + + + + + + + + &About + + + + + + + + + + &New Window + + + New Window + + + Ctrl+N + + + + + true + + + Show &Hidden + + + Ctrl+H + + + + + + + + + + &Computer + + + + + + + + + + &Trash + + + + + &Network + + + + + + + + + + &Desktop + + + + + + + + + + &Add to Bookmarks + + + + + &Applications + + + + + Reload + + + + + true + + + &Icon View + + + + + true + + + &Compact View + + + + + true + + + &Detailed List + + + + + true + + + &Thumbnail View + + + + + + + + + + Cu&t + + + Ctrl+X + + + + + + + + + + &Copy + + + Ctrl+C + + + + + + + + + + &Paste + + + Ctrl+V + + + + + Select &All + + + Ctrl+A + + + + + Pr&eferences + + + + + true + + + Ascending + + + + + true + + + Descending + + + + + true + + + By File Name + + + + + true + + + By Modification Time + + + + + true + + + By File Type + + + + + true + + + By Owner + + + + + true + + + Folder First + + + + + + + + + + New &Tab + + + New Tab + + + Ctrl+T + + + + + + + + + + Go &Back + + + Go Back + + + Alt+Left + + + + + + + + + + Go &Forward + + + Go Forward + + + Alt+Right + + + + + &Invert Selection + + + + + + + + + + &Delete + + + Del + + + + + &Rename + + + F2 + + + + + C&lose Tab + + + Ctrl+W + + + + + File &Properties + + + Alt+Return + + + + + &Folder Properties + + + + + true + + + Case Sensitive + + + + + true + + + By File Size + + + + + Close Window + + + + + Edit Bookmarks + + + + + Open &Terminal + + + F4 + + + + + Open as &Root + + + + + &Edit Bookmarks + + + + + + PCManFM::TabBar + QWidget +
tabbar.h
+ 1 +
+ + Fm::SidePane + QWidget +
sidepane.h
+ 1 +
+
+ + +
diff --git a/pcmanfm/mainwindow.cpp b/pcmanfm/mainwindow.cpp new file mode 100644 index 0000000..e9d382e --- /dev/null +++ b/pcmanfm/mainwindow.cpp @@ -0,0 +1,937 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tabpage.h" +#include "filelauncher.h" +#include "filemenu.h" +#include "bookmarkaction.h" +#include "fileoperation.h" +#include "utilities.h" +#include "filepropsdialog.h" +#include "pathedit.h" +#include "ui_about.h" +#include "application.h" +#include "../libfm-qt/path.h" + +// #include "qmodeltest/modeltest.h" + +using namespace Fm; + +namespace PCManFM { + +MainWindow::MainWindow(FmPath* path): + QMainWindow(), + fileLauncher_(this) { + + Settings& settings = static_cast(qApp)->settings(); + setAttribute(Qt::WA_DeleteOnClose); + // setup user interface + ui.setupUi(this); + + // hide menu items that are not usable + if(!isUriSchemeSupported("computer")) + ui.actionComputer->setVisible(false); + if(!isUriSchemeSupported("trash")) + ui.actionTrash->setVisible(false); + if(!isUriSchemeSupported("network")) + ui.actionNetwork->setVisible(false); + + // add a context menu for showing browse history to back and forward buttons + QToolButton* forwardButton = static_cast(ui.toolBar->widgetForAction(ui.actionGoForward)); + forwardButton->setContextMenuPolicy(Qt::CustomContextMenu); + connect(forwardButton, &QToolButton::customContextMenuRequested, this, &MainWindow::onBackForwardContextMenu); + QToolButton* backButton = static_cast(ui.toolBar->widgetForAction(ui.actionGoBack)); + backButton->setContextMenuPolicy(Qt::CustomContextMenu); + connect(backButton, &QToolButton::customContextMenuRequested, this, &MainWindow::onBackForwardContextMenu); + + // tabbed browsing interface + ui.tabBar->setDocumentMode(true); + ui.tabBar->setTabsClosable(true); + ui.tabBar->setElideMode(Qt::ElideRight); + ui.tabBar->setExpanding(false); + ui.tabBar->setMovable(true); // reorder the tabs by dragging + +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + // switch to the tab under the cursor during dnd. + ui.tabBar->setChangeCurrentOnDrag(true); + ui.tabBar->setAcceptDrops(true); +#endif + + connect(ui.tabBar, &QTabBar::currentChanged, this, &MainWindow::onTabBarCurrentChanged); + connect(ui.tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::onTabBarCloseRequested); + connect(ui.tabBar, &QTabBar::tabMoved, this, &MainWindow::onTabBarTabMoved); + connect(ui.stackedWidget, &QStackedWidget::widgetRemoved, this, &MainWindow::onStackedWidgetWidgetRemoved); + + // side pane + ui.sidePane->setIconSize(QSize(settings.sidePaneIconSize(), settings.sidePaneIconSize())); + ui.sidePane->setMode(Fm::SidePane::ModePlaces); + connect(ui.sidePane, &Fm::SidePane::chdirRequested, this, &MainWindow::onSidePaneChdirRequested); + // detect change of splitter position + connect(ui.splitter, &QSplitter::splitterMoved, this, &MainWindow::onSplitterMoved); + + // path bar + pathEntry = new Fm::PathEdit(this); + connect(pathEntry, &Fm::PathEdit::returnPressed, this, &MainWindow::onPathEntryReturnPressed); + ui.toolBar->insertWidget(ui.actionGo, pathEntry); + + // add filesystem info to status bar + fsInfoLabel = new QLabel(ui.statusbar); + ui.statusbar->addPermanentWidget(fsInfoLabel); + + // setup the splitter + ui.splitter->setStretchFactor(1, 1); // only the right pane can be stretched + QList sizes; + sizes.append(settings.splitterPos()); + sizes.append(300); + ui.splitter->setSizes(sizes); + + // load bookmark menu + bookmarks = fm_bookmarks_dup(); + g_signal_connect(bookmarks, "changed", G_CALLBACK(onBookmarksChanged), this); + loadBookmarksMenu(); + + // Fix the menu groups which is not done by Qt designer + // To my suprise, this was supported in Qt designer 3 :-( + QActionGroup* group = new QActionGroup(ui.menu_View); + group->setExclusive(true); + group->addAction(ui.actionIconView); + group->addAction(ui.actionCompactView); + group->addAction(ui.actionThumbnailView); + group->addAction(ui.actionDetailedList); + + group = new QActionGroup(ui.menuSorting); + group->setExclusive(true); + group->addAction(ui.actionByFileName); + group->addAction(ui.actionByMTime); + group->addAction(ui.actionByFileSize); + group->addAction(ui.actionByFileType); + group->addAction(ui.actionByOwner); + + group = new QActionGroup(ui.menuSorting); + group->setExclusive(true); + group->addAction(ui.actionAscending); + group->addAction(ui.actionDescending); + + // create shortcuts + QShortcut* shortcut; + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_L), this); + connect(shortcut, &QShortcut::activated, pathEntry, static_cast(&Fm::PathEdit::setFocus)); + + shortcut = new QShortcut(Qt::ALT + Qt::Key_D, this); + connect(shortcut, &QShortcut::activated, pathEntry, static_cast(&QWidget::setFocus)); + + shortcut = new QShortcut(Qt::CTRL + Qt::Key_Tab, this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::onShortcutNextTab); + + shortcut = new QShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab, this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::onShortcutPrevTab); + + int i; + for(i = 0; i < 10; ++i) { + shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_0 + i), this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::onShortcutJumpToTab); + + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_0 + i), this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::onShortcutJumpToTab); + } + + shortcut = new QShortcut(QKeySequence(Qt::Key_Backspace), this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionGoUp_triggered); + + shortcut = new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete), this); + connect(shortcut, &QShortcut::activated, this, &MainWindow::on_actionDelete_triggered); + + if(path) + addTab(path); +} + +MainWindow::~MainWindow() { + if(bookmarks) + g_object_unref(bookmarks); +} + +void MainWindow::chdir(FmPath* path) { + TabPage* page = currentPage(); + + if(page) { + page->chdir(path, true); + updateUIForCurrentPage(); + } +} + +// add a new tab +void MainWindow::addTab(FmPath* path) { + Settings& settings = static_cast(qApp)->settings(); + + TabPage* newPage = new TabPage(path, this); + newPage->setFileLauncher(&fileLauncher_); + int index = ui.stackedWidget->addWidget(newPage); + connect(newPage, &TabPage::titleChanged, this, &MainWindow::onTabPageTitleChanged); + connect(newPage, &TabPage::statusChanged, this, &MainWindow::onTabPageStatusChanged); + connect(newPage, &TabPage::openDirRequested, this, &MainWindow::onTabPageOpenDirRequested); + connect(newPage, &TabPage::sortFilterChanged, this, &MainWindow::onTabPageSortFilterChanged); + + ui.tabBar->insertTab(index, newPage->title()); + + if(!settings.alwaysShowTabs()) { + ui.tabBar->setVisible(ui.tabBar->count() > 1); + } +} + +void MainWindow::onPathEntryReturnPressed() { + QString text = pathEntry->text(); + QByteArray utext = text.toUtf8(); + FmPath* path = fm_path_new_for_display_name(utext); + chdir(path); + fm_path_unref(path); +} + +void MainWindow::on_actionGoUp_triggered() { + TabPage* page = currentPage(); + + if(page) { + page->up(); + updateUIForCurrentPage(); + } +} + +void MainWindow::on_actionGoBack_triggered() { + TabPage* page = currentPage(); + + if(page) { + page->backward(); + updateUIForCurrentPage(); + } +} + +void MainWindow::on_actionGoForward_triggered() { + TabPage* page = currentPage(); + + if(page) { + page->forward(); + updateUIForCurrentPage(); + } +} + +void MainWindow::on_actionHome_triggered() { + chdir(fm_path_get_home()); +} + +void MainWindow::on_actionReload_triggered() { + currentPage()->reload(); +} + +void MainWindow::on_actionGo_triggered() { + onPathEntryReturnPressed(); +} + +void MainWindow::on_actionNewTab_triggered() { + FmPath* path = currentPage()->path(); + addTab(path); +} + +void MainWindow::on_actionNewWin_triggered() { + FmPath* path = currentPage()->path(); + Application* app = static_cast(qApp); + MainWindow* newWin = new MainWindow(path); + newWin->resize(app->settings().windowWidth(), app->settings().windowHeight()); + + if(app->settings().windowMaximized()) + newWin->setWindowState(newWin->windowState() | Qt::WindowMaximized); + + newWin->show(); +} + +void MainWindow::on_actionCloseTab_triggered() { + closeTab(ui.tabBar->currentIndex()); +} + +void MainWindow::on_actionCloseWindow_triggered() { + // FIXME: should we save state here? + close(); + // the window will be deleted automatically on close +} + +void MainWindow::on_actionFileProperties_triggered() { + TabPage* page = currentPage(); + + if(page) { + FmFileInfoList* files = page->selectedFiles(); + + if(files) { + Fm::FilePropsDialog::showForFiles(files); + fm_file_info_list_unref(files); + } + } +} + +void MainWindow::on_actionFolderProperties_triggered() { + TabPage* page = currentPage(); + + if(page) { + FmFolder* folder = page->folder(); + + if(folder) { + FmFileInfo* info = fm_folder_get_info(folder); + + if(info) + Fm::FilePropsDialog::showForFile(info); + } + } +} + +void MainWindow::on_actionShowHidden_triggered(bool checked) { + TabPage* tabPage = currentPage(); + tabPage->setShowHidden(checked); + static_cast(qApp)->settings().setShowHidden(checked); +} + +void MainWindow::on_actionByFileName_triggered(bool checked) { + currentPage()->sort(Fm::FolderModel::ColumnFileName, currentPage()->sortOrder()); +} + +void MainWindow::on_actionByMTime_triggered(bool checked) { + currentPage()->sort(Fm::FolderModel::ColumnFileMTime, currentPage()->sortOrder()); +} + +void MainWindow::on_actionByOwner_triggered(bool checked) { + currentPage()->sort(Fm::FolderModel::ColumnFileOwner, currentPage()->sortOrder()); +} + +void MainWindow::on_actionByFileSize_triggered(bool checked) { + currentPage()->sort(Fm::FolderModel::ColumnFileSize, currentPage()->sortOrder()); +} + +void MainWindow::on_actionByFileType_triggered(bool checked) { + currentPage()->sort(Fm::FolderModel::ColumnFileType, currentPage()->sortOrder()); +} + +void MainWindow::on_actionAscending_triggered(bool checked) { + currentPage()->sort(currentPage()->sortColumn(), Qt::AscendingOrder); +} + +void MainWindow::on_actionDescending_triggered(bool checked) { + currentPage()->sort(currentPage()->sortColumn(), Qt::DescendingOrder); +} + +void MainWindow::on_actionCaseSensitive_triggered(bool checked) { + currentPage()->setSortCaseSensitive(checked); +} + +void MainWindow::on_actionFolderFirst_triggered(bool checked) { + currentPage()->setSortFolderFirst(checked); +} + +void MainWindow::on_actionComputer_triggered() { + FmPath* path = fm_path_new_for_uri("computer:///"); + chdir(path); + fm_path_unref(path); +} + +void MainWindow::on_actionApplications_triggered() { + chdir(fm_path_get_apps_menu()); +} + +void MainWindow::on_actionTrash_triggered() { + chdir(fm_path_get_trash()); +} + +void MainWindow::on_actionNetwork_triggered() { + FmPath* path = fm_path_new_for_uri("network:///"); + chdir(path); + fm_path_unref(path); +} + +void MainWindow::on_actionDesktop_triggered() { + chdir(fm_path_get_desktop()); +} + +void MainWindow::on_actionAddToBookmarks_triggered() { + TabPage* page = currentPage(); + + if(page) { + FmPath* cwd = page->path(); + + if(cwd) { + char* dispName = fm_path_display_basename(cwd); + fm_bookmarks_insert(bookmarks, cwd, dispName, -1); + g_free(dispName); + } + } +} + +void MainWindow::on_actionEditBookmarks_triggered() { + Application* app = static_cast(qApp); + app->editBookmarks(); +} + +void MainWindow::on_actionAbout_triggered() { + // the about dialog + class AboutDialog : public QDialog { + public: + explicit AboutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0) { + ui.setupUi(this); + ui.version->setText(tr("Version: %1").arg(PCMANFM_QT_VERSION)); + } + private: + Ui::AboutDialog ui; + }; + AboutDialog dialog(this); + dialog.exec(); +} + +void MainWindow::on_actionIconView_triggered() { + currentPage()->setViewMode(Fm::FolderView::IconMode); +} + +void MainWindow::on_actionCompactView_triggered() { + currentPage()->setViewMode(Fm::FolderView::CompactMode); +} + +void MainWindow::on_actionDetailedList_triggered() { + currentPage()->setViewMode(Fm::FolderView::DetailedListMode); +} + +void MainWindow::on_actionThumbnailView_triggered() { + currentPage()->setViewMode(Fm::FolderView::ThumbnailMode); +} + +void MainWindow::onTabBarCloseRequested(int index) { + closeTab(index); +} + +void MainWindow::onTabBarTabMoved(int from, int to) { + // a tab in the tab bar is moved by the user, so we have to move the + // corredponding tab page in the stacked widget to the new position, too. + QWidget* page = ui.stackedWidget->widget(from); + if(page) { + // we're not going to delete the tab page, so here we block signals + // to avoid calling the slot onStackedWidgetWidgetRemoved() before + // removing the page. Otherwise the page widget will be destroyed. + ui.stackedWidget->blockSignals(true); + ui.stackedWidget->removeWidget(page); + ui.stackedWidget->insertWidget(to, page); // insert the page to the new position + ui.stackedWidget->blockSignals(false); // unblock signals + ui.stackedWidget->setCurrentWidget(page); + } +} + +void MainWindow::closeTab(int index) { + QWidget* page = ui.stackedWidget->widget(index); + if(page) { + ui.stackedWidget->removeWidget(page); // this does not delete the page widget + delete page; + // NOTE: we do not remove the tab here. + // it'll be donoe in onStackedWidgetWidgetRemoved() + } +} + +void MainWindow::resizeEvent(QResizeEvent *event) { + QMainWindow::resizeEvent(event); + Settings& settings = static_cast(qApp)->settings(); + if(settings.rememberWindowSize()) { + settings.setLastWindowMaximized(isMaximized()); + + if(!isMaximized()) { + settings.setLastWindowWidth(width()); + settings.setLastWindowHeight(height()); + } + } +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + QWidget::closeEvent(event); + Settings& settings = static_cast(qApp)->settings(); + if(settings.rememberWindowSize()) { + settings.setLastWindowMaximized(isMaximized()); + + if(!isMaximized()) { + settings.setLastWindowWidth(width()); + settings.setLastWindowHeight(height()); + } + } +} + +void MainWindow::onTabBarCurrentChanged(int index) { + ui.stackedWidget->setCurrentIndex(index); + updateUIForCurrentPage(); +} + +void MainWindow::updateStatusBarForCurrentPage() { + TabPage* tabPage = currentPage(); + QString text = tabPage->statusText(TabPage::StatusTextSelectedFiles); + if(text.isEmpty()) + text = tabPage->statusText(TabPage::StatusTextNormal); + ui.statusbar->showMessage(text); + + text = tabPage->statusText(TabPage::StatusTextFSInfo); + fsInfoLabel->setText(text); + fsInfoLabel->setVisible(!text.isEmpty()); +} + +void MainWindow::updateViewMenuForCurrentPage() { + TabPage* tabPage = currentPage(); + + if(tabPage) { + // update menus. FIXME: should we move this to another method? + ui.actionShowHidden->setChecked(tabPage->showHidden()); + + // view mode + QAction* modeAction = NULL; + + switch(tabPage->viewMode()) { + case Fm::FolderView::IconMode: + modeAction = ui.actionIconView; + break; + + case Fm::FolderView::CompactMode: + modeAction = ui.actionCompactView; + break; + + case Fm::FolderView::DetailedListMode: + modeAction = ui.actionDetailedList; + break; + + case Fm::FolderView::ThumbnailMode: + modeAction = ui.actionThumbnailView; + break; + } + + Q_ASSERT(modeAction != NULL); + modeAction->setChecked(true); + + // sort menu + QAction* sortActions[Fm::FolderModel::NumOfColumns]; + sortActions[Fm::FolderModel::ColumnFileName] = ui.actionByFileName; + sortActions[Fm::FolderModel::ColumnFileMTime] = ui.actionByMTime; + sortActions[Fm::FolderModel::ColumnFileSize] = ui.actionByFileSize; + sortActions[Fm::FolderModel::ColumnFileType] = ui.actionByFileType; + sortActions[Fm::FolderModel::ColumnFileOwner] = ui.actionByOwner; + sortActions[tabPage->sortColumn()]->setChecked(true); + + if(tabPage->sortOrder() == Qt::AscendingOrder) + ui.actionAscending->setChecked(true); + else + ui.actionDescending->setChecked(true); + + ui.actionCaseSensitive->setChecked(tabPage->sortCaseSensitive()); + ui.actionFolderFirst->setChecked(tabPage->sortFolderFirst()); + } +} + +void MainWindow::updateUIForCurrentPage() { + TabPage* tabPage = currentPage(); + + if(tabPage) { + setWindowTitle(tabPage->title()); + pathEntry->setText(tabPage->pathName()); + ui.statusbar->showMessage(tabPage->statusText()); + fsInfoLabel->setText(tabPage->statusText(TabPage::StatusTextFSInfo)); + tabPage->folderView()->childView()->setFocus(); + + // update side pane + ui.sidePane->setCurrentPath(tabPage->path()); + + // update back/forward/up toolbar buttons + ui.actionGoUp->setEnabled(tabPage->canUp()); + ui.actionGoBack->setEnabled(tabPage->canBackward()); + ui.actionGoForward->setEnabled(tabPage->canForward()); + + updateViewMenuForCurrentPage(); + updateStatusBarForCurrentPage(); + } +} + + +void MainWindow::onStackedWidgetWidgetRemoved(int index) { + // qDebug("onStackedWidgetWidgetRemoved: %d", index); + // need to remove associated tab from tabBar + ui.tabBar->removeTab(index); + if(ui.tabBar->count() == 0) { // this is the last one + deleteLater(); // destroy the whole window + // qDebug("delete window"); + } + else { + Settings& settings = static_cast(qApp)->settings(); + if(!settings.alwaysShowTabs() && ui.tabBar->count() == 1) { + ui.tabBar->setVisible(false); + } + } +} + +void MainWindow::onTabPageTitleChanged(QString title) { + TabPage* tabPage = static_cast(sender()); + int index = ui.stackedWidget->indexOf(tabPage); + + if(index >= 0) + ui.tabBar->setTabText(index, title); + + if(tabPage == currentPage()) + setWindowTitle(title); +} + +void MainWindow::onTabPageStatusChanged(int type, QString statusText) { + TabPage* tabPage = static_cast(sender()); + if(tabPage == currentPage()) { + switch(type) { + case TabPage::StatusTextNormal: + case TabPage::StatusTextSelectedFiles: { + // FIXME: updating the status text so frequently is a little bit ineffiecient + QString text = statusText = tabPage->statusText(TabPage::StatusTextSelectedFiles); + if(text.isEmpty()) + ui.statusbar->showMessage(tabPage->statusText(TabPage::StatusTextNormal)); + else + ui.statusbar->showMessage(text); + break; + } + case TabPage::StatusTextFSInfo: + fsInfoLabel->setText(tabPage->statusText(TabPage::StatusTextFSInfo)); + fsInfoLabel->setVisible(!statusText.isEmpty()); + break; + } + } +} + +void MainWindow::onTabPageOpenDirRequested(FmPath* path, int target) { + switch(target) { + case View::OpenInCurrentView: + chdir(path); + break; + + case View::OpenInNewTab: + addTab(path); + break; + + case View::OpenInNewWindow: { + Application* app = static_cast(qApp); + MainWindow* newWin = new MainWindow(path); + // TODO: apply window size from app->settings + newWin->resize(app->settings().windowWidth(), app->settings().windowHeight()); + + if(app->settings().windowMaximized()) + newWin->setWindowState(newWin->windowState() | Qt::WindowMaximized); + + newWin->show(); + break; + } + } +} + +void MainWindow::onTabPageSortFilterChanged() { + TabPage* tabPage = static_cast(sender()); + + if(tabPage == currentPage()) { + updateViewMenuForCurrentPage(); + } +} + + +void MainWindow::onSidePaneChdirRequested(int type, FmPath* path) { + // FIXME: use enum for type value or change it to button. + if(type == 0) // left button (default) + chdir(path); + else if(type == 1) // middle button + addTab(path); +} + +void MainWindow::onSplitterMoved(int pos, int index) { + Application* app = static_cast(qApp); + app->settings().setSplitterPos(pos); +} + +void MainWindow::loadBookmarksMenu() { + GList* l = fm_bookmarks_get_all(bookmarks); + QAction* before = ui.actionAddToBookmarks; + + for(; l; l = l->next) { + FmBookmarkItem* item = reinterpret_cast(l->data); + BookmarkAction* action = new BookmarkAction(item); + connect(action, &QAction::triggered, this, &MainWindow::onBookmarkActionTriggered); + ui.menu_Bookmarks->insertAction(before, action); + } + + ui.menu_Bookmarks->insertSeparator(before); +} + +void MainWindow::onBookmarksChanged(FmBookmarks* bookmarks, MainWindow* pThis) { + // delete existing items + QList actions = pThis->ui.menu_Bookmarks->actions(); + QList::const_iterator it = actions.begin(); + QList::const_iterator last_it = actions.end() - 2; + + while(it != last_it) { + QAction* action = *it; + ++it; + pThis->ui.menu_Bookmarks->removeAction(action); + } + + pThis->loadBookmarksMenu(); +} + +void MainWindow::onBookmarkActionTriggered() { + BookmarkAction* action = static_cast(sender()); + FmPath* path = action->path(); + + if(path) + chdir(path); +} + +void MainWindow::on_actionCopy_triggered() { + TabPage* page = currentPage(); + FmPathList* paths = page->selectedFilePaths(); + copyFilesToClipboard(paths); + fm_path_list_unref(paths); +} + +void MainWindow::on_actionCut_triggered() { + TabPage* page = currentPage(); + FmPathList* paths = page->selectedFilePaths(); + cutFilesToClipboard(paths); + fm_path_list_unref(paths); +} + +void MainWindow::on_actionPaste_triggered() { + pasteFilesFromClipboard(currentPage()->path(), this); +} + +void MainWindow::on_actionDelete_triggered() { + Application* app = static_cast(qApp); + Settings& settings = app->settings(); + TabPage* page = currentPage(); + FmPathList* paths = page->selectedFilePaths(); + + bool shiftPressed = (qApp->keyboardModifiers() & Qt::ShiftModifier ? true : false); + if(settings.useTrash() && !shiftPressed) + FileOperation::trashFiles(paths, settings.confirmDelete(), this); + else + FileOperation::deleteFiles(paths, settings.confirmDelete(), this); + + fm_path_list_unref(paths); +} + +void MainWindow::on_actionRename_triggered() { + TabPage* page = currentPage(); + FmFileInfoList* files = page->selectedFiles(); + + for(GList* l = fm_file_info_list_peek_head_link(files); l; l = l->next) { + FmFileInfo* file = FM_FILE_INFO(l->data); + Fm::renameFile(file, NULL); + } + fm_file_info_list_unref(files); +} + + +void MainWindow::on_actionSelectAll_triggered() { + currentPage()->selectAll(); +} + +void MainWindow::on_actionInvertSelection_triggered() { + currentPage()->invertSelection(); +} + +void MainWindow::on_actionPreferences_triggered() { + Application* app = reinterpret_cast(qApp); + app->preferences(QString()); +} + +/* +void MainWindow::changeEvent(QEvent* event) { + switch(event->type()) { + case QEvent::StyleChange: + break; + } + QWidget::changeEvent(event); +} +*/ + +void MainWindow::onBackForwardContextMenu(QPoint pos) { + // show a popup menu for browsing history here. + QToolButton* btn = static_cast(sender()); + TabPage* page = currentPage(); + Fm::BrowseHistory& history = page->browseHistory(); + int current = history.currentIndex(); + QMenu menu; + for(int i = 0; i < history.size(); ++i) { + const BrowseHistoryItem& item = history.at(i); + Fm::Path path = item.path(); + QAction* action = menu.addAction(path.displayName()); + if(i == current) { + // make the current path bold and checked + action->setCheckable(true); + action->setChecked(true); + QFont font = menu.font(); + font.setBold(true); + action->setFont(font); + } + } + QAction* selectedAction = menu.exec(btn->mapToGlobal(pos)); + if(selectedAction) { + int index = menu.actions().indexOf(selectedAction); + page->jumpToHistory(index); + updateUIForCurrentPage(); + } +} + +void MainWindow::updateFromSettings(Settings& settings) { + // apply settings + + // menu + ui.actionDelete->setText(settings.useTrash() ? tr("&Move to Trash") : tr("&Delete")); + + // side pane + ui.sidePane->setIconSize(QSize(settings.sidePaneIconSize(), settings.sidePaneIconSize())); + + // tabs + ui.tabBar->setTabsClosable(settings.showTabClose()); + + if(!settings.alwaysShowTabs()) { + ui.tabBar->setVisible(ui.tabBar->count() > 1); + } + + // all tab pages + int n = ui.stackedWidget->count(); + + for(int i = 0; i < n; ++i) { + TabPage* page = static_cast(ui.stackedWidget->widget(i)); + page->updateFromSettings(settings); + } +} + +static const char* su_cmd_subst(char opt, gpointer user_data) { + return (const char*)user_data; +} + +static FmAppCommandParseOption su_cmd_opts[] = { + { 's', su_cmd_subst }, + { 0, NULL } +}; + +void MainWindow::on_actionOpenAsRoot_triggered() { + TabPage* page = currentPage(); + + if(page) { + Application* app = static_cast(qApp); + Settings& settings = app->settings(); + + if(!settings.suCommand().isEmpty()) { + // run the su command + // FIXME: it's better to get the filename of the current process rather than hard-code pcmanfm-qt here. + QByteArray suCommand = settings.suCommand().toLocal8Bit(); + char* cmd = NULL; + QByteArray programCommand = app->applicationFilePath().toLocal8Bit(); + programCommand += " %U"; + + if(fm_app_command_parse(suCommand.constData(), su_cmd_opts, &cmd, gpointer(programCommand.constData())) == 0) { + /* no %s found so just append to it */ + g_free(cmd); + cmd = g_strconcat(suCommand.constData(), programCommand.constData(), NULL); + } + + GAppInfo* appInfo = g_app_info_create_from_commandline(cmd, NULL, GAppInfoCreateFlags(0), NULL); + g_free(cmd); + + if(appInfo) { + FmPath* cwd = page->path(); + GError* err = NULL; + char* uri = fm_path_to_uri(cwd); + GList* uris = g_list_prepend(NULL, uri); + + if(!g_app_info_launch_uris(appInfo, uris, NULL, &err)) { + QMessageBox::critical(this, tr("Error"), QString::fromUtf8(err->message)); + g_error_free(err); + } + + g_list_free(uris); + g_free(uri); + g_object_unref(appInfo); + } + } + else { + // show an error message and ask the user to set the command + QMessageBox::critical(this, tr("Error"), tr("Switch user command is not set.")); + app->preferences("advanced"); + } + } +} + +void MainWindow::on_actionOpenTerminal_triggered() { + TabPage* page = currentPage(); + if(page) { + Application* app = static_cast(qApp); + app->openFolderInTerminal(page->path()); + } +} + +void MainWindow::onShortcutNextTab() { + int current = ui.tabBar->currentIndex(); + if(current < ui.tabBar->count() - 1) + ui.tabBar->setCurrentIndex(current + 1); + else + ui.tabBar->setCurrentIndex(0); +} + +void MainWindow::onShortcutPrevTab() { + int current = ui.tabBar->currentIndex(); + if(current > 0) + ui.tabBar->setCurrentIndex(current - 1); + else + ui.tabBar->setCurrentIndex(ui.tabBar->count() - 1); +} + +// Switch to nth tab when Alt+n or Ctrl+n is pressed +void MainWindow::onShortcutJumpToTab() { + QShortcut* shortcut = reinterpret_cast(sender()); + QKeySequence seq = shortcut->key(); + int keyValue = seq[0]; + // See the source code of QKeySequence and refer to the method: + // QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat format). + // Then we know how to test if a key sequence contains a modifier. + // It's a shame that Qt has no API for this task. + + if((keyValue & Qt::ALT) == Qt::ALT) // test if we have Alt key pressed + keyValue -= Qt::ALT; + else if((keyValue & Qt::CTRL) == Qt::CTRL) // test if we have Ctrl key pressed + keyValue -= Qt::CTRL; + + // now keyValue should contains '0' - '9' only + int index; + if(keyValue == '0') + index = 9; + else + index = keyValue - '1'; + if(index < ui.tabBar->count()) + ui.tabBar->setCurrentIndex(index); +} + +} diff --git a/pcmanfm/mainwindow.h b/pcmanfm/mainwindow.h new file mode 100644 index 0000000..9dd938e --- /dev/null +++ b/pcmanfm/mainwindow.h @@ -0,0 +1,158 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_MAIN_WINDOW_H +#define FM_MAIN_WINDOW_H + +#include "ui_main-win.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "launcher.h" + +namespace PCManFM { + +class TabPage; +class Settings; + +class MainWindow : public QMainWindow { +Q_OBJECT +public: + MainWindow(FmPath* path = NULL); + virtual ~MainWindow(); + + void chdir(FmPath* path); + void addTab(FmPath* path); + + TabPage* currentPage() { + return reinterpret_cast(ui.stackedWidget->currentWidget()); + } + + void updateFromSettings(Settings& settings); + +protected Q_SLOTS: + + void onPathEntryReturnPressed(); + + void on_actionNewTab_triggered(); + void on_actionNewWin_triggered(); + void on_actionCloseTab_triggered(); + void on_actionCloseWindow_triggered(); + void on_actionFileProperties_triggered(); + void on_actionFolderProperties_triggered(); + + void on_actionCut_triggered(); + void on_actionCopy_triggered(); + void on_actionPaste_triggered(); + void on_actionDelete_triggered(); + void on_actionRename_triggered(); + void on_actionSelectAll_triggered(); + void on_actionInvertSelection_triggered(); + void on_actionPreferences_triggered(); + + void on_actionGoBack_triggered(); + void on_actionGoForward_triggered(); + void on_actionGoUp_triggered(); + void on_actionHome_triggered(); + void on_actionReload_triggered(); + + void on_actionIconView_triggered(); + void on_actionCompactView_triggered(); + void on_actionDetailedList_triggered(); + void on_actionThumbnailView_triggered(); + + void on_actionGo_triggered(); + void on_actionShowHidden_triggered(bool check); + + void on_actionByFileName_triggered(bool checked); + void on_actionByMTime_triggered(bool checked); + void on_actionByOwner_triggered(bool checked); + void on_actionByFileType_triggered(bool checked); + void on_actionByFileSize_triggered(bool checked); + void on_actionAscending_triggered(bool checked); + void on_actionDescending_triggered(bool checked); + void on_actionFolderFirst_triggered(bool checked); + void on_actionCaseSensitive_triggered(bool checked); + + void on_actionApplications_triggered(); + void on_actionComputer_triggered(); + void on_actionTrash_triggered(); + void on_actionNetwork_triggered(); + void on_actionDesktop_triggered(); + void on_actionAddToBookmarks_triggered(); + void on_actionEditBookmarks_triggered(); + + void on_actionOpenTerminal_triggered(); + void on_actionOpenAsRoot_triggered(); + + void on_actionAbout_triggered(); + + void onBookmarkActionTriggered(); + + void onTabBarCloseRequested(int index); + void onTabBarCurrentChanged(int index); + void onTabBarTabMoved(int from, int to); + + void onShortcutPrevTab(); + void onShortcutNextTab(); + void onShortcutJumpToTab(); + + void onStackedWidgetWidgetRemoved(int index); + + void onTabPageTitleChanged(QString title); + void onTabPageStatusChanged(int type, QString statusText); + void onTabPageOpenDirRequested(FmPath* path, int target); + void onTabPageSortFilterChanged(); + + void onSidePaneChdirRequested(int type, FmPath* path); + void onSplitterMoved(int pos, int index); + + void onBackForwardContextMenu(QPoint pos); + +protected: + // void changeEvent( QEvent * event); + void closeTab(int index); + virtual void resizeEvent(QResizeEvent *event); + virtual void closeEvent(QCloseEvent *event); + +private: + static void onBookmarksChanged(FmBookmarks* bookmarks, MainWindow* pThis); + void loadBookmarksMenu(); + void updateUIForCurrentPage(); + void updateViewMenuForCurrentPage(); + void updateStatusBarForCurrentPage(); + +private: + Ui::MainWindow ui; + QLineEdit* pathEntry; + QLabel* fsInfoLabel; + FmBookmarks* bookmarks; + Launcher fileLauncher_; +}; + +} + +#endif // FM_MAIN_WINDOW_H diff --git a/pcmanfm/org.pcmanfm.Application.xml b/pcmanfm/org.pcmanfm.Application.xml new file mode 100644 index 0000000..5a0f8dc --- /dev/null +++ b/pcmanfm/org.pcmanfm.Application.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcmanfm/pcmanfm-qt-desktop-pref.desktop.in b/pcmanfm/pcmanfm-qt-desktop-pref.desktop.in new file mode 100644 index 0000000..c3c0cdf --- /dev/null +++ b/pcmanfm/pcmanfm-qt-desktop-pref.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=Desktop +GenericName=Desktop Settings +Comment=Change wallpapers and behavior of desktop manager +Exec=pcmanfm-qt --desktop-pref=general +Icon=user-desktop +Categories=Qt;DesktopSettings; +StartupNotify=true diff --git a/pcmanfm/pcmanfm-qt.desktop.in b/pcmanfm/pcmanfm-qt.desktop.in new file mode 100644 index 0000000..0b1a75a --- /dev/null +++ b/pcmanfm/pcmanfm-qt.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=PCManFM File Manager +GenericName=File Manager +Comment=Browse the file system and manage the files +Exec=pcmanfm-qt %U +MimeType=inode/directory; +Icon=system-file-manager +Categories=FileManager;Utility;Core;Qt; +StartupNotify=true diff --git a/pcmanfm/pcmanfm.cpp b/pcmanfm/pcmanfm.cpp new file mode 100644 index 0000000..4e42976 --- /dev/null +++ b/pcmanfm/pcmanfm.cpp @@ -0,0 +1,9 @@ +#include +#include "application.h" +#include "libfmqt.h" + +int main(int argc, char** argv) { + PCManFM::Application app(argc, argv); + app.init(); + return app.exec(); +} diff --git a/pcmanfm/preferences.ui b/pcmanfm/preferences.ui new file mode 100644 index 0000000..fc9e2e4 --- /dev/null +++ b/pcmanfm/preferences.ui @@ -0,0 +1,698 @@ + + + PreferencesDialog + + + + 0 + 0 + 736 + 497 + + + + Preferences + + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + 0 + + + + User Interface + + + + + Behavior + + + + + Thumbnail + + + + + Volume + + + + + Advanced + + + + + + + + + 0 + 0 + + + + 0 + + + + + + + Icons + + + + + + Size of big icons: + + + + + + + + + + Size of small icons: + + + + + + + + + + Size of thumbnails: + + + + + + + + + + Size of side pane icons: + + + + + + + + + + + 0 + 0 + + + + Icon theme: + + + + + + + + 0 + 0 + + + + + + + + + + + Window + + + + QFormLayout::ExpandingFieldsGrow + + + + + Always show the tab bar + + + + + + + Show 'Close' buttons on tabs + + + + + + + Remember the size of the last closed window + + + + + + + Default width of new windows: + + + + + + + Default height of new windows: + + + + + + + 32768 + + + + + + + 32768 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Browsing + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Open files with single click + + + + + + + false + + + Delay of auto-selection in single click mode (0 to disable) + + + + + + + Default view mode: + + + + + + + + + + false + + + sec + + + 0.100000000000000 + + + + + + + + + + File Operations + + + + + + Confirm before deleting files + + + + + + + Move deleted files to "trash bin" instead of erasing from disk. + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Show thumbnails of files + + + + + + + Only show thumbnails for local files + + + + + + + Do not generate thumbnails for image files exceeding this size: + + + + + + + KB + + + 1048576 + + + + + + + + + + + Auto Mount + + + + + + Mount mountable volumes automatically on program startup + + + + + + + Mount removable media automatically when they are inserted + + + + + + + Show available options for removable media when they are inserted + + + + + + + + + + When removable medium unmounted: + + + + + + Close tab containing removable medium + + + + + + + Change folder in the tab to home folder + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Programs + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Terminal emulator: + + + + + + + Switch user command: + + + suCommand + + + + + + + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + + + Qt::PlainText + + + + + + + Archiver integration: + + + archiver + + + + + + + + + + true + + + + + + + + + + false + + + Use SI decimal prefixes instead of IEC binary prefixes + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + smallIconSize + bigIconSize + thumbnailIconSize + sidePaneIconSize + iconTheme + alwaysShowTabs + showTabClose + singleClick + viewMode + configmDelete + useTrash + showThumbnails + mountOnStartup + suCommand + archiver + siUnit + autoRun + mountRemovable + buttonBox + listWidget + thumbnailLocal + maxThumbnailFileSize + + + + + buttonBox + accepted() + PreferencesDialog + accept() + + + 261 + 487 + + + 157 + 274 + + + + + buttonBox + rejected() + PreferencesDialog + reject() + + + 329 + 487 + + + 286 + 274 + + + + + listWidget + currentRowChanged(int) + stackedWidget + setCurrentIndex(int) + + + 94 + 157 + + + 359 + 145 + + + + + singleClick + toggled(bool) + label + setEnabled(bool) + + + 237 + 39 + + + 237 + 39 + + + + + rememberWindowSize + toggled(bool) + fixedWindowWidth + setDisabled(bool) + + + 506 + 351 + + + 462 + 386 + + + + + singleClick + toggled(bool) + autoSelectionDelay + setEnabled(bool) + + + 237 + 39 + + + 237 + 39 + + + + + rememberWindowSize + toggled(bool) + fixedWindowHeight + setDisabled(bool) + + + 549 + 351 + + + 462 + 421 + + + + + rememberWindowSize + toggled(bool) + label_12 + setDisabled(bool) + + + 211 + 342 + + + 211 + 374 + + + + + rememberWindowSize + toggled(bool) + label_13 + setDisabled(bool) + + + 183 + 338 + + + 187 + 404 + + + + + diff --git a/pcmanfm/preferencesdialog.cpp b/pcmanfm/preferencesdialog.cpp new file mode 100644 index 0000000..a327c95 --- /dev/null +++ b/pcmanfm/preferencesdialog.cpp @@ -0,0 +1,318 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "preferencesdialog.h" +#include "application.h" +#include "settings.h" +#include +#include +#include +#include + +#include "folderview.h" + +using namespace PCManFM; + +static int bigIconSizes[] = {96, 72, 64, 48, 36, 32, 24, 20}; +static int smallIconSizes[] = {48, 36, 32, 24, 20, 16, 12}; +static int thumbnailIconSizes[] = {256, 224, 192, 160, 128, 96, 64}; + +PreferencesDialog::PreferencesDialog (QString activePage, QWidget* parent): + QDialog (parent) { + ui.setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + // resize the list widget according to the width of its content. + ui.listWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + ui.listWidget->setMaximumWidth(ui.listWidget->sizeHintForColumn(0) + ui.listWidget->frameWidth() * 2 + 4); + + initFromSettings(); + + if(!activePage.isEmpty()) { + QWidget* page = findChild(activePage + "Page"); + if(page) { + int index = ui.stackedWidget->indexOf(page); + ui.listWidget->setCurrentRow(index); + } + } + adjustSize(); +} + +PreferencesDialog::~PreferencesDialog() { + +} + +static void findIconThemesInDir(QHash& iconThemes, QString dirName) { + QDir dir(dirName); + QStringList subDirs = dir.entryList(QDir::AllDirs); + GKeyFile* kf = g_key_file_new(); + Q_FOREACH(QString subDir, subDirs) { + QString indexFile = dirName % '/' % subDir % "/index.theme"; + if(g_key_file_load_from_file(kf, indexFile.toLocal8Bit().constData(), GKeyFileFlags(0), NULL)) { + // FIXME: skip hidden ones + // icon theme must have this key, so it has icons if it has this key + // otherwise, it might be a cursor theme or any other kind of theme. + if(g_key_file_has_key(kf, "Icon Theme", "Directories", NULL)) { + char* dispName = g_key_file_get_locale_string(kf, "Icon Theme", "Name", NULL, NULL); + // char* comment = g_key_file_get_locale_string(kf, "Icon Theme", "Comment", NULL, NULL); + iconThemes[subDir] = dispName; + g_free(dispName); + } + } + } + g_key_file_free(kf); +} + +void PreferencesDialog::initIconThemes(Settings& settings) { + Application* app = static_cast(qApp); + + // check if auto-detection is done (for example, from xsettings) + if(settings.useFallbackIconTheme()) { // auto-detection failed + // load xdg icon themes and select the current one + QHash iconThemes; + // user customed icon themes + findIconThemesInDir(iconThemes, QString(g_get_home_dir()) % "/.icons"); + + // search for icons in system data dir + const char* const* dataDirs = g_get_system_data_dirs(); + for(const char* const* dataDir = dataDirs; *dataDir; ++dataDir) { + findIconThemesInDir(iconThemes, QString(*dataDir) % "/icons"); + } + + iconThemes.remove("hicolor"); // remove hicolor, which is only a fallback + QHash::const_iterator it; + for(it = iconThemes.begin(); it != iconThemes.end(); ++it) { + ui.iconTheme->addItem(it.value(), it.key()); + } + ui.iconTheme->model()->sort(0); // sort the list of icon theme names + + // select current theme name + int n = ui.iconTheme->count(); + int i; + for(i = 0; i < n; ++i) { + QVariant itemData = ui.iconTheme->itemData(i); + if(itemData == settings.fallbackIconThemeName()) { + break; + } + } + if(i >= n) + i = 0; + ui.iconTheme->setCurrentIndex(i); + } + else { // auto-detection of icon theme works, hide the fallback icon theme combo box. + ui.iconThemeLabel->hide(); + ui.iconTheme->hide(); + } +} + +void PreferencesDialog::initArchivers(Settings& settings) { + const GList* allArchivers = fm_archiver_get_all(); + int i = 0; + for(const GList* l = allArchivers; l; l = l->next, ++i) { + FmArchiver* archiver = reinterpret_cast(l->data); + ui.archiver->addItem(archiver->program, QString(archiver->program)); + if(archiver->program == settings.archiver()) + ui.archiver->setCurrentIndex(i); + } +} + +void PreferencesDialog::initUiPage(Settings& settings) { + initIconThemes(settings); + // icon sizes + int i; + for(i = 0; i < G_N_ELEMENTS(bigIconSizes); ++i) { + int size = bigIconSizes[i]; + ui.bigIconSize->addItem(QString("%1 x %1").arg(size), size); + if(settings.bigIconSize() == size) + ui.bigIconSize->setCurrentIndex(i); + } + for(i = 0; i < G_N_ELEMENTS(smallIconSizes); ++i) { + int size = smallIconSizes[i]; + QString text = QString("%1 x %1").arg(size); + ui.smallIconSize->addItem(text, size); + if(settings.smallIconSize() == size) + ui.smallIconSize->setCurrentIndex(i); + + ui.sidePaneIconSize->addItem(text, size); + if(settings.sidePaneIconSize() == size) + ui.sidePaneIconSize->setCurrentIndex(i); + } + for(i = 0; i < G_N_ELEMENTS(thumbnailIconSizes); ++i) { + int size = thumbnailIconSizes[i]; + ui.thumbnailIconSize->addItem(QString("%1 x %1").arg(size), size); + if(settings.thumbnailIconSize() == size) + ui.thumbnailIconSize->setCurrentIndex(i); + } + + ui.alwaysShowTabs->setChecked(settings.alwaysShowTabs()); + ui.showTabClose->setChecked(settings.showTabClose()); + ui.rememberWindowSize->setChecked(settings.rememberWindowSize()); + ui.fixedWindowWidth->setValue(settings.fixedWindowWidth()); + ui.fixedWindowHeight->setValue(settings.fixedWindowHeight()); +} + +void PreferencesDialog::initBehaviorPage(Settings& settings) { + ui.singleClick->setChecked(settings.singleClick()); + ui.autoSelectionDelay->setValue(double(settings.autoSelectionDelay()) / 1000); + + ui.viewMode->addItem(tr("Icon View"), (int)Fm::FolderView::IconMode); + ui.viewMode->addItem(tr("Compact Icon View"), (int)Fm::FolderView::CompactMode); + ui.viewMode->addItem(tr("Thumbnail View"), (int)Fm::FolderView::ThumbnailMode); + ui.viewMode->addItem(tr("Detailed List View"), (int)Fm::FolderView::DetailedListMode); + const Fm::FolderView::ViewMode modes[] = { + Fm::FolderView::IconMode, + Fm::FolderView::CompactMode, + Fm::FolderView::ThumbnailMode, + Fm::FolderView::DetailedListMode + }; + for(int i = 0; i < G_N_ELEMENTS(modes); ++i) { + if(modes[i] == settings.viewMode()) { + ui.viewMode->setCurrentIndex(i); + break; + } + } + + ui.configmDelete->setChecked(settings.confirmDelete()); + + if(settings.supportTrash()) + ui.useTrash->setChecked(settings.useTrash()); + else { + ui.useTrash->hide(); + } +} + +void PreferencesDialog::initThumbnailPage(Settings& settings) { + ui.showThumbnails->setChecked(settings.showThumbnails()); + ui.thumbnailLocal->setChecked(settings.thumbnailLocalFilesOnly()); + ui.maxThumbnailFileSize->setValue(settings.maxThumbnailFileSize()); +} + +void PreferencesDialog::initVolumePage(Settings& settings) { + ui.mountOnStartup->setChecked(settings.mountOnStartup()); + ui.mountRemovable->setChecked(settings.mountRemovable()); + ui.autoRun->setChecked(settings.autoRun()); + if(settings.closeOnUnmount()) + ui.closeOnUnmount->setChecked(true); + else + ui.goHomeOnUnmount->setChecked(true); +} + +void PreferencesDialog::initTerminals(Settings& settings) { + // load the known terminal list from the terminal.list file of libfm + QSettings termlist(LIBFM_DATA_DIR "/terminals.list", QSettings::IniFormat); + ui.terminal->addItems(termlist.childGroups()); + ui.terminal->setEditText(settings.terminal()); +} + +void PreferencesDialog::initAdvancedPage(Settings& settings) { + initArchivers(settings); + initTerminals(settings); + ui.suCommand->setText(settings.suCommand()); + // ui.siUnit->setChecked(settings.siUnit()); +} + +void PreferencesDialog::initFromSettings() { + Settings& settings = static_cast(qApp)->settings(); + initUiPage(settings); + initBehaviorPage(settings); + initThumbnailPage(settings); + initVolumePage(settings); + initAdvancedPage(settings); +} + +void PreferencesDialog::applyUiPage(Settings& settings) { + if(settings.useFallbackIconTheme()) { + // only apply the value if icon theme combo box is in use + // the combo box is hidden when auto-detection of icon theme from xsettings works. + QString newIconTheme = ui.iconTheme->itemData(ui.iconTheme->currentIndex()).toString(); + if(newIconTheme != settings.fallbackIconThemeName()) { + settings.setFallbackIconThemeName(newIconTheme); + QIcon::setThemeName(settings.fallbackIconThemeName()); + // update the UI by emitting a style change event + Q_FOREACH(QWidget *widget, QApplication::allWidgets()) { + QEvent event(QEvent::StyleChange); + QApplication::sendEvent(widget, &event); + } + } + } + + settings.setBigIconSize(ui.bigIconSize->itemData(ui.bigIconSize->currentIndex()).toInt()); + settings.setSmallIconSize(ui.smallIconSize->itemData(ui.smallIconSize->currentIndex()).toInt()); + settings.setThumbnailIconSize(ui.thumbnailIconSize->itemData(ui.thumbnailIconSize->currentIndex()).toInt()); + settings.setSidePaneIconSize(ui.sidePaneIconSize->itemData(ui.sidePaneIconSize->currentIndex()).toInt()); + settings.setAlwaysShowTabs(ui.alwaysShowTabs->isChecked()); + settings.setShowTabClose(ui.showTabClose->isChecked()); + settings.setRememberWindowSize(ui.rememberWindowSize->isChecked()); + settings.setFixedWindowWidth(ui.fixedWindowWidth->value()); + settings.setFixedWindowHeight(ui.fixedWindowHeight->value()); +} + +void PreferencesDialog::applyBehaviorPage(Settings& settings) { + settings.setSingleClick(ui.singleClick->isChecked()); + settings.setAutoSelectionDelay(int(ui.autoSelectionDelay->value() * 1000)); + // FIXME: bug here? + Fm::FolderView::ViewMode mode = Fm::FolderView::ViewMode(ui.viewMode->itemData(ui.viewMode->currentIndex()).toInt()); + settings.setViewMode(mode); + settings.setConfirmDelete(ui.configmDelete->isChecked()); + + if(settings.supportTrash()) + settings.setUseTrash(ui.useTrash->isChecked()); +} + +void PreferencesDialog::applyThumbnailPage(Settings& settings) { + settings.setShowThumbnails(ui.showThumbnails->isChecked()); + settings.setThumbnailLocalFilesOnly(ui.thumbnailLocal->isChecked()); + settings.setMaxThumbnailFileSize(ui.maxThumbnailFileSize->value()); +} + +void PreferencesDialog::applyVolumePage(Settings& settings) { + settings.setAutoRun(ui.autoRun->isChecked()); + settings.setMountOnStartup(ui.mountOnStartup->isChecked()); + settings.setMountRemovable(ui.mountRemovable->isChecked()); + settings.setCloseOnUnmount(ui.closeOnUnmount->isChecked()); +} + +void PreferencesDialog::applyAdvancedPage(Settings& settings) { + settings.setTerminal(ui.terminal->currentText()); + settings.setSuCommand(ui.suCommand->text()); + settings.setArchiver(ui.archiver->itemData(ui.archiver->currentIndex()).toString()); + settings.setSiUnit(ui.siUnit->isChecked()); +} + + +void PreferencesDialog::applySettings() { + Settings& settings = static_cast(qApp)->settings(); + applyUiPage(settings); + applyBehaviorPage(settings); + applyThumbnailPage(settings); + applyVolumePage(settings); + applyAdvancedPage(settings); + + settings.save(); + + Application* app = static_cast(qApp); + app->updateFromSettings(); +} + +void PreferencesDialog::accept() { + applySettings(); + QDialog::accept(); +} + diff --git a/pcmanfm/preferencesdialog.h b/pcmanfm/preferencesdialog.h new file mode 100644 index 0000000..5fad79d --- /dev/null +++ b/pcmanfm/preferencesdialog.h @@ -0,0 +1,68 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_PREFERENCESDIALOG_H +#define PCMANFM_PREFERENCESDIALOG_H + +#include +#include "ui_preferences.h" +#include + +namespace PCManFM +{ + +class Settings; + +class PreferencesDialog : public QDialog { +Q_OBJECT + +public: + // activePage is the name of page to select (general, display, advanced...) + explicit PreferencesDialog(QString activePage = QString(), QWidget* parent = 0); + virtual ~PreferencesDialog(); + + virtual void accept(); + +private: + void initIconThemes(Settings& settings); + void initArchivers(Settings& settings); + void initUiPage(Settings& settings); + void initBehaviorPage(Settings& settings); + void initThumbnailPage(Settings& settings); + void initVolumePage(Settings& settings); + void initAdvancedPage(Settings& settings); + void initTerminals(Settings& settings); + + void applyUiPage(Settings& settings); + void applyBehaviorPage(Settings& settings); + void applyThumbnailPage(Settings& settings); + void applyVolumePage(Settings& settings); + void applyAdvancedPage(Settings& settings); + + void initFromSettings(); + void applySettings(); + +private: + Ui::PreferencesDialog ui; +}; + +} + +#endif // PCMANFM_PREFERENCESDIALOG_H diff --git a/pcmanfm/settings.cpp b/pcmanfm/settings.cpp new file mode 100644 index 0000000..8598d3a --- /dev/null +++ b/pcmanfm/settings.cpp @@ -0,0 +1,446 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "settings.h" +#include +#include +#include +#include +#include +#include "desktopwindow.h" +#include "utilities.h" +// #include + +using namespace PCManFM; + +inline static const char* bookmarkOpenMethodToString(int value); +inline static int bookmarkOpenMethodFromString(const QString str); + +inline static const char* wallpaperModeToString(int value); +inline static int wallpaperModeFromString(const QString str); + +inline static const char* viewModeToString(Fm::FolderView::ViewMode value); +inline static Fm::FolderView::ViewMode viewModeFromString(const QString str); + +inline static const char* sidePaneModeToString(int value); +inline static int sidePaneModeFromString(const QString str); + +inline static const char* sortOrderToString(Qt::SortOrder order); +inline static Qt::SortOrder sortOrderFromString(const QString str); + +inline static const char* sortColumnToString(Fm::FolderModel::ColumnId value); +inline static Fm::FolderModel::ColumnId sortColumnFromString(const QString str); + +Settings::Settings(): + QObject(), + supportTrash_(Fm::isUriSchemeSupported("trash")), + fallbackIconThemeName_(), + useFallbackIconTheme_(QIcon::themeName().isEmpty() || QIcon::themeName() == "hicolor"), + bookmarkOpenMethod_(0), + suCommand_(), + terminal_(), + mountOnStartup_(true), + mountRemovable_(true), + autoRun_(true), + closeOnUnmount_(false), + wallpaperMode_(0), + wallpaper_(), + desktopBgColor_(), + desktopFgColor_(), + desktopShadowColor_(), + showWmMenu_(false), + desktopShowHidden_(false), + desktopSortOrder_(Qt::AscendingOrder), + desktopSortColumn_(Fm::FolderModel::ColumnFileName), + alwaysShowTabs_(true), + showTabClose_(true), + fixedWindowWidth_(640), + fixedWindowHeight_(480), + lastWindowWidth_(640), + lastWindowHeight_(480), + lastWindowMaximized_(false), + splitterPos_(120), + sidePaneMode_(0), + viewMode_(Fm::FolderView::IconMode), + showHidden_(false), + sortOrder_(Qt::AscendingOrder), + sortColumn_(Fm::FolderModel::ColumnFileName), + // settings for use with libfm + singleClick_(false), + autoSelectionDelay_(600), + useTrash_(true), + confirmDelete_(true), + noUsbTrash_(false), + showThumbnails_(true), + archiver_(), + siUnit_(false), + bigIconSize_(48), + smallIconSize_(24), + sidePaneIconSize_(24), + thumbnailIconSize_(128) { +} + +Settings::~Settings() { + +} + +QString Settings::profileDir(QString profile, bool useFallback) { + // NOTE: it's a shame that QDesktopServices does not handle XDG_CONFIG_HOME + // try user-specific config file first + QString dirName = QLatin1String(qgetenv("XDG_CONFIG_HOME")); + if (dirName.isEmpty()) + dirName = QDir::homePath() % QLatin1String("/.config"); + dirName = dirName % "/pcmanfm-qt/" % profile; + QDir dir(dirName); + + // if user config dir does not exist, try system-wide config dirs instead + if(!dir.exists() && useFallback) { + QString fallbackDir; + for(const char* const* configDir = g_get_system_config_dirs(); *configDir; ++configDir) { + fallbackDir = QString(*configDir) % "/pcmanfm-qt/" % profile; + dir.setPath(fallbackDir); + if(dir.exists()) { + dirName = fallbackDir; + break; + } + } + } + return dirName; +} + +bool Settings::load(QString profile) { + profileName_ = profile; + QString fileName = profileDir(profile, true) % "/settings.conf"; + return loadFile(fileName); +} + +bool Settings::save(QString profile) { + QString fileName = profileDir(profile.isEmpty() ? profileName_ : profile) % "/settings.conf"; + return saveFile(fileName); +} + +bool Settings::loadFile(QString filePath) { + QSettings settings(filePath, QSettings::IniFormat); + settings.beginGroup("System"); + fallbackIconThemeName_ = settings.value("FallbackIconThemeName").toString(); + if(fallbackIconThemeName_.isEmpty()) { + // FIXME: we should choose one from installed icon themes or get + // the value from XSETTINGS instead of hard code a fallback value. + fallbackIconThemeName_ = "elementary"; // fallback icon theme name + } + suCommand_ = settings.value("SuCommand", "gksu %s").toString(); + setTerminal(settings.value("Terminal", "xterm").toString()); + setArchiver(settings.value("Archiver", "file-roller").toString()); + setSiUnit(settings.value("SIUnit", false).toBool()); + settings.endGroup(); + + settings.beginGroup("Behavior"); + bookmarkOpenMethod_ = bookmarkOpenMethodFromString(settings.value("BookmarkOpenMethod").toString()); + // settings for use with libfm + useTrash_ = settings.value("UseTrash", true).toBool(); + singleClick_ = settings.value("SingleClick", false).toBool(); + autoSelectionDelay_ = settings.value("AutoSelectionDelay", 600).toInt(); + confirmDelete_ = settings.value("ConfirmDelete", true).toBool(); + noUsbTrash_ = settings.value("NoUsbTrash", false).toBool(); + fm_config->no_usb_trash = noUsbTrash_; // also set this to libfm since FmFileOpsJob reads this config value before trashing files. + // bool thumbnailLocal_; + // bool thumbnailMax; + settings.endGroup(); + + settings.beginGroup("Desktop"); + wallpaperMode_ = wallpaperModeFromString(settings.value("WallpaperMode").toString()); + wallpaper_ = settings.value("Wallpaper").toString(); + desktopBgColor_.setNamedColor(settings.value("BgColor", "#000000").toString()); + desktopFgColor_.setNamedColor(settings.value("FgColor", "#ffffff").toString()); + desktopShadowColor_.setNamedColor(settings.value("ShadowColor", "#000000").toString()); + if(settings.contains("Font")) + desktopFont_.fromString(settings.value("Font").toString()); + else + desktopFont_ = QApplication::font(); + showWmMenu_ = settings.value("ShowWmMenu", false).toBool(); + desktopShowHidden_ = settings.value("ShowHidden", false).toBool(); + + desktopSortOrder_ = sortOrderFromString(settings.value("SortOrder").toString()); + desktopSortColumn_ = sortColumnFromString(settings.value("SortColumn").toString()); + settings.endGroup(); + + settings.beginGroup("Volume"); + mountOnStartup_ = settings.value("MountOnStartup", true).toBool(); + mountRemovable_ = settings.value("MountRemovable", true).toBool(); + autoRun_ = settings.value("AutoRun", true).toBool(); + closeOnUnmount_ = settings.value("CloseOnUnmount", true).toBool(); + settings.endGroup(); + + settings.beginGroup("Thumbnail"); + showThumbnails_ = settings.value("ShowThumbnails", true).toBool(); + setMaxThumbnailFileSize(settings.value("MaxThumbnailFileSize", 4096).toInt()); + setThumbnailLocalFilesOnly(settings.value("ThumbnailLocalFilesOnly", true).toBool()); + settings.endGroup(); + + settings.beginGroup("FolderView"); + viewMode_ = viewModeFromString(settings.value("Mode", Fm::FolderView::IconMode).toString()); + showHidden_ = settings.value("ShowHidden", false).toBool(); + sortOrder_ = sortOrderFromString(settings.value("SortOrder").toString()); + sortColumn_ = sortColumnFromString(settings.value("SortColumn").toString()); + + // override config in libfm's FmConfig + bigIconSize_ = settings.value("BigIconSize", 48).toInt(); + smallIconSize_ = settings.value("SmallIconSize", 24).toInt(); + sidePaneIconSize_ = settings.value("SidePaneIconSize", 24).toInt(); + thumbnailIconSize_ = settings.value("ThumbnailIconSize", 128).toInt(); + settings.endGroup(); + + settings.beginGroup("Window"); + fixedWindowWidth_ = settings.value("FixedWidth", 640).toInt(); + fixedWindowHeight_ = settings.value("FixedHeight", 480).toInt(); + lastWindowWidth_ = settings.value("LastWindowWidth", 640).toInt(); + lastWindowHeight_ = settings.value("LastWindowHeight", 480).toInt(); + lastWindowMaximized_ = settings.value("LastWindowMaximized", false).toBool(); + rememberWindowSize_ = settings.value("RememberWindowSize", true).toBool(); + alwaysShowTabs_ = settings.value("AlwaysShowTabs", true).toBool(); + showTabClose_ = settings.value("ShowTabClose", true).toBool(); + splitterPos_ = settings.value("SplitterPos", 150).toInt(); + sidePaneMode_ = sidePaneModeFromString(settings.value("SidePaneMode").toString()); + settings.endGroup(); + + return true; +} + +bool Settings::saveFile(QString filePath) { + QSettings settings(filePath, QSettings::IniFormat); + + settings.beginGroup("System"); + settings.setValue("FallbackIconThemeName", fallbackIconThemeName_); + settings.setValue("SuCommand", suCommand_); + settings.setValue("Terminal", terminal_); + settings.setValue("Archiver", archiver_); + settings.setValue("SIUnit", siUnit_); + settings.endGroup(); + + settings.beginGroup("Behavior"); + // settings.setValue("BookmarkOpenMethod", bookmarkOpenMethodToString(bookmarkOpenMethod_)); + // settings for use with libfm + settings.setValue("UseTrash", useTrash_); + settings.setValue("SingleClick", singleClick_); + settings.setValue("AutoSelectionDelay", autoSelectionDelay_); + settings.setValue("ConfirmDelete", confirmDelete_); + settings.setValue("NoUsbTrash", noUsbTrash_); + // bool thumbnailLocal_; + // bool thumbnailMax; + settings.endGroup(); + + settings.beginGroup("Desktop"); + settings.setValue("WallpaperMode", wallpaperModeToString(wallpaperMode_)); + settings.setValue("Wallpaper", wallpaper_); + settings.setValue("BgColor", desktopBgColor_.name()); + settings.setValue("FgColor", desktopFgColor_.name()); + settings.setValue("ShadowColor", desktopShadowColor_.name()); + settings.setValue("Font", desktopFont_.toString()); + settings.setValue("ShowWmMenu", showWmMenu_); + settings.setValue("ShowHidden", desktopShowHidden_); + settings.setValue("SortOrder", sortOrderToString(desktopSortOrder_)); + settings.setValue("SortColumn", sortColumnToString(desktopSortColumn_)); + settings.endGroup(); + + settings.beginGroup("Volume"); + settings.setValue("MountOnStartup", mountOnStartup_); + settings.setValue("MountRemovable", mountRemovable_); + settings.setValue("AutoRun", autoRun_); + settings.setValue("CloseOnUnmount", closeOnUnmount_); + settings.endGroup(); + + settings.beginGroup("Thumbnail"); + settings.setValue("ShowThumbnails", showThumbnails_); + settings.setValue("MaxThumbnailFileSize", maxThumbnailFileSize()); + settings.setValue("ThumbnailLocalFilesOnly", thumbnailLocalFilesOnly()); + settings.endGroup(); + + settings.beginGroup("FolderView"); + settings.setValue("Mode", viewModeToString(viewMode_)); + settings.setValue("ShowHidden", showHidden_); + settings.setValue("SortOrder", sortOrderToString(sortOrder_)); + settings.setValue("SortColumn", sortColumnToString(sortColumn_)); + + // override config in libfm's FmConfig + settings.setValue("BigIconSize", bigIconSize_); + settings.setValue("SmallIconSize", smallIconSize_); + settings.setValue("SidePaneIconSize", sidePaneIconSize_); + settings.setValue("ThumbnailIconSize", thumbnailIconSize_); + settings.endGroup(); + + settings.beginGroup("Window"); + settings.setValue("FixedWidth", fixedWindowWidth_); + settings.setValue("FixedHeight", fixedWindowHeight_); + settings.setValue("LastWindowWidth", lastWindowWidth_); + settings.setValue("LastWindowHeight", lastWindowHeight_); + settings.setValue("LastWindowMaximized", lastWindowMaximized_); + settings.setValue("RememberWindowSize", rememberWindowSize_); + settings.setValue("AlwaysShowTabs", alwaysShowTabs_); + settings.setValue("ShowTabClose", showTabClose_); + settings.setValue("SplitterPos", splitterPos_); + // settings.setValue("SidePaneMode", sidePaneModeToString(sidePaneMode_)); + settings.endGroup(); + return true; +} + +static const char* bookmarkOpenMethodToString(int value) { + return ""; +} + +static int bookmarkOpenMethodFromString(const QString str) { + return 0; +} + +static const char* viewModeToString(Fm::FolderView::ViewMode value) { + const char* ret; + switch(value) { + case Fm::FolderView::IconMode: + default: + ret = "icon"; + break; + case Fm::FolderView::CompactMode: + ret = "compact"; + break; + case Fm::FolderView::DetailedListMode: + ret = "detailed"; + break; + case Fm::FolderView::ThumbnailMode: + ret = "thumbnail"; + break; + } + return ret; +} + +Fm::FolderView::ViewMode viewModeFromString(const QString str) { + Fm::FolderView::ViewMode ret; + if(str == "icon") + ret = Fm::FolderView::IconMode; + else if(str == "compact") + ret = Fm::FolderView::CompactMode; + else if(str == "detailed") + ret = Fm::FolderView::DetailedListMode; + else if(str == "thumbnail") + ret = Fm::FolderView::ThumbnailMode; + else + ret = Fm::FolderView::IconMode; + return ret; +} + +static const char* sortOrderToString(Qt::SortOrder order) { + return (order == Qt::DescendingOrder ? "descending" : "ascending"); +} + +static Qt::SortOrder sortOrderFromString(const QString str) { + return (str == "descending" ? Qt::DescendingOrder : Qt::AscendingOrder); +} + +static const char* sortColumnToString(Fm::FolderModel::ColumnId value) { + const char* ret; + switch(value) { + case Fm::FolderModel::ColumnFileName: + default: + ret = "name"; + break; + case Fm::FolderModel::ColumnFileType: + ret = "type"; + break; + case Fm::FolderModel::ColumnFileSize: + ret = "size"; + break; + case Fm::FolderModel::ColumnFileMTime: + ret = "mtime"; + break; + case Fm::FolderModel::ColumnFileOwner: + ret = "owner"; + break; + } + return ret; +} + +static Fm::FolderModel::ColumnId sortColumnFromString(const QString str) { + Fm::FolderModel::ColumnId ret; + if(str == "name") + ret = Fm::FolderModel::ColumnFileName; + else if(str == "type") + ret = Fm::FolderModel::ColumnFileType; + else if(str == "size") + ret = Fm::FolderModel::ColumnFileSize; + else if(str == "mtime") + ret = Fm::FolderModel::ColumnFileMTime; + else if(str == "owner") + ret = Fm::FolderModel::ColumnFileOwner; + else + ret = Fm::FolderModel::ColumnFileName; + return ret; +} + +static const char* wallpaperModeToString(int value) { + const char* ret; + switch(value) { + case DesktopWindow::WallpaperNone: + default: + ret = "none"; + break; + case DesktopWindow::WallpaperStretch: + ret = "stretch"; + break; + case DesktopWindow::WallpaperFit: + ret = "fit"; + break; + case DesktopWindow::WallpaperCenter: + ret = "center"; + break; + case DesktopWindow::WallpaperTile: + ret = "tile"; + break; + } + return ret; +} + +static int wallpaperModeFromString(const QString str) { + int ret; + if(str == "stretch") + ret = DesktopWindow::WallpaperStretch; + else if(str == "fit") + ret = DesktopWindow::WallpaperFit; + else if(str == "center") + ret = DesktopWindow::WallpaperCenter; + else if(str == "tile") + ret = DesktopWindow::WallpaperTile; + else + ret = DesktopWindow::WallpaperNone; + return ret; +} + +static const char* sidePaneModeToString(int value) { + return NULL; +} + +static int sidePaneModeFromString(const QString str) { + return 0; +} + +void Settings::setTerminal(QString terminalCommand) { + terminal_ = terminalCommand; + // override the settings in libfm FmConfig. + g_free(fm_config->terminal); + fm_config->terminal = g_strdup(terminal_.toLocal8Bit().constData()); + g_signal_emit_by_name(fm_config, "changed::terminal"); + } diff --git a/pcmanfm/settings.h b/pcmanfm/settings.h new file mode 100644 index 0000000..7dea350 --- /dev/null +++ b/pcmanfm/settings.h @@ -0,0 +1,509 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_SETTINGS_H +#define PCMANFM_SETTINGS_H + +#include +#include +#include "folderview.h" +#include "foldermodel.h" +#include "desktopwindow.h" +#include "thumbnailloader.h" + +namespace PCManFM { + +class Settings : public QObject { + Q_OBJECT +public: + Settings(); + virtual ~Settings(); + + bool load(QString profile = "default"); + bool save(QString profile = QString()); + + bool loadFile(QString filePath); + bool saveFile(QString filePath); + + QString profileDir(QString profile, bool useFallback = false); + + // setter/getter functions + QString profileName() const { + return profileName_; + } + + bool supportTrash() const { + return supportTrash_; + } + + QString fallbackIconThemeName() const { + return fallbackIconThemeName_; + } + + bool useFallbackIconTheme() const { + return useFallbackIconTheme_; + } + + void setFallbackIconThemeName(QString iconThemeName) { + fallbackIconThemeName_ = iconThemeName; + } + + int bookmarkOpenMethod() { + return bookmarkOpenMethod_; + } + + void setBookmarkOpenMethod(int bookmarkOpenMethod) { + bookmarkOpenMethod_ = bookmarkOpenMethod; + } + + QString suCommand() const { + return suCommand_; + } + + void setSuCommand(QString suCommand) { + suCommand_ = suCommand; + } + + QString terminal() { + return terminal_; + } + void setTerminal(QString terminalCommand); + + QString archiver() const { + return archiver_; + } + + void setArchiver(QString archiver) { + archiver_ = archiver; + // override libfm FmConfig + g_free(fm_config->archiver); + fm_config->archiver = g_strdup(archiver_.toLocal8Bit().constData()); + } + + bool mountOnStartup() const { + return mountOnStartup_; + } + + void setMountOnStartup(bool mountOnStartup) { + mountOnStartup_ = mountOnStartup; + } + + bool mountRemovable() { + return mountRemovable_; + } + + void setMountRemovable(bool mountRemovable) { + mountRemovable_ = mountRemovable; + } + + bool autoRun() const { + return autoRun_; + } + + void setAutoRun(bool autoRun) { + autoRun_ = autoRun; + } + + bool closeOnUnmount() const { + return closeOnUnmount_; + } + + void setCloseOnUnmount(bool value) { + closeOnUnmount_ = value; + } + + DesktopWindow::WallpaperMode wallpaperMode() const { + return DesktopWindow::WallpaperMode(wallpaperMode_); + } + + void setWallpaperMode(int wallpaperMode) { + wallpaperMode_ = wallpaperMode; + } + + QString wallpaper() const { + return wallpaper_; + } + + void setWallpaper(QString wallpaper) { + wallpaper_ = wallpaper; + } + + const QColor& desktopBgColor() const { + return desktopBgColor_; + } + + void setDesktopBgColor(QColor desktopBgColor) { + desktopBgColor_ = desktopBgColor; + } + + const QColor& desktopFgColor() const { + return desktopFgColor_; + } + + void setDesktopFgColor(QColor desktopFgColor) { + desktopFgColor_ = desktopFgColor; + } + + const QColor& desktopShadowColor() const { + return desktopShadowColor_; + } + + void setDesktopShadowColor(QColor desktopShadowColor) { + desktopShadowColor_ = desktopShadowColor; + } + + QFont desktopFont() const { + return desktopFont_; + } + + void setDesktopFont(QFont font) { + desktopFont_ = font; + } + + bool showWmMenu() const { + return showWmMenu_; + } + + void setShowWmMenu(bool value) { + showWmMenu_ = value; + } + + bool desktopShowHidden() const { + return desktopShowHidden_; + } + + void setDesktopShowHidden(bool desktopShowHidden) { + desktopShowHidden_ = desktopShowHidden; + } + + Qt::SortOrder desktopSortOrder() const { + return desktopSortOrder_; + } + + void setDesktopSortOrder(Qt::SortOrder desktopSortOrder) { + desktopSortOrder_ = desktopSortOrder; + } + + Fm::FolderModel::ColumnId desktopSortColumn() const { + return desktopSortColumn_; + } + + void setDesktopSortColumn(Fm::FolderModel::ColumnId desktopSortColumn) { + desktopSortColumn_ = desktopSortColumn; + } + + bool alwaysShowTabs() const { + return alwaysShowTabs_; + } + + void setAlwaysShowTabs(bool alwaysShowTabs) { + alwaysShowTabs_ = alwaysShowTabs; + } + + bool showTabClose() const { + return showTabClose_; + } + + void setShowTabClose(bool showTabClose) { + showTabClose_ = showTabClose; + } + + bool rememberWindowSize() const { + return rememberWindowSize_; + } + + void setRememberWindowSize(bool rememberWindowSize) { + rememberWindowSize_ = rememberWindowSize; + } + + int windowWidth() const { + if(rememberWindowSize_) + return lastWindowWidth_; + else + return fixedWindowWidth_; + } + + int windowHeight() const { + if(rememberWindowSize_) + return lastWindowHeight_; + else + return fixedWindowHeight_; + } + + bool windowMaximized() const { + if(rememberWindowSize_) + return lastWindowMaximized_; + else + return false; + } + + int fixedWindowWidth() const { + return fixedWindowWidth_; + } + + void setFixedWindowWidth(int fixedWindowWidth) { + fixedWindowWidth_ = fixedWindowWidth; + } + + int fixedWindowHeight() const { + return fixedWindowHeight_; + } + + void setFixedWindowHeight(int fixedWindowHeight) { + fixedWindowHeight_ = fixedWindowHeight; + } + + void setLastWindowWidth(int lastWindowWidth) { + lastWindowWidth_ = lastWindowWidth; + } + + void setLastWindowHeight(int lastWindowHeight) { + lastWindowHeight_ = lastWindowHeight; + } + + void setLastWindowMaximized(bool lastWindowMaximized) { + lastWindowMaximized_ = lastWindowMaximized; + } + + int splitterPos() const { + return splitterPos_; + } + + void setSplitterPos(int splitterPos) { + splitterPos_ = splitterPos; + } + + int sidePaneMode() const { + return sidePaneMode_; + } + + void setSidePaneMode(int sidePaneMode) { + sidePaneMode_ = sidePaneMode; + } + + Fm::FolderView::ViewMode viewMode() const { + return viewMode_; + } + + void setViewMode(Fm::FolderView::ViewMode viewMode) { + viewMode_ = viewMode; + } + + bool showHidden() const { + return showHidden_; + } + + void setShowHidden(bool showHidden) { + showHidden_ = showHidden; + } + + Qt::SortOrder sortOrder() const { + return sortOrder_; + } + + void setSortOrder(Qt::SortOrder sortOrder) { + sortOrder_ = sortOrder; + } + + Fm::FolderModel::ColumnId sortColumn() const { + return sortColumn_; + } + + void setSortColumn(Fm::FolderModel::ColumnId sortColumn) { + sortColumn_ = sortColumn; + } + + // settings for use with libfm + bool singleClick() const { + return singleClick_; + } + + void setSingleClick(bool singleClick) { + singleClick_ = singleClick; + } + + int autoSelectionDelay() const { + return autoSelectionDelay_; + } + + void setAutoSelectionDelay(int value) { + autoSelectionDelay_ = value; + } + + bool useTrash() const { + if(!supportTrash_) + return false; + return useTrash_; + } + + void setUseTrash(bool useTrash) { + useTrash_ = useTrash; + } + + bool confirmDelete() const { + return confirmDelete_; + } + + void setConfirmDelete(bool confirmDelete) { + confirmDelete_ = confirmDelete; + } + + bool noUsbTrash() const { + return noUsbTrash_; + } + + void setNoUsbTrash(bool noUsbTrash) { + noUsbTrash_ = noUsbTrash; + } + + // bool thumbnailLocal_; + // bool thumbnailMax; + + int bigIconSize() const { + return bigIconSize_; + } + + void setBigIconSize(int bigIconSize) { + bigIconSize_ = bigIconSize; + } + + int smallIconSize() const { + return smallIconSize_; + } + + void setSmallIconSize(int smallIconSize) { + smallIconSize_ = smallIconSize; + } + + int sidePaneIconSize() const { + return sidePaneIconSize_; + } + + void setSidePaneIconSize(int sidePaneIconSize) { + sidePaneIconSize_ = sidePaneIconSize; + } + + int thumbnailIconSize() const { + return thumbnailIconSize_; + } + + bool showThumbnails() { + return showThumbnails_; + } + + void setShowThumbnails(bool show) { + showThumbnails_ = show; + } + + void setThumbnailLocalFilesOnly(bool value) { + Fm::ThumbnailLoader::setLocalFilesOnly(value); + } + + bool thumbnailLocalFilesOnly() { + return Fm::ThumbnailLoader::localFilesOnly(); + } + + int maxThumbnailFileSize() { + return Fm::ThumbnailLoader::maxThumbnailFileSize(); + } + + void setMaxThumbnailFileSize(int size) { + Fm::ThumbnailLoader::setMaxThumbnailFileSize(size); + } + + void setThumbnailIconSize(int thumbnailIconSize) { + thumbnailIconSize_ = thumbnailIconSize; + } + + bool siUnit() { + return siUnit_; + } + + void setSiUnit(bool siUnit) { + siUnit_ = siUnit; + // override libfm FmConfig settings. FIXME: should we do this? + fm_config->si_unit = (gboolean)siUnit_; + } + +private: + QString profileName_; + bool supportTrash_; + + // PCManFM specific + QString fallbackIconThemeName_; + bool useFallbackIconTheme_; + + int bookmarkOpenMethod_; + QString suCommand_; + QString terminal_; + bool mountOnStartup_; + bool mountRemovable_; + bool autoRun_; + bool closeOnUnmount_; + + int wallpaperMode_; + QString wallpaper_; + QColor desktopBgColor_; + QColor desktopFgColor_; + QColor desktopShadowColor_; + QFont desktopFont_; + bool showWmMenu_; + + bool desktopShowHidden_; + Qt::SortOrder desktopSortOrder_; + Fm::FolderModel::ColumnId desktopSortColumn_; + + bool alwaysShowTabs_; + bool showTabClose_; + bool rememberWindowSize_; + int fixedWindowWidth_; + int fixedWindowHeight_; + int lastWindowWidth_; + int lastWindowHeight_; + bool lastWindowMaximized_; + int splitterPos_; + int sidePaneMode_; + + Fm::FolderView::ViewMode viewMode_; + bool showHidden_; + Qt::SortOrder sortOrder_; + Fm::FolderModel::ColumnId sortColumn_; + + // settings for use with libfm + bool singleClick_; + int autoSelectionDelay_; + bool useTrash_; + bool confirmDelete_; + bool noUsbTrash_; // do not trash files on usb removable devices + + bool showThumbnails_; + + QString archiver_; + bool siUnit_; + + int bigIconSize_; + int smallIconSize_; + int sidePaneIconSize_; + int thumbnailIconSize_; +}; + +} + +#endif // PCMANFM_SETTINGS_H diff --git a/pcmanfm/tabbar.cpp b/pcmanfm/tabbar.cpp new file mode 100644 index 0000000..f6bf1e5 --- /dev/null +++ b/pcmanfm/tabbar.cpp @@ -0,0 +1,41 @@ +/* + + Copyright (C) 2014 Kuzma Shapran + + 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 "tabbar.h" +#include + +namespace PCManFM { + +TabBar::TabBar(QWidget *parent): + QTabBar(parent) +{ +} + +void TabBar::mouseReleaseEvent(QMouseEvent *event) { + if (event->button() == Qt::MiddleButton) { + int index = tabAt(event->pos()); + if (index != -1) { + Q_EMIT tabCloseRequested(index); + } + } + QTabBar::mouseReleaseEvent(event); +} + +} diff --git a/pcmanfm/tabbar.h b/pcmanfm/tabbar.h new file mode 100644 index 0000000..a7ac764 --- /dev/null +++ b/pcmanfm/tabbar.h @@ -0,0 +1,42 @@ +/* + + Copyright (C) 2014 Kuzma Shapran + + 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 FM_TABBAR_H +#define FM_TABBAR_H + +#include + +class QMouseEvent; + +namespace PCManFM { + +class TabBar : public QTabBar { +Q_OBJECT + +public: + explicit TabBar(QWidget *parent = 0); + +protected: + void mouseReleaseEvent(QMouseEvent *event); +}; + +} + +#endif // FM_TABBAR_H diff --git a/pcmanfm/tabpage.cpp b/pcmanfm/tabpage.cpp new file mode 100644 index 0000000..001e458 --- /dev/null +++ b/pcmanfm/tabpage.cpp @@ -0,0 +1,473 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "tabpage.h" +#include "filelauncher.h" +#include "filemenu.h" +#include "mountoperation.h" +#include +#include +#include +#include +#include "proxyfoldermodel.h" +#include "settings.h" +#include "application.h" +#include "cachedfoldermodel.h" +#include + +using namespace Fm; + +namespace PCManFM { + +TabPage::TabPage(FmPath* path, QWidget* parent): + QWidget(parent), + folder_(NULL), + folderModel_(NULL), + overrideCursor_(false) { + + Settings& settings = static_cast(qApp)->settings(); + + // create proxy folder model to do item filtering + proxyModel_ = new ProxyFolderModel(); + proxyModel_->setShowHidden(settings.showHidden()); + proxyModel_->setShowThumbnails(settings.showThumbnails()); + connect(proxyModel_, &ProxyFolderModel::sortFilterChanged, this, &TabPage::onModelSortFilterChanged); + + verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + folderView_ = new View(settings.viewMode(), this); + // newView->setColumnWidth(Fm::FolderModel::ColumnName, 200); + connect(folderView_, &View::openDirRequested, this, &TabPage::onOpenDirRequested); + connect(folderView_, &View::selChanged, this, &TabPage::onSelChanged); + + // FIXME: this is very dirty + folderView_->setModel(proxyModel_); + verticalLayout->addWidget(folderView_); + + chdir(path, true); +} + +TabPage::~TabPage() { + qDebug("delete TabPage"); + freeFolder(); + if(proxyModel_) + delete proxyModel_; + if(folderModel_) + folderModel_->unref(); + + if(overrideCursor_) { + QApplication::restoreOverrideCursor(); // remove busy cursor + } +} + +void TabPage::freeFolder() { + if(folder_) { + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderStartLoading, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderFinishLoading, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderError, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderFsInfo, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderRemoved, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderUnmount, this); + g_signal_handlers_disconnect_by_func(folder_, (gpointer)onFolderContentChanged, this); + g_object_unref(folder_); + folder_ = NULL; + } +} + +/*static*/ void TabPage::onFolderStartLoading(FmFolder* _folder, TabPage* pThis) { + if(!pThis->overrideCursor_) { + // FIXME: sometimes FmFolder of libfm generates unpaired "start-loading" and + // "finish-loading" signals of uncertain reasons. This should be a bug in libfm. + // Until it's fixed in libfm, we need to workaround the problem here, not to + // override the cursor twice. + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + pThis->overrideCursor_ = true; + } + qDebug("start-loading"); +#if 0 +#if FM_CHECK_VERSION(1, 0, 2) && 0 // disabled + if(fm_folder_is_incremental(_folder)) { + /* create a model for the folder and set it to the view + it is delayed for non-incremental folders since adding rows into + model is much faster without handlers connected to its signals */ + FmFolderModel* model = fm_folder_model_new(folder, FALSE); + fm_folder_view_set_model(fv, model); + fm_folder_model_set_sort(model, app_config->sort_by, + (app_config->sort_type == GTK_SORT_ASCENDING) ? + FM_SORT_ASCENDING : FM_SORT_DESCENDING); + g_object_unref(model); + } + else +#endif + fm_folder_view_set_model(fv, NULL); +#endif +} + +// slot +void TabPage::restoreScrollPos() { + // scroll to recorded position + folderView_->childView()->verticalScrollBar()->setValue(browseHistory().currentScrollPos()); +} + +/*static*/ void TabPage::onFolderFinishLoading(FmFolder* _folder, TabPage* pThis) { + // FIXME: is this needed? + FmFileInfo* fi = fm_folder_get_info(_folder); + if(fi) { // if loading of the folder fails, it's possible that we don't have FmFileInfo. + pThis->title_ = QString::fromUtf8(fm_file_info_get_disp_name(fi)); + Q_EMIT pThis->titleChanged(pThis->title_); + } + + fm_folder_query_filesystem_info(_folder); // FIXME: is this needed? +#if 0 + FmFolderView* fv = folder_view; + const FmNavHistoryItem* item; + GtkScrolledWindow* scroll = GTK_SCROLLED_WINDOW(fv); + + /* Note: most of the time, we delay the creation of the + * folder model and do it after the whole folder is loaded. + * That is because adding rows into model is much faster when no handlers + * are connected to its signals. So we detach the model from folder view + * and create the model again when it's fully loaded. + * This optimization, however, is not used for FmFolder objects + * with incremental loading (search://) */ + if(fm_folder_view_get_model(fv) == NULL) { + /* create a model for the folder and set it to the view */ + FmFolderModel* model = fm_folder_model_new(folder, app_config->show_hidden); + fm_folder_view_set_model(fv, model); +#if FM_CHECK_VERSION(1, 0, 2) + /* since 1.0.2 sorting should be applied on model instead of view */ + fm_folder_model_set_sort(model, app_config->sort_by, + (app_config->sort_type == GTK_SORT_ASCENDING) ? + FM_SORT_ASCENDING : FM_SORT_DESCENDING); +#endif + g_object_unref(model); + } + +#endif + + // update status text + QString& text = pThis->statusText_[StatusTextNormal]; + text = pThis->formatStatusText(); + Q_EMIT pThis->statusChanged(StatusTextNormal, text); + + if(pThis->overrideCursor_) { + QApplication::restoreOverrideCursor(); // remove busy cursor + pThis->overrideCursor_ = false; + } + qDebug("finish-loading"); + + // After finishing loading the folder, the model is updated, but Qt delays the UI update + // for performance reasons. Therefore at this point the UI is not up to date. + // Of course, the scrollbar ranges are not updated yet. We solve this by installing an Qt timeout handler. + QTimer::singleShot(10, pThis, SLOT(restoreScrollPos())); +} + +/*static*/ FmJobErrorAction TabPage::onFolderError(FmFolder* _folder, GError* err, FmJobErrorSeverity severity, TabPage* pThis) { + if(err->domain == G_IO_ERROR) { + if(err->code == G_IO_ERROR_NOT_MOUNTED && severity < FM_JOB_ERROR_CRITICAL) { + FmPath* path = fm_folder_get_path(_folder); + MountOperation* op = new MountOperation(pThis); + op->mount(path); + if(op->wait()) { // blocking event loop, wait for mount operation to finish. + // This will reload the folder, which generates a new "start-loading" + // signal, so we get more "start-loading" signals than "finish-loading" + // signals. FIXME: This is a bug of libfm. + // Because the two signals are not correctly paired, we need to + // remove busy cursor here since "finish-loading" is not emitted. + QApplication::restoreOverrideCursor(); // remove busy cursor + pThis->overrideCursor_ = false; + return FM_JOB_RETRY; + } + } + } + if(severity >= FM_JOB_ERROR_MODERATE) { + /* Only show more severe errors to the users and + * ignore milder errors. Otherwise too many error + * message boxes can be annoying. + * This fixes bug #3411298- Show "Permission denied" when switching to super user mode. + * https://sourceforge.net/tracker/?func=detail&aid=3411298&group_id=156956&atid=801864 + * */ + + // FIXME: consider replacing this modal dialog with an info bar to improve usability + QMessageBox::critical(pThis, tr("Error"), QString::fromUtf8(err->message)); + } + return FM_JOB_CONTINUE; +} + +/*static*/ void TabPage::onFolderFsInfo(FmFolder* _folder, TabPage* pThis) { + guint64 free, total; + QString& msg = pThis->statusText_[StatusTextFSInfo]; + if(fm_folder_get_filesystem_info(_folder, &total, &free)) { + char total_str[64]; + char free_str[64]; + fm_file_size_to_str(free_str, sizeof(free_str), free, fm_config->si_unit); + fm_file_size_to_str(total_str, sizeof(total_str), total, fm_config->si_unit); + msg = tr("Free space: %1 (Total: %2)") + .arg(QString::fromUtf8(free_str)) + .arg(QString::fromUtf8(total_str)); + } + else + msg.clear(); + Q_EMIT pThis->statusChanged(StatusTextFSInfo, msg); +} + +QString TabPage::formatStatusText() { + if(proxyModel_ && folder_) { + FmFileInfoList* files = fm_folder_get_files(folder_); + int total_files = fm_file_info_list_get_length(files); + int shown_files = proxyModel_->rowCount(); + int hidden_files = total_files - shown_files; + QString text = tr("%n item(s)", "", shown_files); + if(hidden_files > 0) + text += tr(" (%n hidden)", "", hidden_files); + return text; + } + return QString(); +} + +/*static*/ void TabPage::onFolderRemoved(FmFolder* _folder, TabPage* pThis) { + // the folder we're showing is removed, destroy the widget + qDebug("folder removed"); + Settings& settings = static_cast(qApp)->settings(); + // NOTE: call pThis->deleteLater() directly from this GObject signal handler + // does not work but I don't know why. + // Maybe it's the problem of glib mainloop integration? + // Call it when idle works, though. + if(settings.closeOnUnmount()) + QTimer::singleShot(0, pThis, SLOT(deleteLater())); + else + pThis->chdir(fm_path_get_home()); +} + +/*static*/ void TabPage::onFolderUnmount(FmFolder* _folder, TabPage* pThis) { + // the folder we're showing is unmounted, destroy the widget + qDebug("folder unmount"); + // NOTE: call pThis->deleteLater() directly from this GObject signal handler + // does not work but I don't know why. + // Maybe it's the problem of glib mainloop integration? + // Call it when idle works, though. + Settings& settings = static_cast(qApp)->settings(); + // NOTE: call pThis->deleteLater() directly from this GObject signal handler + // does not work but I don't know why. + // Maybe it's the problem of glib mainloop integration? + // Call it when idle works, though. + if(settings.closeOnUnmount()) + QTimer::singleShot(0, pThis, SLOT(deleteLater())); + else + pThis->chdir(fm_path_get_home()); +} + +/*static */ void TabPage::onFolderContentChanged(FmFolder* _folder, TabPage* pThis) { + /* update status text */ + pThis->statusText_[StatusTextNormal] = pThis->formatStatusText(); + Q_EMIT pThis->statusChanged(StatusTextNormal, pThis->statusText_[StatusTextNormal]); +} + +QString TabPage::pathName() { + char* disp_path = fm_path_display_name(path(), TRUE); + QString ret = QString::fromUtf8(disp_path); + g_free(disp_path); + return ret; +} + +void TabPage::chdir(FmPath* newPath, bool addHistory) { + if(folder_) { + // we're already in the specified dir + if(fm_path_equal(newPath, fm_folder_get_path(folder_))) + return; + + if(addHistory) { + // store current scroll pos in the browse history + BrowseHistoryItem& item = history_.currentItem(); + QAbstractItemView* childView = folderView_->childView(); + item.setScrollPos(childView->verticalScrollBar()->value()); + } + + // free the previous model + if(folderModel_) { + proxyModel_->setSourceModel(NULL); + folderModel_->unref(); // unref the cached model + folderModel_ = NULL; + } + + freeFolder(); + } + + char* disp_name = fm_path_display_basename(newPath); + title_ = QString::fromUtf8(disp_name); + Q_EMIT titleChanged(title_); + g_free(disp_name); + + folder_ = fm_folder_from_path(newPath); + g_signal_connect(folder_, "start-loading", G_CALLBACK(onFolderStartLoading), this); + g_signal_connect(folder_, "finish-loading", G_CALLBACK(onFolderFinishLoading), this); + g_signal_connect(folder_, "error", G_CALLBACK(onFolderError), this); + g_signal_connect(folder_, "fs-info", G_CALLBACK(onFolderFsInfo), this); + /* destroy the page when the folder is unmounted or deleted. */ + g_signal_connect(folder_, "removed", G_CALLBACK(onFolderRemoved), this); + g_signal_connect(folder_, "unmount", G_CALLBACK(onFolderUnmount), this); + g_signal_connect(folder_, "content-changed", G_CALLBACK(onFolderContentChanged), this); + + folderModel_ = CachedFolderModel::modelFromFolder(folder_); + proxyModel_->setSourceModel(folderModel_); + proxyModel_->sort(Fm::FolderModel::ColumnFileName); + + if(fm_folder_is_loaded(folder_)) { + onFolderStartLoading(folder_, this); + onFolderFinishLoading(folder_, this); + onFolderFsInfo(folder_, this); + } + else + onFolderStartLoading(folder_, this); + + if(addHistory) { + // add current path to browse history + QAbstractItemView* childView = folderView_->childView(); + history_.add(path()); + } +} + +void TabPage::selectAll() { + folderView_->selectAll(); +} + +void TabPage::invertSelection() { + folderView_->invertSelection(); +} + +void TabPage::onOpenDirRequested(FmPath* path, int target) { + Q_EMIT openDirRequested(path, target); +} + +// when the current selection in the folder view is changed +void TabPage::onSelChanged(int numSel) { + QString msg; + if(numSel > 0) { + /* FIXME: display total size of all selected files. */ + if(numSel == 1) { /* only one file is selected */ + FmFileInfoList* files = folderView_->selectedFiles(); + FmFileInfo* fi = fm_file_info_list_peek_head(files); + const char* size_str = fm_file_info_get_disp_size(fi); + if(size_str) { + msg = QString("\"%1\" (%2) %3") + .arg(QString::fromUtf8(fm_file_info_get_disp_name(fi))) + .arg(QString::fromUtf8(size_str ? size_str : "")) + .arg(QString::fromUtf8(fm_file_info_get_desc(fi))); + } + else { + msg = QString("\"%1\" %2") + .arg(QString::fromUtf8(fm_file_info_get_disp_name(fi))) + .arg(QString::fromUtf8(fm_file_info_get_desc(fi))); + } + /* FIXME: should we support statusbar plugins as in the gtk+ version? */ + fm_file_info_list_unref(files); + } + else { + FmFileInfoList* files; + goffset sum; + GList* l; + char size_str[128]; + msg = tr("%1 item(s) selected", NULL, numSel).arg(numSel); + /* don't count if too many files are selected, that isn't lightweight */ + if(numSel < 1000) { + sum = 0; + files = folderView_->selectedFiles(); + for(l = fm_file_info_list_peek_head_link(files); l; l = l->next) { + if(fm_file_info_is_dir(FM_FILE_INFO(l->data))) { + /* if we got a directory then we cannot tell it's size + unless we do deep count but we cannot afford it */ + sum = -1; + break; + } + sum += fm_file_info_get_size(FM_FILE_INFO(l->data)); + } + if(sum >= 0) { + fm_file_size_to_str(size_str, sizeof(size_str), sum, + fm_config->si_unit); + msg += QString(" (%1)").arg(QString::fromUtf8(size_str)); + } + /* FIXME: should we support statusbar plugins as in the gtk+ version? */ + fm_file_info_list_unref(files); + } + /* FIXME: can we show some more info on selection? + that isn't lightweight if a lot of files are selected */ + } + } + statusText_[StatusTextSelectedFiles] = msg; + Q_EMIT statusChanged(StatusTextSelectedFiles, msg); +} + + +void TabPage::backward() { + // remember current scroll position + BrowseHistoryItem& item = history_.currentItem(); + QAbstractItemView* childView = folderView_->childView(); + item.setScrollPos(childView->verticalScrollBar()->value()); + + history_.backward(); + chdir(history_.currentPath(), false); +} + +void TabPage::forward() { + // remember current scroll position + BrowseHistoryItem& item = history_.currentItem(); + QAbstractItemView* childView = folderView_->childView(); + item.setScrollPos(childView->verticalScrollBar()->value()); + + history_.forward(); + chdir(history_.currentPath(), false); +} + +void TabPage::jumpToHistory(int index) +{ + if(index >=0 && index < history_.size()) { + // remember current scroll position + BrowseHistoryItem& item = history_.currentItem(); + QAbstractItemView* childView = folderView_->childView(); + item.setScrollPos(childView->verticalScrollBar()->value()); + + history_.setCurrentIndex(index); + chdir(history_.currentPath(), false); + } +} + +bool TabPage::canUp() { + return (path() != NULL && fm_path_get_parent(path()) != NULL); +} + +void TabPage::up() { + FmPath* _path = path(); + if(_path) { + FmPath* parent = fm_path_get_parent(_path); + if(parent) + chdir(parent, true); + } +} + +void TabPage::onModelSortFilterChanged() { + Q_EMIT sortFilterChanged(); +} + +void TabPage::updateFromSettings(Settings& settings) { + folderView_->updateFromSettings(settings); +} + +}; diff --git a/pcmanfm/tabpage.h b/pcmanfm/tabpage.h new file mode 100644 index 0000000..ae79cf2 --- /dev/null +++ b/pcmanfm/tabpage.h @@ -0,0 +1,218 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 FM_TABPAGE_H +#define FM_TABPAGE_H + +#include +#include +#include +#include "browsehistory.h" +#include "view.h" +#include "path.h" + +namespace Fm { + class FileLauncher; + class FolderModel; + class ProxyFolderModel; + class CachedFolderModel; +}; + +namespace PCManFM { + +class Settings; +class Launcher; + +class TabPage : public QWidget { +Q_OBJECT + +public: + enum StatusTextType { + StatusTextNormal, + StatusTextSelectedFiles, + StatusTextFSInfo, + StatusTextNum + }; + +public: + explicit TabPage(FmPath* path, QWidget* parent = 0); + virtual ~TabPage(); + + void chdir(FmPath* newPath, bool addHistory = true); + + Fm::FolderView::ViewMode viewMode() { + return folderView_->viewMode(); + } + + void setViewMode(Fm::FolderView::ViewMode mode) { + folderView_->setViewMode(mode); + } + + void sort(int col, Qt::SortOrder order = Qt::AscendingOrder) { + // if(folderModel_) + // folderModel_->sort(col, order); + if(proxyModel_) + proxyModel_->sort(col, order); + } + + int sortColumn() { + return proxyModel_->sortColumn(); + } + + Qt::SortOrder sortOrder() { + return proxyModel_->sortOrder(); + } + + bool sortFolderFirst() { + return proxyModel_->folderFirst(); + } + void setSortFolderFirst(bool value) { + proxyModel_->setFolderFirst(value); + } + + bool sortCaseSensitive() { + return proxyModel_->sortCaseSensitivity(); + } + void setSortCaseSensitive(bool value) { + proxyModel_->setSortCaseSensitivity(value ? Qt::CaseSensitive : Qt::CaseInsensitive); + } + + bool showHidden() { + return proxyModel_->showHidden(); + } + + void setShowHidden(bool showHidden) { + proxyModel_->setShowHidden(showHidden); + } + + FmPath* path() { + return folder_ ? fm_folder_get_path(folder_) : NULL; + } + + QString pathName(); + + FmFolder* folder() { + return folder_; + } + + Fm::FolderModel* folderModel() { + return reinterpret_cast(folderModel_); + } + + View* folderView() { + return folderView_; + } + + Fm::BrowseHistory& browseHistory() { + return history_; + } + + FmFileInfoList* selectedFiles() { + return folderView_->selectedFiles(); + } + + FmPathList* selectedFilePaths() { + return folderView_->selectedFilePaths(); + } + + void selectAll(); + + void invertSelection(); + + void reload() { + if(folder_) + fm_folder_reload(folder_); + } + + QString title() const { + return title_; + } + + QString statusText(StatusTextType type = StatusTextNormal) const { + return statusText_[type]; + } + + bool canBackward() { + return history_.canBackward(); + } + + void backward(); + + bool canForward() { + return history_.canForward(); + } + + void forward(); + + void jumpToHistory(int index); + + bool canUp(); + + void up(); + + void updateFromSettings(Settings& settings); + + void setFileLauncher(Fm::FileLauncher* launcher) { + folderView_->setFileLauncher(launcher); + } + + Fm::FileLauncher* fileLauncher() { + return folderView_->fileLauncher(); + } + +Q_SIGNALS: + void statusChanged(int type, QString statusText); + void titleChanged(QString title); + void openDirRequested(FmPath* path, int target); + void sortFilterChanged(); + +protected Q_SLOTS: + void onOpenDirRequested(FmPath* path, int target); + void onModelSortFilterChanged(); + void onSelChanged(int numSel); + void restoreScrollPos(); + +private: + void freeFolder(); + QString formatStatusText(); + + static void onFolderStartLoading(FmFolder* _folder, TabPage* pThis); + static void onFolderFinishLoading(FmFolder* _folder, TabPage* pThis); + static FmJobErrorAction onFolderError(FmFolder* _folder, GError* err, FmJobErrorSeverity severity, TabPage* pThis); + static void onFolderFsInfo(FmFolder* _folder, TabPage* pThis); + static void onFolderRemoved(FmFolder* _folder, TabPage* pThis); + static void onFolderUnmount(FmFolder* _folder, TabPage* pThis); + static void onFolderContentChanged(FmFolder* _folder, TabPage* pThis); + +private: + View* folderView_; + Fm::CachedFolderModel* folderModel_; + Fm::ProxyFolderModel* proxyModel_; + QVBoxLayout* verticalLayout; + FmFolder* folder_; + QString title_; + QString statusText_[StatusTextNum]; + Fm::BrowseHistory history_; // browsing history + bool overrideCursor_; +}; + +} + +#endif // FM_TABPAGE_H diff --git a/pcmanfm/translations/pcmanfm-qt-desktop-pref_pt.desktop b/pcmanfm/translations/pcmanfm-qt-desktop-pref_pt.desktop new file mode 100644 index 0000000..731909a --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt-desktop-pref_pt.desktop @@ -0,0 +1,4 @@ +#Translations +Name[pt]=Área de trabalho +GenericName[pt]=Definições da área de trabalho +Comment[pt]=Mudar o papel de parede e o comportamento da área de trabalho diff --git a/pcmanfm/translations/pcmanfm-qt_ar.ts b/pcmanfm/translations/pcmanfm-qt_ar.ts new file mode 100644 index 0000000..32294a6 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_ar.ts @@ -0,0 +1,1081 @@ + + + + + AboutDialog + + + About + + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + + Lightweight file manager + + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + + Authors + + + + + License + + + + + AutoRunDialog + + + Removable medium is inserted + + + + + <b>Removable medium is inserted</b> + + + + + Type of medium: + + + + + Detecting... + + + + + Please select the action you want to perform: + + + + + DesktopPreferencesDialog + + + Desktop Preferences + + + + + Background + + + + + Wallpaper mode: + + + + + Wallpaper image file: + + + + + Select background color: + + + + + + Image file + + + + + Image file path + + + + + + &Browse + + + + + Label Text + + + + + Select text color: + + + + + Select shadow color: + + + + + Select font: + + + + + General + + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + + + + + MainWindow + + + File Manager + + + + + Go Up + + + + + Alt+Up + + + + + Home + + + + + Alt+Home + + + + + Reload + + + + + F5 + + + + + &Reload + + + + + Go + + + + + Quit + + + + + &About + + + + + New Window + + + + + Ctrl+N + + + + + Show &Hidden + + + + + Ctrl+H + + + + + &Computer + + + + + &Trash + + + + + &Network + + + + + &Desktop + + + + + &Add to Bookmarks + + + + + &Applications + + + + + Ctrl+X + + + + + &Copy + + + + + Ctrl+C + + + + + &Paste + + + + + Ctrl+V + + + + + Select &All + + + + + Pr&eferences + + + + + &Invert Selection + + + + + &Delete + + + + + &Rename + + + + + Ctrl+A + + + + + Go &Up + + + + + &New Window + + + + + &Icon View + + + + + &Compact View + + + + + &Detailed List + + + + + &Thumbnail View + + + + + Cu&t + + + + + Ascending + + + + + Descending + + + + + By File Name + + + + + By Modification Time + + + + + By File Type + + + + + By Owner + + + + + Folder First + + + + + New &Tab + + + + + New Tab + + + + + Ctrl+T + + + + + Go &Back + + + + + Go Back + + + + + Alt+Left + + + + + Go &Forward + + + + + Go Forward + + + + + Alt+Right + + + + + Del + + + + + F2 + + + + + C&lose Tab + + + + + File &Properties + + + + + &Folder Properties + + + + + &Sorting + + + + + Main Toolbar + + + + + Ctrl+W + + + + + Alt+Return + + + + + Case Sensitive + + + + + By File Size + + + + + Close Window + + + + + Edit Bookmarks + + + + + Open &Terminal + + + + + F4 + + + + + Open as &Root + + + + + &Edit Bookmarks + + + + + &File + + + + + &Help + + + + + &View + + + + + &Edit + + + + + &Bookmarks + + + + + &Go + + + + + &Tool + + + + + PCManFM::Application + + + Name of configuration profile + + + + + PROFILE + + + + + Run PCManFM as a daemon + + + + + Quit PCManFM + + + + + Launch desktop manager + + + + + Turn off desktop manager if it's running + + + + + Open desktop preference dialog on the page with the specified name + + + + + + NAME + + + + + Open new window + + + + + Open Find Files utility + + + + + Set desktop wallpaper from image FILE + + + + + FILE + + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + + + + + MODE + + + + + Open Preferences dialog on the page with the specified name + + + + + Files or directories to open + + + + + [FILE1, FILE2,...] + + + + + + Error + + + + + Terminal emulator is not set. + + + + + PCManFM::AutoRunDialog + + + Open in file manager + + + + + Removable Disk + + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + + + + + Stretch to fill the entire screen + + + + + Stretch to fit the screen + + + + + Center on the screen + + + + + Tile the image to fill the entire screen + + + + + Image Files + + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + + + + + Desktop Preferences + + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + + + + + &Delete + + + + + + Error + + + + + Switch user command is not set. + + + + + PCManFM::PreferencesDialog + + + Icon View + + + + + Compact Icon View + + + + + Thumbnail View + + + + + Detailed List View + + + + + PCManFM::TabPage + + + Error + + + + + Free space: %1 (Total: %2) + + + + + %n item(s) + + + + + + + + + + + + (%n hidden) + + + + + + + + + + + + %1 item(s) selected + + + + + PCManFM::View + + + Open in New T&ab + + + + + Open in New Win&dow + + + + + Open in Termina&l + + + + + PreferencesDialog + + + Preferences + + + + + User Interface + + + + + Behavior + + + + + Thumbnail + + + + + Volume + + + + + Advanced + + + + + Icons + + + + + Size of big icons: + + + + + Size of small icons: + + + + + Size of thumbnails: + + + + + Size of side pane icons: + + + + + Icon theme: + + + + + Window + + + + + Default width of new windows: + + + + + Default height of new windows: + + + + + Always show the tab bar + + + + + Show 'Close' buttons on tabs + + + + + Remember the size of the last closed window + + + + + Browsing + + + + + Open files with single click + + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + + + + + sec + + + + + File Operations + + + + + Confirm before deleting files + + + + + Move deleted files to "trash bin" instead of erasing from disk. + + + + + Show thumbnails of files + + + + + Only show thumbnails for local files + + + + + Do not generate thumbnails for image files exceeding this size: + + + + + KB + + + + + Auto Mount + + + + + Mount mountable volumes automatically on program startup + + + + + Mount removable media automatically when they are inserted + + + + + Show available options for removable media when they are inserted + + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + + + + + Terminal emulator: + + + + + Switch user command: + + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + + + + + Archiver integration: + + + + + Use SI decimal prefixes instead of IEC binary prefixes + + + + diff --git a/pcmanfm/translations/pcmanfm-qt_cs_CZ.ts b/pcmanfm/translations/pcmanfm-qt_cs_CZ.ts new file mode 100644 index 0000000..2008576 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_cs_CZ.ts @@ -0,0 +1,1075 @@ + + + + + AboutDialog + + + About + O + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + + Lightweight file manager + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + Authors + Autoři + + + + License + Licence + + + + AutoRunDialog + + + Removable medium is inserted + + + + + <b>Removable medium is inserted</b> + + + + + Type of medium: + + + + + Detecting... + + + + + Please select the action you want to perform: + + + + + DesktopPreferencesDialog + + + Desktop Preferences + + + + + Background + + + + + Wallpaper mode: + + + + + Wallpaper image file: + + + + + Select background color: + + + + + + Image file + + + + + Image file path + + + + + + &Browse + + + + + Label Text + + + + + Select text color: + + + + + Select shadow color: + + + + + Select font: + + + + + General + + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Pokročilé + + + + MainWindow + + + File Manager + Správce souborů + + + + Go Up + Nahoru + + + + Alt+Up + Alt+Nahoru + + + + Home + Domů + + + + Alt+Home + Alt+Home + + + + Reload + Obnovit + + + + F5 + F5 + + + + &Reload + &Obnovit + + + + Go + Jdi + + + + Quit + ukončit + + + + &About + &O programu + + + + New Window + Nové okno + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Zobrazit &skryté + + + + Ctrl+H + Ctrl+H + + + + &Computer + Počítač + + + + &Trash + &Koš + + + + &Network + Síť + + + + &Desktop + Plocha + + + + &Add to Bookmarks + Přidat k záložkám + + + + &Applications + Programy + + + + Ctrl+X + Ctrl+X + + + + &Copy + Kopírovat + + + + Ctrl+C + Ctrl+C + + + + &Paste + Vložit + + + + Ctrl+V + Ctrl+V + + + + Select &All + Vybrat všechno + + + + Pr&eferences + &Nastavení + + + + &Invert Selection + Invertovat výběr + + + + &Delete + Smazat + + + + &Rename + Přejmenovat + + + + Ctrl+A + Ctrl+A + + + + Go &Up + Nahoru + + + + &New Window + Nové &okno + + + + &Icon View + Pohled s ikonami + + + + &Compact View + Kompaktní pohled + + + + &Detailed List + Seznam s podrobnostmi + + + + &Thumbnail View + Pohled s náhledy + + + + Cu&t + Vyjmout + + + + Ascending + Vzestupně + + + + Descending + Sestupně + + + + By File Name + Podle jména + + + + By Modification Time + Podle času + + + + By File Type + Podle typu + + + + By Owner + Podle vlastníka + + + + Folder First + Složky jako první + + + + New &Tab + Nový &panel + + + + New Tab + Nový panel + + + + Ctrl+T + Ctrl+T + + + + Go &Back + Zpět + + + + Go Back + Zpět + + + + Alt+Left + Alt+Vlevo + + + + Go &Forward + &Vpřed + + + + Go Forward + Vpřed + + + + Alt+Right + Alt+Vpravo + + + + Del + + + + + F2 + F2 + + + + C&lose Tab + Zavřít panel + + + + File &Properties + Vlastnosti souboru + + + + &Folder Properties + Vlastnosti složky + + + + &Sorting + Řadit + + + + Main Toolbar + Hlavní panel + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Return + + + + Case Sensitive + Rozlišovat velikost písmen + + + + By File Size + Podle velikosti + + + + Close Window + Zavřít okno + + + + Edit Bookmarks + Upravit záložky + + + + Open &Terminal + Otevřít &terminál + + + + F4 + F4 + + + + Open as &Root + Otevřít jako &Root + + + + &Edit Bookmarks + Upravit záložky + + + + &File + &Soubor + + + + &Help + &Nápověda + + + + &View + &Zobrazení + + + + &Edit + Úpr&avy + + + + &Bookmarks + Zál&ožky + + + + &Go + &Jdi + + + + &Tool + Nás&troje + + + + PCManFM::Application + + + Name of configuration profile + + + + + PROFILE + + + + + Run PCManFM as a daemon + + + + + Quit PCManFM + + + + + Launch desktop manager + + + + + Turn off desktop manager if it's running + + + + + Open desktop preference dialog on the page with the specified name + + + + + + NAME + + + + + Open new window + + + + + Open Find Files utility + + + + + Set desktop wallpaper from image FILE + + + + + FILE + + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + + + + + MODE + + + + + Open Preferences dialog on the page with the specified name + + + + + Files or directories to open + + + + + [FILE1, FILE2,...] + + + + + + Error + + + + + Terminal emulator is not set. + + + + + PCManFM::AutoRunDialog + + + Open in file manager + + + + + Removable Disk + + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + + + + + Stretch to fill the entire screen + + + + + Stretch to fit the screen + + + + + Center on the screen + + + + + Tile the image to fill the entire screen + + + + + Image Files + + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + + + + + Desktop Preferences + + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + + + + + &Delete + Smazat + + + + + Error + + + + + Switch user command is not set. + + + + + PCManFM::PreferencesDialog + + + Icon View + + + + + Compact Icon View + + + + + Thumbnail View + + + + + Detailed List View + + + + + PCManFM::TabPage + + + Error + + + + + Free space: %1 (Total: %2) + + + + + %n item(s) + + + + + + + + + (%n hidden) + + + + + + + + + %1 item(s) selected + + + + + PCManFM::View + + + Open in New T&ab + + + + + Open in New Win&dow + + + + + Open in Termina&l + + + + + PreferencesDialog + + + Preferences + + + + + User Interface + Uživatelské rozhraní + + + + Behavior + Chování + + + + Thumbnail + Náhled + + + + Volume + + + + + Advanced + Pokročilé + + + + Icons + + + + + Size of big icons: + Velikost velkých ikon: + + + + Size of small icons: + Velikost malých ikon: + + + + Size of thumbnails: + Velikost náhledů: + + + + Size of side pane icons: + Velikost ikon v postranním panelu: + + + + Icon theme: + + + + + Window + + + + + Default width of new windows: + + + + + Default height of new windows: + + + + + Always show the tab bar + + + + + Show 'Close' buttons on tabs + + + + + Remember the size of the last closed window + + + + + Browsing + + + + + Open files with single click + + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + + + + + sec + + + + + File Operations + + + + + Confirm before deleting files + + + + + Move deleted files to "trash bin" instead of erasing from disk. + + + + + Show thumbnails of files + Zobrazovat náhledy souborů + + + + Only show thumbnails for local files + Zobrazovat náhlet jen u lokálních souborů + + + + Do not generate thumbnails for image files exceeding this size: + Negenerovat náhledy obrázků přesahujících tuto velikost: + + + + KB + + + + + Auto Mount + + + + + Mount mountable volumes automatically on program startup + + + + + Mount removable media automatically when they are inserted + + + + + Show available options for removable media when they are inserted + + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + + + + + Terminal emulator: + + + + + Switch user command: + + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + + + + + Archiver integration: + + + + + Use SI decimal prefixes instead of IEC binary prefixes + + + + diff --git a/pcmanfm/translations/pcmanfm-qt_de.ts b/pcmanfm/translations/pcmanfm-qt_de.ts new file mode 100644 index 0000000..4a272a5 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_de.ts @@ -0,0 +1,1083 @@ + + + + + AboutDialog + + + About + Über + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Ressourcen schonender Dateimanager + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder (nach Ihrer Option) jeder späteren Version. + +Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. + +Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA. + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programmierung: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + Authors + Autoren + + + + License + Lizenz + + + + AutoRunDialog + + + Removable medium is inserted + Ein entfernbares Speichermedium wurde eingelegt + + + + <b>Removable medium is inserted</b> + <b>Ein entfernbares Speichermedium wurde eingelegt</b> + + + + Type of medium: + Art des Mediums: + + + + Detecting... + Erkennungsvorgang... + + + + Please select the action you want to perform: + Bitte wählen Sie die Handlung, welche Sie ausführen möchten: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Arbeitsplatzeinstellungen + + + + Background + Hintergrund + + + + Wallpaper mode: + Hintergrundbildmodus: + + + + Wallpaper image file: + Hintergrundbild: + + + + Select background color: + Hintergrundfarbe: + + + + + Image file + Bilddatei + + + + Image file path + Pfad zur Bilddatei + + + + + &Browse + &Suchen + + + + Label Text + Text + + + + Select text color: + Farbe der Beschriftung: + + + + Select shadow color: + Farbe des Schattens: + + + + Select font: + Schrift für Beschriftung: + + + + General + Allgemeines + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + Beim Klicken auf den Arbeitsplatz die Menüs des Fenstermanagers anzeigen + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Erweitert + + + + MainWindow + + + File Manager + Dateimanager + + + + Go Up + Go Up + + + + Alt+Up + Alt+Up + + + + Home + Home + + + + Alt+Home + Alt+Home + + + + Reload + Ordner neu laden + + + + F5 + F5 + + + + &Reload + Ordner neu &laden + + + + Go + Gehe zu + + + + Quit + Fenster schließen + + + + &About + &Über + + + + New Window + Neues Fenster + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + &Versteckte anzeigen + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Geräte + + + + &Trash + &Papierkorb + + + + &Network + &Netzwerk + + + + &Desktop + Arbeits&fläche + + + + &Add to Bookmarks + Zu Favoriten &hinzufügen + + + + &Applications + &Anwendungen + + + + Ctrl+X + Ctrl+X + + + + &Copy + &Kopieren + + + + Ctrl+C + Ctrl+C + + + + &Paste + E&infügen + + + + Ctrl+V + Ctrl+V + + + + Select &All + &Alles markieren + + + + Pr&eferences + &Einstellungen + + + + &Invert Selection + Auswahl &umkehren + + + + &Delete + &Löschen + + + + &Rename + Um&benennen + + + + Ctrl+A + Ctrl+A + + + + Go &Up + &Übergeordneter Ordner + + + + &New Window + Neues &Fenster + + + + &Icon View + &Symbolansicht + + + + &Compact View + &Listenansicht + + + + &Detailed List + &Detailansicht + + + + &Thumbnail View + &Miniaturansicht + + + + Cu&t + &Ausschneiden + + + + Ascending + Aufsteigend + + + + Descending + Absteigend + + + + By File Name + Nach Name + + + + By Modification Time + Nach Änderungsdatum + + + + By File Type + Nach Dateityp + + + + By Owner + Nach Besitzer + + + + Folder First + Ordner zuerst + + + + New &Tab + Neuer &Reiter + + + + New Tab + Neuer Reiter + + + + Ctrl+T + Ctrl+T + + + + Go &Back + &Zurück + + + + Go Back + Zurück + + + + Alt+Left + Alt+Left + + + + Go &Forward + &Vorwärts + + + + Go Forward + Vorwärts + + + + Alt+Right + Alt+Right + + + + Del + Del + + + + F2 + F2 + + + + C&lose Tab + Reiter &schließen + + + + File &Properties + &Dateieigenschaften + + + + &Folder Properties + &Eigenschaften des aktuellen Ordners + + + + &Sorting + S&ortierung + + + + Main Toolbar + Hauptwerkzeugleiste + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Return + + + + Case Sensitive + Groß-/Kleinschreibung beachten + + + + By File Size + Nach Dateigröße + + + + Close Window + Fenster schließen + + + + Edit Bookmarks + Favoriten bearbeiten + + + + Open &Terminal + &Terminal öffnen + + + + F4 + F4 + + + + Open as &Root + Als &Root öffnen + + + + &Edit Bookmarks + &Favoriten bearbeiten + + + + &File + &Datei + + + + &Help + &Hilfe + + + + &View + &Ansicht + + + + &Edit + &Bearbeiten + + + + &Bookmarks + &Favoriten + + + + &Go + &Gehe zu + + + + &Tool + &Werkzeuge + + + + PCManFM::Application + + + Name of configuration profile + Name des Konfigurationsprofils + + + + PROFILE + PROFIL + + + + Run PCManFM as a daemon + PCManFM als Daemon starten + + + + Quit PCManFM + PCManFM beenden + + + + Launch desktop manager + Verwaltung der Arbeitsfläche starten + + + + Turn off desktop manager if it's running + Verwaltung der Arbeitsfläche beenden, falls aktiv + + + + Open desktop preference dialog on the page with the specified name + Einstellungsdialog der Arbeitsfläche mit dem angegebenen Reiter öffnen + + + + + NAME + NAME + + + + Open new window + Neues Fenster öffnen + + + + Open Find Files utility + Dateisuche öffnen + + + + Set desktop wallpaper from image FILE + Angegebene DATEI als Hintergrundbild einstellen + + + + FILE + DATEI + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Hintergrundbildmodus einstellen. MODUS=(color|stretch|fit|center|tile) + + + + MODE + MODUS + + + + Open Preferences dialog on the page with the specified name + Einstellungsdialog auf dem angegebenen Reiter öffnen + + + + Files or directories to open + Zu öfnende Dateien oder Ordner + + + + [FILE1, FILE2,...] + [DATEI1, DATEI2, ...] + + + + + Error + Fehler + + + + Terminal emulator is not set. + Es ist kein Terminalemulator eingestellt. + + + + PCManFM::AutoRunDialog + + + Open in file manager + In Dateimanager öffnen + + + + Removable Disk + Entfernbares Medium + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Nur mit Hintergrundfarbe füllen + + + + Stretch to fill the entire screen + Gefüllt + + + + Stretch to fit the screen + Gestreckt + + + + Center on the screen + Zentriert + + + + Tile the image to fill the entire screen + Nebeneinander + + + + Image Files + Bilddateien + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + Symbole &fixieren + + + + Desktop Preferences + Arbeitsplatzeinstellungen + + + + PCManFM::MainWindow + + + Version: %1 + Version: %1 + + + + &Move to Trash + In den &Papierkorb verschieben + + + + &Delete + &Löschen + + + + + Error + Fehler + + + + Switch user command is not set. + Befehl, um den Benutzer zu wechseln, ist nicht eingestellt. + + + + PCManFM::PreferencesDialog + + + Icon View + Symbolansicht + + + + Compact Icon View + Kleine Symbolansicht + + + + Thumbnail View + Miniaturansicht + + + + Detailed List View + Detaillierte Listenansicht + + + + PCManFM::TabPage + + + Error + Fehler + + + + Free space: %1 (Total: %2) + Freier Speicherplatz: %1 (Gesamt: %2) + + + + %n item(s) + + %n Objekt + %n Objekte + + + + + (%n hidden) + + (%n versteckt) + (%n versteckt) + + + + + %1 item(s) selected + %1 Objekte ausgewählt + + + + PCManFM::View + + + Open in New T&ab + In einem neuen &Reiter öffnen + + + + Open in New Win&dow + In einem neuen &Fenster öffnen + + + + Open in Termina&l + Im &Terminal öffnen + + + + PreferencesDialog + + + Preferences + Einstellungen + + + + User Interface + Benutzeroberfläche + + + + Behavior + Verhalten + + + + Thumbnail + Vorschaubild + + + + Volume + Datenträger + + + + Advanced + Erweitert + + + + Icons + Symbole + + + + Size of big icons: + Größe für große Symbole: + + + + Size of small icons: + Größe für kleine Symbole: + + + + Size of thumbnails: + Größe von Vorschaubildern: + + + + Size of side pane icons: + Größe der Symbole in der Seitenleiste: + + + + Icon theme: + Symbolthema: + + + + Window + Fenster + + + + Default width of new windows: + Breite für neue Fenster: + + + + Default height of new windows: + Höhe für neue Fenster: + + + + Always show the tab bar + Reiterleiste immer anzeigen + + + + Show 'Close' buttons on tabs + 'Schließen'-Knopf an Reitern zeigen + + + + Remember the size of the last closed window + Größe des zuletzt geschlossenen Fensters merken + + + + Browsing + Durchstöbern + + + + Open files with single click + Einfacher Klick zum Öffnen von Dateien + + + + Delay of auto-selection in single click mode (0 to disable) + Wartezeit für die automatische Auswahl im Einzelklickmodus (0 zum Abschalten) + + + + Default view mode: + Standardansicht: + + + + sec + sec + + + + File Operations + Dateioperationen + + + + Confirm before deleting files + Löschen von Dateien bestätigen + + + + Move deleted files to "trash bin" instead of erasing from disk. + Gelöschte Dateien in den "Papierkorb" verschieben anstatt sie von der Festplatte zu löschen. + + + + Show thumbnails of files + Vorschaubilder von Dateien anzeigen + + + + Only show thumbnails for local files + Vorschaubilder nur für lokale Dateien anzeigen + + + + Do not generate thumbnails for image files exceeding this size: + Keine Vorschaubilder erzeugen für Dateien größer als: + + + + KB + KB + + + + Auto Mount + Automatisches Einbinden + + + + Mount mountable volumes automatically on program startup + Datenträger bei Programmstart automatisch einhängen + + + + Mount removable media automatically when they are inserted + Wechseldatenträger automatisch beim Einlegen einbinden + + + + Show available options for removable media when they are inserted + Verfügbare Optionen für Wechseldatenträger beim Einlegen anzeigen + + + + When removable medium unmounted: + Wenn Wechseldatenträger ausgeworfen: + + + + Close tab containing removable medium + Schließe Tab mit Wechseldatenträger + + + + Change folder in the tab to home folder + Ändere Ordner im Tab zum Persönlichen Ordner + + + + Programs + Programme + + + + Terminal emulator: + Terminalemulator: + + + + Switch user command: + Befehl für Benutzerwechsel: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Beispiele:"xterm -e %s" für Terminal oder "gksu %s" für Benutzerwechsel. +%s = das Kommando, welches in einem Terminal oder als Root ausgeführt werden soll. + + + + Archiver integration: + Archivmanagerintegration: + + + + Use SI decimal prefixes instead of IEC binary prefixes + SI-Dezimalpräfixe anstatt IEC-Binärpräfixe verwenden + + + diff --git a/pcmanfm/translations/pcmanfm-qt_es.ts b/pcmanfm/translations/pcmanfm-qt_es.ts new file mode 100644 index 0000000..06e3eca --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_es.ts @@ -0,0 +1,1203 @@ + + + + + AboutDialog + + + About + Acerca de + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Administrador de archivos liviano + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + Authors + Autores + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programado por: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + License + Licencia + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + Administrador de archivos PCManFM + +Copyright (C) 2009-2014 洪 任 諭 (Hong Jen Yee) + +Este programa es software libre; puede redistribuirlo y / o +modificarlo bajo los términos de la Licencia Pública General GNU +publicada por la Fundación para el Software Libre; ya sea la versión 2 +de la Licencia, o (a su elección) cualquier versión posterior. + +Este programa se distribuye con la esperanza de que sea útil, +pero SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de +COMERCIALIZACIÓN o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Vea la +Licencia Pública General GNU para más detalles. + +Debería haber recibido una copia de la Licencia Pública General GNU +junto con este programa; si no, escriba a la Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + + AutoRunDialog + + + Removable medium is inserted + Disco removible insertado + + + + <b>Removable medium is inserted</b> + <b>Disco removible insertado</b> + + + + Type of medium: + Tipo de disco: + + + + Detecting... + Detectando... + + + + Please select the action you want to perform: + Seleccione la acción que desea ejecutar: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Preferencias de Escritorio + + + + General + General + + + + Background + Fondo + + + + Wallpaper mode: + Modo de papel tapiz: + + + + Wallpaper image file: + Imagen de papel tapiz: + + + + Select background color: + Seleccione color de fondo: + + + + + Image file + Archivo de imagen + + + + Image file path + Ruta de archivo de imagen + + + + + &Browse + E&xaminar + + + + Label Text + Texto de etiquetas + + + + Select text color: + Seleccione color de texto: + + + + Select shadow color: + Seleccione color de sombra: + + + + Select font: + Seleccione el tipo de letra: + + + + Window Manager + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Avanzado + + + + Show menus provided by window managers when desktop is clicked + Mostrar menús de los administradores de ventanas cuando se hace click sobre el escritorio + + + + FindFilesDialog + + Find Files + Buscar archivos + + + Name/Location + Nombre/Posición + + + File name patterns + Patrones de nombre de archivos + + + Pattern: + Patrón: + + + Case insensitive + No coincidir mayúsculas + + + Use regular expression + Usar expresión regular + + + Places to search + Lugares donde buscar + + + Add + Agregar + + + Remove + Eliminar + + + Search in sub directories + Buscar en sub directorios + + + Search hidden files + Buscar archivos ocultos + + + File Type + Tipo de Archivo + + + Only search for files of following types: + Solo buscar archivos de los siguientes tipos: + + + Text files + Archivos de texto + + + Image files + Archivos de imágenes + + + Audio files + Archivos de audio + + + Video files + Archivos de video + + + Documents + Documentos + + + Content + Contenido + + + File contains + Contenidos del archivo + + + Properties + Propiedades + + + File Size + Tamaño del Archivo + + + Bigger than: + Mayor a: + + + Smaller than: + Menor a: + + + Last Modified Time + Fecha de Modificación + + + Earlier than: + Antes de: + + + Later than: + Después de: + + + + MainWindow + + + File Manager + Administrador de archivos + + + + &File + &Archivo + + + + &Help + Ay&uda + + + + &View + &Ver + + + + &Sorting + &Ordenar + + + + &Edit + &Editar + + + + &Bookmarks + &Marcadores + + + + &Go + &Ir + + + + &Tool + &Herramientas + + + + Main Toolbar + Barra de Herramientas Principal + + + + Go &Up + S&ubir + + + + Go Up + Subir + + + + Alt+Up + Alt+Arriba + + + + Home + Carpeta personal + + + + Alt+Home + Alt+Inicio + + + + &Reload + &Recargar + + + + F5 + F5 + + + + Go + Ir + + + + Quit + Salir + + + + &About + &Acerca de + + + + &New Window + &Nueva ventana + + + + New Window + Nueva ventana + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Mo&strar ocultos + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Sistema + + + + &Trash + &Papelera + + + + &Network + &Red + + + + &Desktop + &Escritorio + + + + &Add to Bookmarks + &Agregar a marcadores + + + + &Applications + &Aplicaciones + + + + Reload + Recargar + + + + &Icon View + V&ista de Íconos + + + + &Compact View + Vista &Compacta + + + + &Detailed List + Lista &Detallada + + + + &Thumbnail View + Vista de &Miniaturas + + + + Cu&t + Cor&tar + + + + Ctrl+X + Ctrl+X + + + + &Copy + &Copiar + + + + Ctrl+C + Ctrl+C + + + + &Paste + &Pegar + + + + Ctrl+V + Ctrl+V + + + + Select &All + Seleccion&ar Todo + + + + Ctrl+A + Ctrl+A + + + + Pr&eferences + Pr&eferencias + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + By File Name + Por Nombre de Archivo + + + + By Modification Time + Por Fecha de Modificación + + + + By File Type + Por Tipo de Archivo + + + + By Owner + Por Dueño + + + + Folder First + Carpetas Primero + + + + New &Tab + Nueva &Pestaña + + + + New Tab + Nueva Pestaña + + + + Ctrl+T + Ctrl+T + + + + Go &Back + Re&troceder + + + + Go Back + Retroceder + + + + Alt+Left + Alt+Izquierda + + + + Go &Forward + A&vanzar + + + + Go Forward + Avanzar + + + + Alt+Right + Alt+Derecha + + + + &Invert Selection + &Invertir Selección + + + + &Delete + &Eliminar + + + + Del + Supr + + + + &Rename + Cambia&r Nombre + + + + F2 + F2 + + + + C&lose Tab + &Cerrar Pestaña + + + + Ctrl+W + Ctrl+W + + + + File &Properties + Propiedades de &Archivo + + + + Alt+Return + Alt+Enter + + + + &Folder Properties + &Propiedades de &Carpeta + + + + Case Sensitive + Coincidir Mayúsculas + + + + By File Size + Por Tamaño de Archivo + + + + Close Window + Cerrar Ventana + + + + Edit Bookmarks + Editar Marcadores + + + + Open &Terminal + Abrir &terminal + + + + F4 + F4 + + + + Open as &Root + Abrir como &root + + + + &Edit Bookmarks + &Editar Marcadores + + + + PCManFM::Application + + + Name of configuration profile + Nombre del perfil ce configuración + + + + PROFILE + PERFIL + + + + Run PCManFM as a daemon + Ejecutar PCManFM como un servicio + + + + Quit PCManFM + Cerrar PCManFM + + + + Launch desktop manager + Abrir administrador de escritorio + + + + Turn off desktop manager if it's running + Cerrar administrador de escritorio si está en ejecución + + + + Open desktop preference dialog on the page with the specified name + Abrir diálogo de preferencias de escritorio en la página especificada + + + + + NAME + NOMBRE + + + + Open new window + Abrir nueva ventana + + + + Open Find Files utility + Abrir búsqueda de archivos + + + + Set desktop wallpaper from image FILE + Configurar papel tapiz desde un archivo + + + + FILE + ARCHIVO + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Definir modo de papel tapiz. MODO =(color|estirar|ajustar|centrar|repetir) + + + + MODE + MODO + + + + Open Preferences dialog on the page with the specified name + Abrir diálogo de preferencias en la página especificada + + + + Files or directories to open + Archivos o directorios a abrir + + + + [FILE1, FILE2,...] + [Archivo 1, Archivo 2,...] + + + + + Error + Error + + + + Terminal emulator is not set. + El emulador de terminal no está configurado. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Abrir en administrador de archivos + + + + Removable Disk + Disco Removible + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Llenar solamente con el color de fondo + + + + Stretch to fill the entire screen + Estirar para llenar la pantalla + + + + Stretch to fit the screen + Estirar para ajustar a la pantalla + + + + Center on the screen + Centrar en la pantalla + + + + Tile the image to fill the entire screen + Repetir la imagen hasta llenar la pantalla + + + + Image Files + Archivos de Imagen + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + &Pegar en la posición actual + + + + Desktop Preferences + Preferencias de Escritorio + + + + PCManFM::MainWindow + + + Version: %1 + Versión: %1 + + + + &Move to Trash + &Mover a la Papelera + + + + &Delete + &Eliminar + + + + + Error + Error + + + + Switch user command is not set. + El comando para cambiar de usuario no está definido. + + + + PCManFM::PreferencesDialog + + + Icon View + Vista de Íconos + + + + Compact Icon View + Vista Compacta de Íconos + + + + Thumbnail View + Vista de Miniaturas + + + + Detailed List View + Lista Detallada + + + + PCManFM::TabPage + + + Error + Error + + + + Free space: %1 (Total: %2) + Espacio libre: %1 (Total %2) + + + + %n item(s) + + %n elemento + %n elementos + + + + + (%n hidden) + + (%n oculto) + (%n ocultos) + + + + + %1 item(s) selected + %1 elemento(s) seleccionado(s) + + + + PCManFM::View + + + Open in New T&ab + &Abrir en Nueva Pestaña + + + + Open in New Win&dow + Abrir en Nueva &Ventana + + + + Open in Termina&l + Abrir en Termina&l + + + + PreferencesDialog + + + Preferences + Preferencias + + + + User Interface + Interfaz de Usuario + + + + Behavior + Comportamiento + + + + Thumbnail + Miniaturas + + + + Volume + Volumen + + + + Advanced + Avanzado + + + + Icons + Íconos + + + + Size of big icons: + Tamaño de íconos grandes: + + + + Size of small icons: + Tamaño de íconos pequeños: + + + + Size of thumbnails: + Tamaño de miniaturas: + + + + Size of side pane icons: + Tamaño de íconos del panel lateral: + + + + Icon theme: + Tema de íconos: + + + + Window + Ventana + + + + Always show the tab bar + Mostrar siempre la barra de pestañas + + + + Show 'Close' buttons on tabs + Mostrar botones de cerrar en las pestañas + + + + Remember the size of the last closed window + Recordar el tamaño de la última ventana cerrada + + + + Default width of new windows: + Ancho para nuevas ventanas: + + + + Default height of new windows: + Altura para nuevas ventanas: + + + + Browsing + Navegación + + + + Open files with single click + Abrir archivos con un solo click + + + + Delay of auto-selection in single click mode (0 to disable) + Demora de selección automática en modo de un click (0 para deshabilitar) + + + + Default view mode: + Modo de visualización por defecto: + + + + sec + seg + + + + File Operations + Operaciones de Archivos + + + + Confirm before deleting files + Confirmar antes de borrar + + + + Move deleted files to "trash bin" instead of erasing from disk. + Mover archivos a la papelera en lugar de eliminarlos del disco. + + + + Show thumbnails of files + Mostrar miniaturas de archivos + + + + Only show thumbnails for local files + Solo mostrar miniaturas para archivos locales + + + + Do not generate thumbnails for image files exceeding this size: + No generar miniaturas para archivos de imágenes mayores a: + + + + KB + KB + + + + Auto Mount + Montar Automáticamente + + + + Mount mountable volumes automatically on program startup + Montar discos removibles automáticamente al inicio + + + + Mount removable media automatically when they are inserted + Montar discos removibles automáticamente cuando se insertan + + + + Show available options for removable media when they are inserted + Mostrar opciones disponibles para los discos removibles al insertarlos + + + + When removable medium unmounted: + Cuando se desconecta un disco removible: + + + + Close tab containing removable medium + Cerrar la pestaña que contiene al disco removible + + + + Change folder in the tab to home folder + Cambiar el directorio en la pestaña a la carpeta personal + + + + Programs + Programas + + + + Terminal emulator: + Emulador de terminal: + + + + Switch user command: + Comando para cambiar de usuario: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Ejemplos: "xterm -e %s" para terminal o "gksu %s" para cambiar de usuario. +%s = la línea de comandos a ejecutar en la terminal o como otro usuario. + + + + Archiver integration: + Integración con programas de archivo: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Usar prefijos decimales SI en lugar de prefijos binarios IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_fr.ts b/pcmanfm/translations/pcmanfm-qt_fr.ts new file mode 100644 index 0000000..2bbcab0 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_fr.ts @@ -0,0 +1,1141 @@ + + + + + AboutDialog + + + About + À propos + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Gestionnaire de fichiers léger + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + Gestionnaire de fichiers de PCMan + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +Ce programme est du logiciel libre ; vous le redistribuer +avec ou sans modification sous les termes de la licence pu- +blique générale GNU telle que publiée par le fondation pour +le logiciel libre, soit en version 2, soit en n'importe quelle +version ultérieure (à votre discrétion). + +Ce programme est distribué dans l'espoir qu'il soit utile, +mais SANS AUCUNE GARANTIE ; sans même la garantie impli- +cite de QUALITÉ MARCHANDE ou d'APTITUDE À UN CERTAIN +BUT. Voir la licence publique générale GNU pour de plus am- +ples détails. + +Vous devriez avoir reçu une copie de la licence publique géné- +rale GNU avec ce programme ; si ce n'est pas le cas, écrivez à la +fondation pour le logiciel libre à l'adresse ci-dessous : +Free Software Foundation, Inc.n 51 Franklin Street, +Fifth Floor, Boston, MA 02110-1301, USA. {2009 ?} {2014 ?} {2 +?} {51 ?} {02110-1301,?} + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programmation : +Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + Authors + Auteurs + + + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +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. + Gestionnaire de fichiers de PCMan + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +Ce programme est du logiciel libre ; vous le redistribuer +avec ou sans modification sous les termes de la licence pu- +blique générale GNU telle que publiée par le fondation pour +le logiciel libre, soit en version 2, soit en n'importe quelle +version ultérieure (à votre discrétion). + +Ce programme est distribué dans l'espoir qu'il soit utile, +mais SANS AUCUNE GARANTIE ; sans même la garantie impli- +cite de QUALITÉ MARCHANDE ou d'APTITUDE À UN CERTAIN +BUT. Voir la licence publique générale GNU pour de plus am- +ples détails. + +Vous devriez avoir reçu une copie de la licence publique géné- +rale GNU avec ce programme ; si ce n'est pas le cas, écrivez à la +fondation pour le logiciel libre à l'adresse ci-dessous : +Free Software Foundation, Inc.n 51 Franklin Street, +Fifth Floor, Boston, MA 02110-1301, USA. + + + + License + Licence + + + + AutoRunDialog + + + Removable medium is inserted + Un média amovible a été inséré + + + + <b>Removable medium is inserted</b> + <b>Un média amovible a été inséré</b> + + + + Type of medium: + Type de média : + + + + Detecting... + Détection en cours... + + + + Please select the action you want to perform: + Veuillez sélectionner l'action que vous voulez effectuer : + + + + DesktopPreferencesDialog + + + Desktop Preferences + Préférences du bureau + + + + Background + Arrière-plan + + + + Wallpaper mode: + Mode du fond d'écran : + + + + Wallpaper image file: + Fichier image du fond d'écran : + + + + Select background color: + Sélectionnez la couleur d'arrière-plan : + + + + + Image file + Fichier image + + + + Image file path + Chemin du fichier image + + + + + &Browse + &Parcourir + + + + Label Text + Texte de l'étiquette + + + + Select text color: + Sélectionnez la couleur du texte : + + + + Select shadow color: + Sélectionnez la couleur de l'ombre : + + + + Select font: + Sélectionnez la police : + + + + General + Général + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + Afficher les menus fournis par les gestionnaires de fenêtres lorsqu'on clique sur le bureau + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Avancé + + + + MainWindow + + + File Manager + Gestionnaire de fichiers + + + + Go Up + Monter + + + + Alt+Up + Alt+Haut + + + + Home + Page d'accueil + + + + Alt+Home + Alt+Début / Origine + + + + Reload + Recharger + + + + F5 + F5 + + + + &Reload + &Recharger + + + + Go + Aller à… + + + + Quit + Quitter + + + + &About + &À propos + + + + New Window + Nouvelle fenêtre + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Afficher les éléments cac&hés + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Ordinateur + + + + &Trash + &Corbeille + + + + &Network + &Réseau + + + + &Desktop + &Bureau + + + + &Add to Bookmarks + &Ajouter aux signets + + + + &Applications + &Applications + + + + Ctrl+X + Ctrl+X + + + + &Copy + &Copier + + + + Ctrl+C + Ctrl+C + + + + &Paste + &Coller + + + + Ctrl+V + Ctrl+V + + + + Select &All + Tout sélect&ionner + + + + Pr&eferences + Préfér&ences + + + + &Invert Selection + &Inverser la sélection + + + + &Delete + &Supprimer + + + + &Rename + &Renommer + + + + Ctrl+A + Ctrl+A + + + + Go &Up + Mon&ter + + + + &New Window + &Nouvelle fenêtre + + + + &Icon View + Vue en &icônes + + + + &Compact View + Vue &compacte + + + + &Detailed List + Liste &détaillée + + + + &Thumbnail View + Vue en vigne&ttes + + + + Cu&t + Cou&per + + + + Ascending + Ascendant + + + + Descending + Descendant + + + + By File Name + Par nom de fichier + + + + By Modification Time + Par date de modification + + + + By File Type + Par type de fichier + + + + By Owner + Par propriétaire + + + + Folder First + Dossier en premier + + + + New &Tab + Nouvel ongle&t + + + + New Tab + Nouvel onglet + + + + Ctrl+T + Ctrl+T + + + + Go &Back + Re&culer + + + + Go Back + Reculer + + + + Alt+Left + Alt+Gauche + + + + Go &Forward + Ava&ncer + + + + Go Forward + Avancer + + + + Alt+Right + Alt+Droite + + + + Del + Suppr + + + + F2 + F2 + + + + C&lose Tab + Fermer &l'onglet + + + + File &Properties + &Propriétés du fichier + + + + &Folder Properties + Propriétés du &dossier + + + + &Sorting + Tri en cour&s + + + + Main Toolbar + Barre d'outils principale + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Entrée + + + + Case Sensitive + Sensible à la casse + + + + By File Size + Par taille de fichier + + + + Close Window + Fermer la fenêtre + + + + Edit Bookmarks + Modifier les signets + + + + Open &Terminal + Ouvrir le &terminal + + + + F4 + F4 + + + + Open as &Root + Ouvrir en tant que &root + + + + &Edit Bookmarks + Modifi&er les signets + + + + &File + &Fichier + + + + &Help + &Aide + + + + &View + + + + + &Edit + &Édition + + + + &Bookmarks + &Signets + + + + &Go + A&ller à… + + + + &Tool + Ou&tils + + + + PCManFM::Application + + + Name of configuration profile + Nom du profil de configuration + + + + PROFILE + PROFIL + + + + Run PCManFM as a daemon + Lancer PCManFM comme démon + + + + Quit PCManFM + Quitter PCManFM + + + + Launch desktop manager + Lancer le gestionnaire de bureau + + + + Turn off desktop manager if it's running + Éteindre le gestionnaire de bureau s'il fonctionne + + + + Open desktop preference dialog on the page with the specified name + Ouvrir la boîte de dialogue des préférences du bureau sur la page avec le nom spécifié + + + + + NAME + NAME + + + + Set desktop wallpaper from image FILE + Définir le fond d'écran de bureau depuis l'image FILE + + + + FILE + FILE + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Définir le mode de fond d'écran de bureau. MODE=(couleur|étirer|ajuster|centrer|découper) + + + + MODE + MODE + + + + Open Preferences dialog on the page with the specified name + Ouvrir la boîte de dialogue des préférences sur la page avec le nom spécifié + + + + Open new window + Ouvrir une nouvelle fenêtre + + + + Open Find Files utility + Ouvrir l'utilitaire de recherche de fichiers + + + + [FILE1, FILE2,...] + [FILE1, FILE2, etc.] + + + + Files or directories to open + + + + + + Error + Erreur + + + + Terminal emulator is not set. + L'émulateur de terminal n'est pas défini. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Ouvrir dans le gestionnaire de fichiers + + + + Removable Disk + Disque amovible + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Remplir seulement avec la couleur d'arrière-plan + + + + Stretch to fill the entire screen + Étirer pour remplir l'écran entier + + + + Stretch to fit the screen + Étirer pour remplir l'écran + + + + Center on the screen + Centrer sur l’écran + + + + Tile the image to fill the entire screen + Faire une mosaïque avec l'image pour remplir l'écran entier + + + + Image Files + Fichiers image + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + Res&ter à la position actuelle + + + + Desktop Preferences + Préférences du bureau + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + &Mettre à la corbeille + + + + &Delete + &Supprimer + + + + + Error + Erreur + + + + Switch user command is not set. + La commande de changement d’utilisateur n'est pas configurée. + + + + PCManFM::PreferencesDialog + + + Icon View + Vue en icônes + + + + Compact Icon View + Vue en icônes compacte + + + + Thumbnail View + Vue en vignettes + + + + Detailed List View + Vue en liste détaillée + + + + PCManFM::TabPage + + + Error + Erreur + + + + Free space: %1 (Total: %2) + Espace libre: %1 (total : %2) + + + + %n item(s) + + %n élément + %n éléments + + + + + (%n hidden) + + (%n caché) + (%n cachés) + + + + + %1 item(s) selected + %1 élément(s) sélectionné(s) + + + + PCManFM::View + + + Open in New T&ab + Ouvrir dans un nouvel ongle&t + + + + Open in New Win&dow + Ouvrir &dans une nouvelle fenêtre + + + + Open in Termina&l + Ouvrir dans &le terminal + + + + PreferencesDialog + + + Preferences + Préférences + + + + User Interface + Interface utilisateur + + + + Behavior + Comportement + + + + Thumbnail + Vignette + + + + Volume + Volume + + + + Advanced + Avancé + + + + Icons + Icônes + + + + Size of big icons: + Taille des grandes icônes : + + + + Size of small icons: + Taille des petites icônes : + + + + Size of thumbnails: + Taille des vignettes : + + + + Size of side pane icons: + Taille des icônes de panneau latéral : + + + + Icon theme: + Thème d'icônes : + + + + Window + Fenêtre + + + + Default width of new windows: + Largeur par défaut des nouvelles fenêtres : + + + + Default height of new windows: + Hauteur par défaut des nouvelles fenêtres : + + + + Always show the tab bar + Toujours afficher la barre des onglets + + + + Show 'Close' buttons on tabs + Afficher le bouton « Fermer » sur les onglets + + + + Remember the size of the last closed window + + + + + Browsing + Navigation + + + + Open files with single click + Ouvrir les fichiers avec un simple clic + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + Mode de vue par défaut : + + + + sec + + + + + File Operations + Opérations sur les fichiers + + + + Confirm before deleting files + Confirmer avant de supprimer les fichiers + + + + Move deleted files to "trash bin" instead of erasing from disk. + Mettre les fichiers supprimés à la corbeille eu lieu de les effacer du disque. + + + + Show thumbnails of files + Montrer les vignettes des fichiers + + + + Only show thumbnails for local files + Montrer les vignettes seulement pour les fichiers locaux + + + + Do not generate thumbnails for image files exceeding this size: + Ne pas générer de vignettes pour les fichiers image excédant cette taille : + + + + KB + Ko + + + + Auto Mount + Monter automatiquement + + + + Mount mountable volumes automatically on program startup + Monter automatiquement les volumes au démarrage du programme + + + + Mount removable media automatically when they are inserted + Monter automatiquement les médias amovibles lorsqu'ils sont insérés + + + + Show available options for removable media when they are inserted + Montrer les options disponibles pour les médias amovibles lorsqu'ils sont insérés + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + Programmes + + + + Terminal emulator: + Émulateur de terminal : + + + + Switch user command: + Commande de changement d'utilisateur : + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Exemples : « xterm -e %s » pour le terminal ; « gksu %s » pour changer d’utilisateur. +%s = la ligne de commande que vous voulez exécuter avec le terminal ou su. + + + + Archiver integration: + Intégration du logiciel de compression de données : + + + + Use SI decimal prefixes instead of IEC binary prefixes + Utiliser les préfixes de décimales du système international d'unités au lieu des préfixes binaires de l'IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_gl.ts b/pcmanfm/translations/pcmanfm-qt_gl.ts new file mode 100644 index 0000000..82bffab --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_gl.ts @@ -0,0 +1,1133 @@ + + + + + AboutDialog + + + About + Sobre + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Un xestor de xanelas lixeiro + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +Este programa é software libre; pode distribuílo e/ou +modificalo baixo os termos da Licenza Pública Xeral GNU +tal como foi publicada pola Free Software Foundation; tanto na versión 2 +da Licenza, como (segundo o seu criterio) calquera versión posterior. + +Este programa distribúese coa esperanza de que sexa útil, +pero SEN NINGUNHA GARANTÍA; nin sequera a garantíia implícita de +COMERCIALIZACIÓN ou ADECUACIÖN PARA UN PROPÓSITO ESPECÍFICO. +Vexa a Licenza Pública Xeral GNU para obter mais detalles. + +Debe ter recibido unha copia da Licenza Pública Xeral GNU +con este programa; se non é así, escriba á Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. {2009 ?} {2014 ?} {2 +?} {51 ?} {02110-1301,?} + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programación: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + Authors + Autores + + + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +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. + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +Este programa é software libre; pode distribuílo e/ou +modificalo baixo os termos da Licenza Pública Xeral GNU +tal como foi publicada pola Free Software Foundation; tanto na versión 2 +da Licenza, como (segundo o seu criterio) calquera versión posterior. + +Este programa distribúese coa esperanza de que sexa útil, +pero SEN NINGUNHA GARANTÍA; nin sequera a garantíia implícita de +COMERCIALIZACIÓN ou ADECUACIÖN PARA UN PROPÓSITO ESPECÍFICO. +Vexa a Licenza Pública Xeral GNU para obter mais detalles. + +Debe ter recibido unha copia da Licenza Pública Xeral GNU +con este programa; se non é así, escriba á Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + + License + Licenza + + + + AutoRunDialog + + + Removable medium is inserted + Foi inserido un dispositivo removíbel + + + + <b>Removable medium is inserted</b> + <b>Foi inserido un dispositivo removíbel</b> + + + + Type of medium: + Tipo de dispositivo: + + + + Detecting... + Detectando... + + + + Please select the action you want to perform: + Escolla a acción que quere realizar: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Preferencias do escritorio + + + + Background + Fondo + + + + Wallpaper mode: + Modo do fondo de escritorio: + + + + Wallpaper image file: + Ficheiro de imaxe do fondo de escritorio: + + + + Select background color: + Escoller a cor do fondo: + + + + + Image file + Ficheiro de imaxe + + + + Image file path + Ruta ao ficheiro de imaxe + + + + + &Browse + &Examinar + + + + Label Text + Texto da etiqueta + + + + Select text color: + Escoller a cor do texto: + + + + Select shadow color: + Escoller a cor da sombra: + + + + Select font: + Escoller o tipo de letra: + + + + General + Xeral + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + Amosar os menús fornecidos polos xestores de xanelas cando se preme no escritorio + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Avanzado + + + + MainWindow + + + File Manager + Xestor de ficheiros + + + + Go Up + Subir + + + + Alt+Up + Alt+Frecha arriba + + + + Home + Inicio + + + + Alt+Home + Alt+Inicio + + + + Reload + Cargar de novo + + + + F5 + F5 + + + + &Reload + &Cargar de novo + + + + Go + Ir para + + + + Quit + Saír + + + + &About + &Sobre + + + + New Window + Nova xanela + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Amosar a&gochados + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Computador + + + + &Trash + &Lixo + + + + &Network + &Rede + + + + &Desktop + &Escritorio + + + + &Add to Bookmarks + En&gadir aos marcadores + + + + &Applications + &Aplicacións + + + + Ctrl+X + Ctrl-X + + + + &Copy + &Copiar + + + + Ctrl+C + Ctrl+C + + + + &Paste + &Pegar + + + + Ctrl+V + Ctrl+V + + + + Select &All + Seleccionar &todo + + + + Pr&eferences + Pre&ferencias + + + + &Invert Selection + &Inverter a selección + + + + &Delete + &Eliminar + + + + &Rename + &Renomear + + + + Ctrl+A + Ctrl+A + + + + Go &Up + S&ubir + + + + &New Window + &Nova xanela + + + + &Icon View + Vista de &iconas + + + + &Compact View + Vista &compacta + + + + &Detailed List + Vista &detallada + + + + &Thumbnail View + Vista de &miniaturas + + + + Cu&t + Cor&tar + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + By File Name + Polo nome do ficheiro + + + + By Modification Time + Pola data de modificación + + + + By File Type + Polo tipo do ficheiro + + + + By Owner + Polo propietario + + + + Folder First + Primeiro os cartafoles + + + + New &Tab + Nova &lapela + + + + New Tab + Nova lapela + + + + Ctrl+T + Ctrl+T + + + + Go &Back + A&trás + + + + Go Back + Ir cara atrás + + + + Alt+Left + Alt+Frecha esquerda + + + + Go &Forward + Adian&te + + + + Go Forward + Adiante + + + + Alt+Right + Alt+Frecha dereita + + + + Del + Supr + + + + F2 + F2 + + + + C&lose Tab + &Pechar a lapela + + + + File &Properties + &Propiedades do ficheiro + + + + &Folder Properties + Propiedades do &cartafol + + + + &Sorting + &Ordenación + + + + Main Toolbar + Barra de ferramentas principal + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Intro + + + + Case Sensitive + Distinguindo maiúsculas de minúsculas + + + + By File Size + Polo tamaño do ficheiro + + + + Close Window + Pechar a xanela + + + + Edit Bookmarks + Editar os marcadores + + + + Open &Terminal + Abrir un &terminal + + + + F4 + F4 + + + + Open as &Root + Abrir como &root + + + + &Edit Bookmarks + &Editar marcadores + + + + &File + &Ficheiro + + + + &Help + &Axuda + + + + &View + &Ver + + + + &Edit + &Editar + + + + &Bookmarks + &Marcadores + + + + &Go + &Ir para + + + + &Tool + &Ferramenta + + + + PCManFM::Application + + + Name of configuration profile + Nome do perfil de configuración + + + + PROFILE + PERFIL + + + + Run PCManFM as a daemon + Executar PCManFM como un servizo + + + + Quit PCManFM + Saír do PCManFM + + + + Launch desktop manager + Iniciar o xestor de escritorio + + + + Turn off desktop manager if it's running + Apagar o xestor de escritorio se está en execución + + + + Open desktop preference dialog on the page with the specified name + Abrir o diálogo de preferencias do escritorio na páxina co nome especificado + + + + + NAME + NOME + + + + Set desktop wallpaper from image FILE + Estabelecer o fondo de pantalla do escritorio desde o FICHEIRO de imaxe + + + + FILE + FICHEIRO + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Axuste o modo de fondo de escritorio. MODO=(color|stretch|fit|center|tile) + + + + MODE + MODO + + + + Open Preferences dialog on the page with the specified name + Abrir o diálogo de preferencias do escritorio na páxina co nome especificado + + + + Open new window + Abrir unha nova xanela + + + + Open Find Files utility + Abrir a utilidade de busca de ficheiros + + + + [FILE1, FILE2,...] + [FICHEIRO1, FICHEIRO2,...] + + + + Files or directories to open + + + + + + Error + Erro + + + + Terminal emulator is not set. + Non foi estabelecido o emulador de terminal + + + + PCManFM::AutoRunDialog + + + Open in file manager + Abrir no xestor de ficheiros + + + + Removable Disk + Disco extraíbel + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Encher só coa cor de fondo + + + + Stretch to fill the entire screen + Estirar para encher a pantalla completa + + + + Stretch to fit the screen + Estirar para adaptar á pantalla + + + + Center on the screen + Centrar na pantalla + + + + Tile the image to fill the entire screen + Facer mosaico coa imaxe para encher a pantalla completa + + + + Image Files + Ficheiros de imaxe + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + &Permanente na posición actual + + + + Desktop Preferences + Preferencias do escritorio + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + &Mover ao lixo + + + + &Delete + &Eliminar + + + + + Error + Erro + + + + Switch user command is not set. + A orde para cambiar de usuario non está configurada. + + + + PCManFM::PreferencesDialog + + + Icon View + Vista en Iconas + + + + Compact Icon View + Vista compacta en iconas + + + + Thumbnail View + Vista de miniaturas + + + + Detailed List View + Ver como lista detallada + + + + PCManFM::TabPage + + + Error + Erro + + + + Free space: %1 (Total: %2) + Espazo libre: %1 (Total: %2) + + + + %n item(s) + + %n elemento + %n elementos + + + + + (%n hidden) + +  (%n agochado) +  (%n agochados) + + + + + %1 item(s) selected + Escolleu %1 elemento(s) + + + + PCManFM::View + + + Open in New T&ab + Abrir nunha nova l&apela + + + + Open in New Win&dow + Abrir nunha nova xa&nela + + + + Open in Termina&l + Abrir nun termina&l + + + + PreferencesDialog + + + Preferences + Preferencias + + + + User Interface + Interface de usuario + + + + Behavior + Comportamento + + + + Thumbnail + Miniatura + + + + Volume + Volume + + + + Advanced + Avanzado + + + + Icons + Iconas + + + + Size of big icons: + Tamaño das iconas grandes: + + + + Size of small icons: + Tamaño das iconas pequenas: + + + + Size of thumbnails: + Tamaño das miniaturas: + + + + Size of side pane icons: + Tamaño das iconas do panel lateral: + + + + Icon theme: + Tema de iconas: + + + + Window + Xanela + + + + Default width of new windows: + Largo predeterminado para as novas xanelas: + + + + Default height of new windows: + Alto predeterminado para as novas xanelas: + + + + Always show the tab bar + Amosar sempre a barra de lapelas + + + + Show 'Close' buttons on tabs + Amosar os botóns de «Pechar» nas lapelas + + + + Remember the size of the last closed window + + + + + Browsing + Navegando + + + + Open files with single click + Abrir os ficheiros cun só clic + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + Modo de vista predeterminado: + + + + sec + + + + + File Operations + Operacións de ficheiro + + + + Confirm before deleting files + Confirmar antes de eliminar os ficheiros + + + + Move deleted files to "trash bin" instead of erasing from disk. + Mover os ficheiros eliminados ao «cesto do lixo» no canto de borralos do disco. + + + + Show thumbnails of files + Amosar miniaturas dos ficheiros + + + + Only show thumbnails for local files + Amosar só as miniaturas dos ficheiros locais + + + + Do not generate thumbnails for image files exceeding this size: + Non xerar miniaturas dos ficheiros de imaxe se o tamaño excede de: + + + + KB +  KB + + + + Auto Mount + Montaxe automático + + + + Mount mountable volumes automatically on program startup + Montar os volumes montábeis automaticamente no arrinque do programa + + + + Mount removable media automatically when they are inserted + Montar os dispositivos removíbeis automaticamente ao seren inseridos + + + + Show available options for removable media when they are inserted + Amosar as opción para os dispositivos removíbeis ao seren inseridos + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + Programas + + + + Terminal emulator: + Emulador de terminal: + + + + Switch user command: + Orde de cambio de usuario: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Exemplos: «xterm -e %s» para o terminal ou «gksu %s» para cambiar de usuario. +%s = á liña de ordes que quere executar co terminal ou como superusario. + + + + Archiver integration: + Integración do «Archiver»: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Utilizar prefixos decimais SI no canto de prefixos binarios IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_it.ts b/pcmanfm/translations/pcmanfm-qt_it.ts new file mode 100644 index 0000000..833e512 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_it.ts @@ -0,0 +1,1080 @@ + + + + + AboutDialog + + + About + Informazioni + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Gestore file leggero + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programmazione: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + Authors + Autori + + + + License + Licenza + + + + AutoRunDialog + + + Removable medium is inserted + Supporto removibile inserito + + + + <b>Removable medium is inserted</b> + <b>Supporto removibile inserito</b> + + + + Type of medium: + Tipo di supporto: + + + + Detecting... + Rilevamento... + + + + Please select the action you want to perform: + Scegliere l'azione da eseguire: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Preferenze della scrivania + + + + Background + Sfondo + + + + Wallpaper mode: + Modalità sfondo: + + + + Wallpaper image file: + File immagine sfondo: + + + + Select background color: + Scegliere colore sfondo: + + + + + Image file + File immagine + + + + Image file path + Percorso file immagine + + + + + &Browse + &Sfoglia + + + + Label Text + Testo etichette + + + + Select text color: + Scegliere colore testo: + + + + Select shadow color: + Scegliere colore ombra: + + + + Select font: + Scegliere carattere: + + + + General + Generali + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + Mostra menu forniti dai gestori finestre quando si fa clic sulla Scrivania + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Avanzate + + + + MainWindow + + + File Manager + Gestore file + + + + Go Up + Vai su + + + + Alt+Up + Alt+Su + + + + Home + Cartella home + + + + Alt+Home + Alt+Inizio + + + + Reload + Ricarica + + + + F5 + F5 + + + + &Reload + &Ricarica + + + + Go + Vai + + + + Quit + Esci + + + + &About + &Informazioni + + + + New Window + Nuova finestra + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Mostra &nascosti + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Computer + + + + &Trash + Ces&tino + + + + &Network + &Rete + + + + &Desktop + &Scrivania + + + + &Add to Bookmarks + &Aggiungi ai segnalibri + + + + &Applications + &Applicazioni + + + + Ctrl+X + Ctrl+X + + + + &Copy + &Copia + + + + Ctrl+C + Ctrl+C + + + + &Paste + &Incolla + + + + Ctrl+V + Ctrl+V + + + + Select &All + Seleziona t&utto + + + + Pr&eferences + Pr&eferenze + + + + &Invert Selection + &Inverti selezione + + + + &Delete + &Rimuovi + + + + &Rename + &Rinomina + + + + Ctrl+A + Ctrl+A + + + + Go &Up + Vai &su + + + + &New Window + &Nuova finestra + + + + &Icon View + Vista &icone + + + + &Compact View + Vista &compatta + + + + &Detailed List + Elenco &dettagliato + + + + &Thumbnail View + Vista minia&ture + + + + Cu&t + &Taglia + + + + Ascending + Crescente + + + + Descending + Decrescente + + + + By File Name + Per nome file + + + + By Modification Time + Per data modifica + + + + By File Type + Per tipo file + + + + By Owner + Per proprietario + + + + Folder First + Prima le cartelle + + + + New &Tab + Nuova sc&heda + + + + New Tab + Nuova scheda + + + + Ctrl+T + Ctrl+T + + + + Go &Back + Vai in&dietro + + + + Go Back + Va indietro + + + + Alt+Left + Alt+Sinistra + + + + Go &Forward + Vai &avanti + + + + Go Forward + Va avanti + + + + Alt+Right + Alt+Destra + + + + Del + Canc + + + + F2 + F2 + + + + C&lose Tab + C&hiudi scheda + + + + File &Properties + &Proprietà file + + + + &Folder Properties + Proprietà &cartella + + + + &Sorting + &Ordinamento + + + + Main Toolbar + Barra strumenti principale + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Invio + + + + Case Sensitive + Distingui MAIUSCOLE/minuscole + + + + By File Size + Per dimensione file + + + + Close Window + Chiudi finestra + + + + Edit Bookmarks + Modifica segnalibri + + + + Open &Terminal + Apri &terminale + + + + F4 + F4 + + + + Open as &Root + Apri come &root + + + + &Edit Bookmarks + &Modifica segnalibri + + + + &File + &File + + + + &Help + A&iuto + + + + &View + &Visualizza + + + + &Edit + &Modifica + + + + &Bookmarks + &Segnalibri + + + + &Go + &Vai + + + + &Tool + S&trumenti + + + + PCManFM::Application + + + Name of configuration profile + Nome del profilo di configurazione + + + + PROFILE + PROFILO + + + + Run PCManFM as a daemon + Esegue PCManFM come demone + + + + Quit PCManFM + Esce da PCManFM + + + + Launch desktop manager + Lancia il gestore della scrivania + + + + Turn off desktop manager if it's running + Spegne il gestore della scrivania se è in esecuzione + + + + Open desktop preference dialog on the page with the specified name + Apre le preferenze della scrivania alla pagina con il nome specificato + + + + + NAME + NOME + + + + Set desktop wallpaper from image FILE + Imposta lo sfondo della scrivania con l'immagine dal FILE + + + + FILE + FILE + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Imposta la modalità dello sfondo della scrivania. MODO=(color|stretch|fit|center|tile) + + + + MODE + MODE + + + + Open Preferences dialog on the page with the specified name + Apre le Preferenze alla pagina con il nome specificato + + + + Open new window + Apre una nuova finestra + + + + Open Find Files utility + Apre l'utilità di ricerca file + + + + [FILE1, FILE2,...] + [FILE1, FILE2, ...] + + + + Files or directories to open + + + + + + Error + Errore + + + + Terminal emulator is not set. + L'emulatore di terminale non è impostato. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Apre nel gestore file + + + + Removable Disk + Disco rimovibile + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Riempi solo con il colore di sfondo + + + + Stretch to fill the entire screen + Allarga per riempire tutto lo schermo + + + + Stretch to fit the screen + Restringe per adattare allo schermo + + + + Center on the screen + Centra nello schermo + + + + Tile the image to fill the entire screen + Ripete l'immagine per riempire tutto lo schermo + + + + Image Files + File immagine + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + Blo&cca alla posizione attuale + + + + Desktop Preferences + Preferenze scrivania + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + Cestin&a + + + + &Delete + &Rimuovi + + + + + Error + Errore + + + + Switch user command is not set. + Il comando per cambiare utente non è impostato. + + + + PCManFM::PreferencesDialog + + + Icon View + Vista icone + + + + Compact Icon View + Vista icone compatta + + + + Thumbnail View + Vista miniature + + + + Detailed List View + Vista elenco dettagliato + + + + PCManFM::TabPage + + + Error + Errore + + + + Free space: %1 (Total: %2) + Spazio libero: %1 (totale: %2) + + + + %n item(s) + + %n oggetto + + + + + + (%n hidden) + +  (%n nascosto) +  (%n nascosti) + + + + + %1 item(s) selected + %1 elemento selezionato + + + + PCManFM::View + + + Open in New T&ab + Apri in una nuova sc&heda + + + + Open in New Win&dow + Apre una nuova &finestra + + + + Open in Termina&l + Apri nel termina&le + + + + PreferencesDialog + + + Preferences + Preferenze + + + + User Interface + Interfaccia utente + + + + Behavior + Comportamento + + + + Thumbnail + Miniatura + + + + Volume + Volume + + + + Advanced + Avanzate + + + + Icons + Icone + + + + Size of big icons: + Dimensione delle icone grandi: + + + + Size of small icons: + Dimensione delle icone piccole: + + + + Size of thumbnails: + Dimensione delle miniature: + + + + Size of side pane icons: + Dimensione delle icone del riquadro laterale: + + + + Icon theme: + Tema delle icone: + + + + Window + Finestra + + + + Default width of new windows: + Larghezza predefinita delle nuove finestre: + + + + Default height of new windows: + Altezza predefinita delle nuove finestre: + + + + Always show the tab bar + Mostra sempre la barra delle schede + + + + Show 'Close' buttons on tabs + Mostra pulsanti di chiusura sulle schede + + + + Remember the size of the last closed window + + + + + Browsing + Navigazione + + + + Open files with single click + Apri file con un clic singolo + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + Modalità vista predefinita: + + + + sec + + + + + File Operations + Operazioni sui file + + + + Confirm before deleting files + Conferma prima di rimuovere i file + + + + Move deleted files to "trash bin" instead of erasing from disk. + Sposta nel «Cestino» i file rimossi invece di eliminarli dal disco. + + + + Show thumbnails of files + Mostra miniature dei file + + + + Only show thumbnails for local files + Mostra miniature solo per i file locali + + + + Do not generate thumbnails for image files exceeding this size: + Non generare miniature per file immagine più grandi di: + + + + KB +  KB + + + + Auto Mount + Montaggio automatico + + + + Mount mountable volumes automatically on program startup + Monta automaticamente i volumi montabili all'avvio del programma + + + + Mount removable media automatically when they are inserted + Monta automaticamente i volumi rimovibli quando vengono inseriti + + + + Show available options for removable media when they are inserted + Mostra opzioni disponibili per i volumi rimovibli quando vengono inseriti + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + Programmi + + + + Terminal emulator: + Emulatore di terminale: + + + + Switch user command: + Comando per cambiare utente: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Esempi: "xterm -e %s" per il terminale o "gksu %s" per cambiare utente. +%s = la riga di comando da eseguire con il terminal o con su. + + + + Archiver integration: + Integrazione con gli archivi: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Usa i prefissi decimali del SI invece di quelli binari dello IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_ja.ts b/pcmanfm/translations/pcmanfm-qt_ja.ts new file mode 100644 index 0000000..b9a5ae2 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_ja.ts @@ -0,0 +1,1156 @@ + + + + + AboutDialog + + + About + 情報 + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + 軽量なファイルマネージャー + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + + このプログラムはフリーソフトウェアです。 +あなたはこれを、フリーソフトウェア財団によって発行された +GNU 一般公衆利用許諾契約書(バージョン2か、希望によっては +それ以降のバージョンのうちどれか)の定める条件の下で +再頒布または改変することができます。 + + このプログラムは有用であることを願って頒布されますが、 +*全くの無保証* です。 +商業可能性の保証や特定の目的への適合性は、 +言外に示されたものも含め全く存在しません。 +詳しくはGNU 一般公衆利用許諾契約書をご覧ください。 + + あなたはこのプログラムとともに、 +GNU 一般公衆利用許諾契約書の複製物を1部 +受け取ったはずです。もし受け取っていなければ、 +フリーソフトウェア財団まで請求してください。 +(宛先は the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.) + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + プログラム作成: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + Authors + 作者 + + + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +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. + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + + このプログラムはフリーソフトウェアです。 +あなたはこれを、フリーソフトウェア財団によって発行された +GNU 一般公衆利用許諾契約書(バージョン2か、希望によっては +それ以降のバージョンのうちどれか)の定める条件の下で +再頒布または改変することができます。 + + このプログラムは有用であることを願って頒布されますが、 +*全くの無保証* です。 +商業可能性の保証や特定の目的への適合性は、 +言外に示されたものも含め全く存在しません。 +詳しくはGNU 一般公衆利用許諾契約書をご覧ください。 + + あなたはこのプログラムとともに、 +GNU 一般公衆利用許諾契約書の複製物を1部 +受け取ったはずです。もし受け取っていなければ、 +フリーソフトウェア財団まで請求してください。 +(宛先は the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.) + + + + License + ライセンス + + + + AutoRunDialog + + + Removable medium is inserted + リムーバブルメディアが接続されました + + + + <b>Removable medium is inserted</b> + <b>リムーバブルメディアが接続されました</b> + + + + Type of medium: + メディアの種類: + + + + Detecting... + 検出中... + + + + Please select the action you want to perform: + 実行させる処理を選んでください + + + + DesktopPreferencesDialog + + + Desktop Preferences + デスクトップの設定 + + + + Background + 背景 + + + + Wallpaper mode: + 壁紙のモード: + + + + Wallpaper image file: + 壁紙の画像ファイル: + + + + Select background color: + 背景色を選択: + + + + + Image file + 画像ファイル + + + + Image file path + 画像ファイルのパス + + + + + &Browse + 参照(&B) + + + + Label Text + ラベルテキスト + + + + Select text color: + 文字色を選択 + + + + Select shadow color: + 影の色を選択: + + + + Select font: + フォントを選択 + + + + General + 一般 + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + デスクトップのクリック時にウインドウマネージャーのメニューを表示 + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + 高度 + + + + MainWindow + + + File Manager + ファイルマネージャー + + + + Go Up + 上へ + + + + Alt+Up + Alt+Up + + + + Home + ホーム + + + + Alt+Home + Alt+Home + + + + Reload + 再読込み + + + + F5 + F5 + + + + &Reload + 再読込み(&R) + + + + Go + 開く + + + + Quit + 終了 + + + + &About + 情報(&A) + + + + New Window + 新しいウインドウ + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + 隠しファイルを表示(&H) + + + + Ctrl+H + Ctrl+H + + + + &Computer + コンピューター(&C) + + + + &Trash + ゴミ箱(&T) + + + + &Network + ネットワーク(&N) + + + + &Desktop + デスクトップ(&D) + + + + &Add to Bookmarks + ブックマークに追加(&A) + + + + &Applications + アプリケーション(&A) + + + + Ctrl+X + Ctrl+X + + + + &Copy + コピー(&C) + + + + Ctrl+C + Ctrl+C + + + + &Paste + 貼り付け(&P) + + + + Ctrl+V + Ctrl+V + + + + Select &All + すべてを選択(&A) + + + + Pr&eferences + 設定(&R) + + + + &Invert Selection + 選択を反転(&I) + + + + &Delete + 削除(&D) + + + + &Rename + 名前を変更(&R) + + + + Ctrl+A + Ctrl+A + + + + Go &Up + 上へ(&U) + + + + &New Window + 新しいウインドウ(&N) + + + + &Icon View + アイコン表示(&I) + + + + &Compact View + コンパクト表示(&C) + + + + &Detailed List + 詳細リスト(&D) + + + + &Thumbnail View + サムネイル表示(&T) + + + + Cu&t + 切り取り(&T) + + + + Ascending + 昇順 + + + + Descending + 降順 + + + + By File Name + 名前 + + + + By Modification Time + 更新日時 + + + + By File Type + 種類 + + + + By Owner + 所有者 + + + + Folder First + フォルダを先に + + + + New &Tab + 新しいタブ(&T) + + + + New Tab + 新しいタブ + + + + Ctrl+T + Ctrl+T + + + + Go &Back + 戻る(&B) + + + + Go Back + 戻る + + + + Alt+Left + Alt+Left + + + + Go &Forward + 進む(&F) + + + + Go Forward + 進む + + + + Alt+Right + Alt+Right + + + + Del + Del + + + + F2 + F2 + + + + C&lose Tab + タブを閉じる(&C) + + + + File &Properties + ファイルのプロパティー(&P) + + + + &Folder Properties + フォルダーのプロパティー(&F) + + + + &Sorting + ソート(&S) + + + + Main Toolbar + メインツールバー + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Return + + + + Case Sensitive + 大文字小文字を区別 + + + + By File Size + サイズ + + + + Close Window + ウインドウを閉じる + + + + Edit Bookmarks + ブックマークを編集 + + + + Open &Terminal + 端末で開く(&T) + + + + F4 + F4 + + + + Open as &Root + rootで開く(&R) + + + + &Edit Bookmarks + ブックマークを編集 + + + + &File + ファイル(&F) + + + + &Help + ヘルプ(&H) + + + + &View + 表示(&V) + + + + &Edit + 編集(&E) + + + + &Bookmarks + ブックマーク(&B) + + + + &Go + 開く(&G) + + + + &Tool + ツール(&T) + + + + PCManFM::Application + + + Name of configuration profile + 設定プロファイルの名前 + + + + PROFILE + PROFILE + + + + Run PCManFM as a daemon + PCManFMをデーモンとして実行 + + + + Quit PCManFM + PCManFMを終了 + + + + Launch desktop manager + デスクトップマネージャーを起動 + + + + Turn off desktop manager if it's running + 実行中のデスクトップマネージャーを終了 + + + + Open desktop preference dialog on the page with the specified name + 特定の名前のページ上でデスクトップ設定ダイアログを開く + + + + + NAME + NAME + + + + Set desktop wallpaper from image FILE + 画像ファイルからデスクトップの壁紙を設定 + + + + FILE + FILE + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + デスクトップの壁紙のモードを設定する。MODE=(color|stretch|fit|center|tile) + + + + MODE + MODE + + + + Open Preferences dialog on the page with the specified name + 特定の名前のページで設定ダイアログを開く + + + + Open new window + 新しいウインドウを開く + + + + Open Find Files utility + ファイル検索ユーティリティーを開く + + + + [FILE1, FILE2,...] + [FILE1, FILE2,...] + + + + Files or directories to open + 開くファイルまたはディレクトリー + + + + + Error + エラー + + + + Terminal emulator is not set. + 端末エミュレーターを未設定です + + + + PCManFM::AutoRunDialog + + + Open in file manager + ファイルマネージャーで開く + + + + Removable Disk + リムーバブルディスク + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + 背景色のみで埋める + + + + Stretch to fill the entire screen + 画面全部に引き伸ばす + + + + Stretch to fit the screen + 画面に合わせて調節 + + + + Center on the screen + 画面の中央に表示 + + + + Tile the image to fill the entire screen + 画面全体に並べる + + + + Image Files + 画像ファイル + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + 現在の場所に固定 + + + + Desktop Preferences + デスクトップ設定 + + + + PCManFM::MainWindow + + + Version: %1 + バージョン: %1 + + + + &Move to Trash + ゴミ箱へ移動(&M) + + + + &Delete + 削除(&D) + + + + + Error + エラー + + + + Switch user command is not set. + ユーザー切替コマンドを未設定です + + + Terminal emulator is not set. + 端末エミュレーターを未設定です + + + + PCManFM::PreferencesDialog + + + Icon View + アイコン表示 + + + + Compact Icon View + 小さなアイコン表示 + + + + Thumbnail View + サムネイル表示 + + + + Detailed List View + 詳細なリスト表示 + + + + PCManFM::TabPage + + + Error + エラー + + + + Free space: %1 (Total: %2) + 空き領域: %1 (全体: %2) + + + + %n item(s) + + %n 個のアイテム + + + + + (%n hidden) + + (%n 個の隠しアイテム) + + + + + %1 item(s) selected + %1 個のアイテムを選択 + + + + PCManFM::View + + + Open in New T&ab + 新しいタブを開く(&T) + + + + Open in New Win&dow + 新しいウインドウを開く(&D) + + + + Open in Termina&l + 端末内で開く(&L) + + + + PreferencesDialog + + + Preferences + 設定 + + + + User Interface + ユーザーインターフェース + + + + Behavior + 挙動 + + + + Thumbnail + サムネイル + + + + Volume + ボリューム + + + + Advanced + 高度 + + + + Icons + アイコン + + + + Size of big icons: + 大きいアイコンの大きさ: + + + + Size of small icons: + 小さいアイコンの大きさ: + + + + Size of thumbnails: + サムネイルの大きさ: + + + + Size of side pane icons: + サイドペインのアイコンの大きさ + + + + Icon theme: + アイコンテーマ: + + + + Window + ウインドウ + + + + Default width of new windows: + 新しいウインドウのデフォルト幅 + + + + Default height of new windows: + 新しいウインドウのデフォルトの高さ + + + + Always show the tab bar + タブバーを常に表示 + + + + Show 'Close' buttons on tabs + 閉じるボタンをタブに表示 + + + + Remember the size of the last closed window + 直前に閉じたウインドウのサイズを記憶 + + + + Browsing + ブラウジング + + + + Open files with single click + シングルクリックでファイルを開く + + + + Delay of auto-selection in single click mode (0 to disable) + シングルクリックモードでの自動選択の遅延時間(0で無効) + + + + Default view mode: + デフォルトの表示モード + + + + sec + + + + + File Operations + ファイル操作 + + + + Confirm before deleting files + ファイルを削除する前に確認 + + + + Move deleted files to "trash bin" instead of erasing from disk. + ディスクから削除せずに"ゴミ箱"へ入れる + + + + Show thumbnails of files + ファイルのサムネイルを表示 + + + + Only show thumbnails for local files + ローカルファイルのみサムネイル表示 + + + + Do not generate thumbnails for image files exceeding this size: + 次のサイズを超える画像ファイルのサムネイルを生成しない: + + + + KB + KB + + + + When removable medium unmounted: + リムーバブルメディアもアンマウントする際に: + + + + Close tab containing removable medium + リムーバブルメディアを表示しているタブを閉じる + + + + Change folder in the tab to home folder + そのタブのフォルダーをホームフォルダーに移動 + + + + Terminal emulator: + 端末エミュレーター: + + + Do not generate thumbnails for files exceeding this size (KB): + 次のサイズ(KB)を超えるファイルのサムネイルを生成しない: + + + + Auto Mount + 自動マウント + + + + Mount mountable volumes automatically on program startup + プログラム開始時にマウント可能なボリュームをマウントする + + + + Mount removable media automatically when they are inserted + リムーバブルメディアが接続された際に自動的にマウントする + + + + Show available options for removable media when they are inserted + リムーバブルメディアが接続された際に、可能な処理を表示する + + + + Programs + プログラム + + + Terminal emulator command for directories: + ディレクトリーで実行する端末エミュレーターのコマンド + + + + Switch user command: + ユーザーを切り替えるためのコマンド + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + 例: 端末に "xterm -e %s" 、ユーザー切替に "gksu %s" +%s には、端末やsuで実行するコマンドが代入されます + + + + Archiver integration: + アーカイバー連係: + + + Terminal emulator command for programs: + プログラムを実行する端末エミュレーターのコマンド: + + + + Use SI decimal prefixes instead of IEC binary prefixes + IEC二進接頭辞の代わりに、SI十進接頭辞を用いる + + + diff --git a/pcmanfm/translations/pcmanfm-qt_lt_LT.ts b/pcmanfm/translations/pcmanfm-qt_lt_LT.ts new file mode 100644 index 0000000..ee866bb --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_lt_LT.ts @@ -0,0 +1,917 @@ + + + + + AboutDialog + + About + Apie + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + Lightweight file manager + Lengva failų tvarkyklė + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Programavo: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + Authors + Autoriai + + + PCMan File Manager +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) +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. + PCMan File Manager +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) +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. + + + License + Licencija + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + AutoRunDialog + + Removable medium is inserted + Įdėta išimama laikmena + + + <b>Removable medium is inserted</b> + <b>Įdėta išimama laikmena</b> + + + Type of medium: + Laikmenos tipas: + + + Detecting... + Aptinkama... + + + Please select the action you want to perform: + Pasirinkite veiksmą kurį norite atlikti: + + + + DesktopPreferencesDialog + + Desktop Preferences + Darbastalio nustatymai + + + Background + Fonas + + + Wallpaper mode: + Fono režimas: + + + Wallpaper image file: + Fono paveikslėlis: + + + Select background color: + Pasirinkite fono spalvą: + + + Image file + Paveikslėlio failas + + + Image file path + Paveikslėlio kelias + + + &Browse + &Naršyti + + + Label Text + Antraštė + + + Select text color: + Parinkite teksto spalvą: + + + Select shadow color: + Pasirinkite šešėlio spalvą: + + + Select font: + Pasirinkite šriftą: + + + General + Bendra + + + Advanced + Sudėtingesni + + + Show menus provided by window managers when desktop is clicked + + + + Window Manager + + + + Desktop + + + + Desktop folder: + + + + Folder path + + + + + MainWindow + + File Manager + Failų tvarkyklė + + + Go Up + Aukštyn + + + Alt+Up + Alt+Up + + + Home + Home (Namai) + + + Alt+Home + Alt+Home + + + Reload + Įkelti iš naujo + + + F5 + F5 + + + &Reload + Į&kelti iš naujo + + + Go + Eiti + + + Quit + Išeiti + + + &About + &Apie + + + New Window + Naujas langas + + + Ctrl+N + Ctrl+N + + + Show &Hidden + Rodyti &paslėptus + + + Ctrl+H + Ctrl+H + + + &Computer + &Kompiuteris + + + &Trash + Š&iukšlinė + + + &Network + &Tinklas + + + &Desktop + &Darbastalis + + + &Add to Bookmarks + Į&dėti į žymeles + + + &Applications + &Programos + + + Ctrl+X + Ctrl+X + + + &Copy + &Kopijuoti + + + Ctrl+C + Ctrl+C + + + &Paste + Į&klijuoti + + + Ctrl+V + Ctrl+V + + + Select &All + Pažymėti &viską + + + Pr&eferences + &Nustatymai + + + &Invert Selection + Pasirinkti &atvirkščiai + + + &Delete + &Pašalinti + + + &Rename + &Pervadinti + + + Ctrl+A + Ctrl+A + + + Go &Up + &Aukštyn + + + &New Window + &Naujas langas + + + &Icon View + &Piktogramų rodinys + + + &Compact View + &Glaustas rodinys + + + &Detailed List + &Detalaus sąrašo vaizdas + + + &Thumbnail View + &Miniatiūrų rodinys + + + Cu&t + Iš&kirpti + + + Ascending + Didėjančiai + + + Descending + Mažėjančiai + + + By File Name + Pagal failo vardą + + + By Modification Time + Pagal keitimo datą + + + By File Type + Pagal failo tipą + + + By Owner + Pagal savininką + + + Folder First + Pirmiausia aplankai + + + New &Tab + Nauja &kortelė + + + New Tab + Nauja kortelė + + + Ctrl+T + Ctrl+T + + + Go &Back + &Atgal + + + Go Back + Atgal + + + Alt+Left + Alt+Left + + + Go &Forward + &Pirmyn + + + Go Forward + Pirmyn + + + Alt+Right + Alt+Right + + + Del + Del + + + F2 + F2 + + + C&lose Tab + &Užverti kortelę + + + File &Properties + Failo &savybės + + + &Folder Properties + Aplanko sa&vybės + + + &Sorting + &Rikiavimas + + + Ctrl+W + Ctrl+W + + + Alt+Return + Alt+Return + + + Case Sensitive + Skirti raidžių dydį + + + By File Size + Pagal failo dydį + + + Close Window + Užverti langą + + + Edit Bookmarks + Redaguoti žymeles + + + Open &Terminal + Atverti &terminalą + + + F4 + F4 + + + Open as &Root + Atverti &administratoriaus teisėmis + + + &Edit Bookmarks + &Redaguoti žymeles + + + &File + &Failas + + + &Help + Ž&inynas + + + &View + &Rodymas + + + &Edit + &Taisa + + + &Bookmarks + Ž&ymelės + + + &Go + &Eiti + + + &Tool + Į&rankiai + + + Main Toolbar + + + + + PCManFM::Application + + Name of configuration profile + Konfigūracijos profilio pavadinimas + + + PROFILE + PROFILIS + + + Run PCManFM as a daemon + Paleisti PCManFM kaip demoną + + + Quit PCManFM + Užverti PCManFM + + + Launch desktop manager + Paleisti darbastalio tvarkyklę + + + Turn off desktop manager if it's running + Išjungti darbastalio tvarkyklę (jei ji veikia) + + + Open desktop preference dialog on the page with the specified name + Atverti nustatymų dialogą nurodytame puslapyje + + + NAME + PAVADINIMAS + + + Set desktop wallpaper from image FILE + Nustatyti darbastalio foną iš paveikslėlio FAILO + + + FILE + FAILAS + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Darbastalio fono režimas. REŽIMAS=(color|stretch|fit|center|tile) + + + MODE + REŽIMAS + + + Open Preferences dialog on the page with the specified name + Atverti nustatymų dialogą nurodytame puslapyje + + + Open new window + Atverti naują langą + + + Open Find Files utility + Atverti failų paieškos įrankį + + + [FILE1, FILE2,...] + [FAILAS1, FAILAS2,...] + + + Error + Klaida + + + Terminal emulator is not set. + Nenustatytas terminalo emuliatorius. + + + Files or directories to open + + + + + PCManFM::AutoRunDialog + + Open in file manager + Atverti failų tvarkyklėje + + + Removable Disk + Išimamas diskas + + + + PCManFM::DesktopPreferencesDialog + + Fill with background color only + Užpildyti tik fono spalva + + + Stretch to fill the entire screen + Ištempti per visą ekraną + + + Stretch to fit the screen + Sutalpinti ekrane + + + Center on the screen + Rodyti ekrano centre + + + Tile the image to fill the entire screen + Užpildyti ekraną paveikslėliais + + + Image Files + Paveikslėlių failai + + + + PCManFM::DesktopWindow + + Desktop Preferences + Darbastalio nustatymai + + + Stic&k to Current Position + + + + + PCManFM::MainWindow + + &Move to Trash + &Perkelti į šiukšliadėžę + + + &Delete + &Pašalinti + + + Error + Klaida + + + Switch user command is not set. + Nenustatyta naudotojo perjungimo komanda. + + + Terminal emulator is not set. + Nenustatytas terminalo emuliatorius. + + + Version: %1 + + + + + PCManFM::PreferencesDialog + + Icon View + Piktogramų peržiūra + + + Compact Icon View + Kompaktiškas piktogramų rodinys + + + Thumbnail View + Miniatiūrų rodinys + + + Detailed List View + Išsamus sąrašas + + + + PCManFM::TabPage + + Free space: %1 (Total: %2) + Laisvos vietos: %1 (Iš viso: %2 ) + + + %n item(s) + + %n elementas(-ai) + + + + (%n hidden) + + (%n paslėptas) + + + + Error + Klaida + + + %1 item(s) selected + + + + + PCManFM::View + + Open in New T&ab + + + + Open in New Win&dow + + + + Open in Termina&l + + + + + PreferencesDialog + + Preferences + Nustatymai + + + User Interface + Naudotojo sąsaja + + + Behavior + Elgsena + + + Thumbnail + Miniatiūra + + + Volume + Tomas + + + Advanced + Papildomi + + + Icons + Piktogramos + + + Size of big icons: + Didelių piktogramų dydis: + + + Size of small icons: + Mažų piktogramų dydis: + + + Size of thumbnails: + Miniatiūrų dydis: + + + Size of side pane icons: + Šoninio skydelio piktogramų dydis: + + + Icon theme: + Piktogramų tema: + + + Window + Langas + + + Default width of new windows: + Numatytasis naujų langų plotis: + + + Default height of new windows: + Numatytasis naujų langų aukštis: + + + Always show the tab bar + Visada rodyti kortelių juostą + + + Show 'Close' buttons on tabs + Ant kortelių rodyti uždarymo mygtukus + + + Browsing + Naršymas + + + Open files with single click + Atverti failus vienu mygtuko paspaudimu + + + Default view mode: + Numatytas rodinys: + + + File Operations + Failų operacijos + + + Confirm before deleting files + Patvirtinti prieš ištrinant failus + + + Move deleted files to "trash bin" instead of erasing from disk. + Ištrintus failus perkelti į šiukšlinę, o ne ištrinti iš disko. + + + Show thumbnails of files + Rodyti failų miniatiūras + + + Only show thumbnails for local files + Miniatiūras rodyti tik vietiniams failams + + + Do not generate thumbnails for files exceeding this size (KB): + Negeneruoti miniatiūrų, jei failas didesnis nei (KB): + + + Auto Mount + Automatinis prijungimas + + + Mount mountable volumes automatically on program startup + Paleidžiant programą automatiškai prijungti prijungiamus tomus + + + Mount removable media automatically when they are inserted + Prijungti išimamas laikmenas automatiškai jas įdėjus + + + Show available options for removable media when they are inserted + Prijungus išimamą laikmeną rodyti galimus veiksmus + + + Programs + Programos + + + Terminal emulator command for directories: + Terminalo emuliatoriaus komanda aplankams: + + + Switch user command: + Naudotojo perjungimo komanda: + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Pavyzdys: „xterm -e %s“ terminalui ar „gksu %s“ naudotojo perjungimui. +%s = komandinė eilutė, kurią jūs norite vykdyti kartu su terminalu arba „su“. + + + Archiver integration: + Archyvatoriaus integracija: + + + Terminal emulator command for programs: + Terminalo emuliatoriaus komanda programoms: + + + Use SI decimal prefixes instead of IEC binary prefixes + Naudoti SI dešimtainius matmenis vietoj IEC dvejetainių matmenų + + + Do not generate thumbnails for image files exceeding this size: + + + + KB + + + + Terminal emulator: + + + + When removable medium unmounted: + + + + Close tab containing removable medium + + + + Change folder in the tab to home folder + + + + Delay of auto-selection in single click mode (0 to disable) + + + + sec + + + + Remember the size of the last closed window + + + + diff --git a/pcmanfm/translations/pcmanfm-qt_pt.desktop b/pcmanfm/translations/pcmanfm-qt_pt.desktop new file mode 100644 index 0000000..e9a31be --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_pt.desktop @@ -0,0 +1,4 @@ +#Translations +Name[pt]=Gestor de ficheiros PCManFM +GenericName[pt]=Gestor de ficheiros +Comment[pt]=Explorar o sistema de ficheiros e gerir os seus ficheiros e pastas diff --git a/pcmanfm/translations/pcmanfm-qt_pt.ts b/pcmanfm/translations/pcmanfm-qt_pt.ts new file mode 100644 index 0000000..f363ed2 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_pt.ts @@ -0,0 +1,1149 @@ + + + + + AboutDialog + + + About + Sobre + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Gestor de ficheiros + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + Gestor de ficheiros PCMan + +Direitos de autor (C) 2009 - 2015 洪任諭 (Hong Jen Yee) + +Esta aplicação é um programa livre. Pode distribuir e/ou modificar a aplicação +nos termos da GNU General Public License, conforme pubilcada +pela Free Software Foundation; tanto na sua versão 2 ou, por opção, +qualquer versão mais recente. + +Este programa é disponibilizado na expetativa de ser útil. mas não possui +qualquer garantia. Nem mesmo a garantia implícita de comercialização +ou adaptação a algum caso em concreto. Consulte a GNU General Public License +para mais detalhes. + +Deve ter recebido uma cópia da GNU General Public License com o programa +Se tal facto não ocorreu, escreva para a Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + <html><head/><body><p><a href="http://pcmanfm.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">http://pcmanfm.sourceforge.net/</span></a></p></body></html> + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Desenvolvido por: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + Authors + Autores + + + PCMan File Manager + +Copyright (C) 2009 - 2013 洪任諭 (Hong Jen Yee) + +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. + Gestor de ficheiros PCMan + +Direitos de autor (C) 2009 - 2015 洪任諭 (Hong Jen Yee) + +Esta aplicação é um programa livre. Pode distribuir e/ou modifcar a aplicação +segundo os termos da GNU General Public License, conforme pubilcada +pela Free Software Foundation; tanto na sua versão 2 ou, por opção, +qualquer versão mais recente. + +Este programa é disponibilizado na expetativa de ser útil. mas não possui +qualquer garantia. Nem mesmo a garantia implícita de comercialização +ou adaptação a algum caso em concreto. Consulte a GNU General Public License +para mais detalhes. + +Deve ter recebido uma cópia da GNU General Public License com o programa +Se tal facto não ocorreu, escreva para a Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + + License + Licença + + + + AutoRunDialog + + + Removable medium is inserted + Disco amovível inserido + + + + <b>Removable medium is inserted</b> + <b>Disco amovível inserido</b> + + + + Type of medium: + Tipo de disco: + + + + Detecting... + A detetar... + + + + Please select the action you want to perform: + Escolha a ação que pretende executar: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Preferências da área de trabalho + + + + Background + Fundo + + + + Wallpaper mode: + Modo de papel de parede: + + + + Wallpaper image file: + Ficheiro do papel de parede: + + + + Select background color: + Escolha a cor de fundo: + + + + + Image file + Ficheiro de imagem + + + + Image file path + Caminho do ficheiro de imagem + + + + + &Browse + E&xplorar + + + + Label Text + Texto + + + + Select text color: + Escolha a cor do texto: + + + + Select shadow color: + Escolha a cor da sombra: + + + + Select font: + Escolha o tipo de letra: + + + + General + Geral + + + + Window Manager + Gestor de janelas + + + + Show menus provided by window managers when desktop is clicked + Mostrar menus disponibilizados pelo gestor de janelas ao clicar na área de trabalho + + + + Desktop + Área de trabalho + + + + Desktop folder: + Pasta da área de trabalho: + + + + Folder path + Caminho da pasta + + + + Advanced + Avançado + + + + MainWindow + + + File Manager + Gestor de ficheiros + + + + Go Up + Subir + + + + Alt+Up + Alt+Up + + + + Home + Pasta pessoal + + + + Alt+Home + Alt+Home + + + + Reload + Recarregar + + + + F5 + F5 + + + + &Reload + &Recarregar + + + + Go + Ir + + + + Quit + Sair + + + + &About + &Sobre + + + + New Window + Nova janela + + + + Ctrl+N + Ctrl+N + + + + Show &Hidden + Mostrar &ocultos + + + + Ctrl+H + Ctrl+H + + + + &Computer + &Computador + + + + &Trash + &Lixo + + + + &Network + &Rede + + + + &Desktop + Área &de trabalho + + + + &Add to Bookmarks + &Adicionar aos marcadores + + + + &Applications + &Aplicações + + + + Ctrl+X + Ctrl+X + + + + &Copy + &Copiar + + + + Ctrl+C + Ctrl+C + + + + &Paste + Co&lar + + + + Ctrl+V + Ctrl+V + + + + Select &All + Selecion&ar tudo + + + + + Pr&eferences + Pr&eferências + + + + &Invert Selection + &Inverter seleção + + + + &Delete + E&liminar + + + + &Rename + Muda&r nome + + + + Ctrl+A + Ctrl+A + + + + Go &Up + S&ubir + + + + &New Window + &Nova janela + + + + &Icon View + V&ista de ícones + + + + &Compact View + Vista &compacta + + + + &Detailed List + Lista &detalhada + + + + &Thumbnail View + Vista de minia&turas + + + + Cu&t + Cor&tar + + + + Ascending + Ascendente + + + + Descending + Descendente + + + + By File Name + Por nome de ficheiro + + + + By Modification Time + Por data de modificação + + + + By File Type + Por tipo de ficheiro + + + + By Owner + Por dono + + + + Folder First + Pastas no início + + + + New &Tab + Novo &separador + + + + New Tab + Novo separador + + + + Ctrl+T + Ctrl+T + + + + Go &Back + &Recuar + + + + Go Back + Recuar + + + + Alt+Left + Alt+Left + + + + Go &Forward + &Avançar + + + + Go Forward + Avançar + + + + Alt+Right + Alt+Right + + + + Del + Del + + + + F2 + F2 + + + + C&lose Tab + &Fechar separador + + + + File &Properties + &Propriedades do ficheiro + + + + &Folder Properties + Propried&ades da pasta + + + + &Sorting + &Ordenação + + + + Main Toolbar + Barra principal + + + + Ctrl+W + Ctrl+W + + + + Alt+Return + Alt+Return + + + + Case Sensitive + Diferenciar maiúsculas/minúsculas + + + + By File Size + Por tamanho de ficheiro + + + + Close Window + Fechar janela + + + + Edit Bookmarks + Editar marcadores + + + + Open &Terminal + Abrir &terminal + + + + F4 + F4 + + + + Open as &Root + Abrir como &root + + + + &Edit Bookmarks + &Editar marcadores + + + + &File + &Ficheiro + + + + &Help + Aj&uda + + + + &View + &Ver + + + + &Edit + &Editar + + + + &Bookmarks + &Marcadores + + + + &Go + &Ir + + + + &Tool + Ferramen&tas + + + + PCManFM::Application + + + Name of configuration profile + Nome do perfil + + + + PROFILE + Perfil + + + + Run PCManFM as a daemon + Executar PCManFM como serviço + + + + Quit PCManFM + Fechar PCManFM + + + + Launch desktop manager + Abrir gestor da área de trabalho + + + + Turn off desktop manager if it's running + Fechar gestor da área de trabalho se estiver em execução + + + + Open desktop preference dialog on the page with the specified name + Abrir diálogo de preferências da área de trabalho na página especificada + + + + + NAME + Nome + + + + Set desktop wallpaper from image FILE + Definir papel de parede com base num ficheiro + + + + FILE + Ficheiro + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Definir modo do papel de parede. Modo =(color|stretch|fit|center|tile) + + + + MODE + Modo + + + + Open Preferences dialog on the page with the specified name + Abrir diálogo de preferências na página especificada + + + + Open new window + Abrir nova janela + + + + Open Find Files utility + Abrir utilitário de procura de ficheiros + + + + [FILE1, FILE2,...] + [Ficheiro1, ficheiro2,...] + + + + Files or directories to open + Ficheiros ou diretórios a abrir + + + + + Error + Erro + + + + Terminal emulator is not set. + O emulador de terminal não está definido. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Abrir no gestor de ficheiros + + + + Removable Disk + Disco amovível + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Preencher apenas com a cor de fundo + + + + Stretch to fill the entire screen + Esticar para preencher o ecrã + + + + Stretch to fit the screen + Esticar para ajustar ao ecrã + + + + Center on the screen + Centrar no ecrã + + + + Tile the image to fill the entire screen + Imagens em mosaico para preencher o ecrã + + + + Image Files + Ficheiros de imagem + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + Fi&xar na posiçao atual + + + + Desktop Preferences + Preferências da área de trabalho + + + + PCManFM::MainWindow + + + Version: %1 + Versão: %1 + + + + &Move to Trash + &Mover para o lixo + + + + &Delete + &Eliminar + + + + + Error + Erro + + + + Switch user command is not set. + O comando para trocar de utilizador não está definido. + + + Terminal emulator is not set. + O emulador de terminal não está definido. + + + + PCManFM::PreferencesDialog + + + Icon View + Vista de ícones + + + + Compact Icon View + Vista compacta de ícones + + + + Thumbnail View + Vista de miniaturas + + + + Detailed List View + Lista detalhada + + + + PCManFM::TabPage + + + Error + Erro + + + + Free space: %1 (Total: %2) + Espaço livre: %1 (Total: %2) + + + + %n item(s) + + %n item + %n itens + + + + + (%n hidden) + + (%n oculto) + (%n ocultos) + + + + + %1 item(s) selected + %1 itens selecionados + + + + PCManFM::View + + + Open in New T&ab + Abrir em novo sep&arador + + + + Open in New Win&dow + Abrir em &nova janela + + + + Open in Termina&l + Abrir no termina&l + + + + PreferencesDialog + + + Preferences + Preferências + + + + User Interface + Interface + + + + Behavior + Comportamento + + + + Thumbnail + Miniaturas + + + + Volume + Volume + + + + Advanced + Avançado + + + + Icons + Ícones + + + + Size of big icons: + Tamanho dos ícones grandes: + + + + Size of small icons: + Tamanho dos ícones pequenos: + + + + Size of thumbnails: + Tamanho das miniaturas: + + + + Size of side pane icons: + Tamanho dos ícones no painel lateral: + + + + Icon theme: + Tema de ícones: + + + + Window + Janela + + + + Default width of new windows: + Largura para as novas janelas: + + + + Default height of new windows: + Altura para as novas janeas: + + + + Always show the tab bar + Mostrar sempre barra de separadores + + + + Show 'Close' buttons on tabs + Mostrar botão "Fechar" nos separadores + + + + Remember the size of the last closed window + Memorizar tamanho da última janela fechada + + + + Browsing + Navegação + + + + Open files with single click + Abrir ficheiros com um clique + + + + Delay of auto-selection in single click mode (0 to disable) + Atraso para seleçao automática no modo de um clique (0 para desativar) + + + + Default view mode: + Modo de visualização: + + + + sec + seg + + + + File Operations + Operações de ficheiros + + + + Confirm before deleting files + Confirmar antes de eliminar + + + + Move deleted files to "trash bin" instead of erasing from disk. + Mover ficheiros para o lixo em vez de os eliminar do disco. + + + + Show thumbnails of files + Mostrar miniaturas dos ficheiros + + + + Only show thumbnails for local files + Mostrar apenas para ficheiros locais + + + + Do not generate thumbnails for image files exceeding this size: + Não gerar miniaturas para as imagens que excedam este tamanho: + + + + KB + KB + + + + When removable medium unmounted: + Ao desmontar um disco amovível: + + + + Close tab containing removable medium + Fechar o separador que contém o disco + + + + Change folder in the tab to home folder + Mudar o separador para a pasta pessoal + + + + Terminal emulator: + Emulador de terminal: + + + Do not generate thumbnails for files exceeding this size (KB): + Não gerar miniaturas para os ficheiros que excedam (KB): + + + + Auto Mount + Montar automaticamente + + + + Mount mountable volumes automatically on program startup + Montar discos amovíveis ao iniciar a aplicação + + + + Mount removable media automatically when they are inserted + Montar discos amovíveis ao inserir + + + + Show available options for removable media when they are inserted + Mostrar opções possíveis para os discos assim que forem inseridos + + + + Programs + Programas + + + Terminal emulator command for directories: + Comando do terminal para os diretórios: + + + + Switch user command: + Comando para trocar de utilizador: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Exemplo: "xterm -e %s" para terminal ou "gksu %s" para trocar de utilizador. +%s = a linha de comandos a executar no terminal ou com o comando su. + + + + Archiver integration: + Integração de arquivadores: + + + Terminal emulator command for programs: + Comando do terminal para os programas: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Utilizar prefixos decimais SI em vez dos prefixos binários IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_ru.ts b/pcmanfm/translations/pcmanfm-qt_ru.ts new file mode 100644 index 0000000..4479358 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_ru.ts @@ -0,0 +1,1189 @@ + + + + + AboutDialog + + + About + О программе + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Легковесный диспетчер файлов + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + Authors + Авторы + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Программирование: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + License + Лицензия + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + AutoRunDialog + + + Removable medium is inserted + Вставлен съёмный носитель + + + + <b>Removable medium is inserted</b> + <b>Вставлен съёмный носитель</b> + + + + Type of medium: + Тип носителя: + + + + Detecting... + Обнаружение... + + + + Please select the action you want to perform: + Выберите действие, которое хотите совершить: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Настройки рабочего стола + + + + General + Общие + + + + Background + Фон + + + + Wallpaper mode: + Режим обоев: + + + + Wallpaper image file: + Файл изображения обоев: + + + + Select background color: + Выбрать цвет фона: + + + + + Image file + Файл изображения + + + + Image file path + Путь к файлу изображения + + + + + &Browse + &Обзор + + + + Label Text + Текст ярлыков + + + + Select text color: + Выбрать цвет текста: + + + + Select shadow color: + Выбрать цвет тени: + + + + Select font: + Выбрать шрифт: + + + + Window Manager + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Расширенные + + + + Show menus provided by window managers when desktop is clicked + Показывать меню, предоставляемые оконными менеджерами по клику на рабочий стол + + + + FindFilesDialog + + Find Files + Найnb файлы + + + Name/Location + Имя/расположение + + + File name patterns + Шаблоны имён файлов + + + Pattern: + Шаблон: + + + Case insensitive + Регистрочувствительный + + + Use regular expression + Использовать регулярные выражения + + + Places to search + Места поиска + + + Add + Добавить + + + Remove + Удалить + + + Search in sub directories + Искать в подпапках + + + Search hidden files + Искать скрытые файлы + + + File Type + Тип файла + + + Only search for files of following types: + Искать только следующие типы файлов: + + + Text files + Текстовые файлы + + + Image files + Файлы изображений + + + Audio files + Аудиофайлы + + + Video files + Видеофайлы + + + Documents + Документы + + + Content + Содержание + + + File contains + Содержание файла + + + Properties + Свойства + + + File Size + Размер файла + + + Bigger than: + Больше чем: + + + Smaller than: + Меньше чем: + + + Last Modified Time + Время последнего изменения + + + Earlier than: + Раньше чем: + + + Later than: + Позже чем: + + + + MainWindow + + + File Manager + Диспетчер файлов + + + + &File + &Файл + + + + &Help + &Справка + + + + &View + &Вид + + + + &Sorting + &Сортировка + + + + &Edit + &Правка + + + + &Bookmarks + &Закладки + + + + &Go + &Перейти + + + + &Tool + &Инструмент + + + + Main Toolbar + Главная панель инструментов + + + + Go &Up + Перейти &вверх + + + + Go Up + Перейти вверх + + + + Alt+Up + + + + + Home + Домой + + + + Alt+Home + + + + + &Reload + &Обновить + + + + F5 + + + + + Go + Перейти + + + + Quit + Выйти + + + + &About + &О программе + + + + &New Window + &Новое окно + + + + New Window + Новое окно + + + + Ctrl+N + + + + + Show &Hidden + Показать &скрытые + + + + Ctrl+H + + + + + &Computer + &Компьютер + + + + &Trash + &Корзина + + + + &Network + &Сеть + + + + &Desktop + &Рабочий стол + + + + &Add to Bookmarks + &Добавить в закладки + + + + &Applications + &Приложения + + + + Reload + Обновить + + + + &Icon View + Просмотр &значками + + + + &Compact View + &Компактный просмотр + + + + &Detailed List + Просмотр &подробным списком + + + + &Thumbnail View + Просмотр &эскизами + + + + Cu&t + &Вырезать + + + + Ctrl+X + + + + + &Copy + &Копировать + + + + Ctrl+C + + + + + &Paste + &Вставить + + + + Ctrl+V + + + + + Select &All + Выделить &всё + + + + Ctrl+A + + + + + Pr&eferences + &Настройки + + + + Ascending + По возрастанию + + + + Descending + По убыванию + + + + By File Name + По имени файла + + + + By Modification Time + По времени изменения + + + + By File Type + По типу файла + + + + By Owner + По владельцу + + + + Folder First + Сначала папки + + + + New &Tab + Новая &вкладка + + + + New Tab + Новая вкладка + + + + Ctrl+T + + + + + Go &Back + Перейти &назад + + + + Go Back + Перейти назад + + + + Alt+Left + + + + + Go &Forward + Перейти &вперёд + + + + Go Forward + Перейти вперёд + + + + Alt+Right + + + + + &Invert Selection + &Инвертировать выделение + + + + &Delete + &Удалить + + + + Del + + + + + &Rename + &Переименовать + + + + F2 + + + + + C&lose Tab + &Закрыть вкладку + + + + Ctrl+W + + + + + File &Properties + &Свойства файла + + + + Alt+Return + + + + + &Folder Properties + &Свойства папки + + + + Case Sensitive + Регистрочувствительная + + + + By File Size + По размеру файла + + + + Close Window + Закрыть окно + + + + Edit Bookmarks + Изменить закладки + + + + Open &Terminal + Открыть &терминал + + + + F4 + + + + + Open as &Root + Открыть от имени &суперпользователя + + + + &Edit Bookmarks + &Изменить закладки + + + + PCManFM::Application + + + Name of configuration profile + Имя профиля конфигурации + + + + PROFILE + ПРОФИЛЬ + + + + Run PCManFM as a daemon + Запустить PCManFM как демон + + + + Quit PCManFM + Выйти из PCManFM + + + + Launch desktop manager + Запустить менеджер рабочего стола + + + + Turn off desktop manager if it's running + Отключить менеджер рабочего стола, если он запущен + + + + Open desktop preference dialog on the page with the specified name + Открыть диалог настроек рабочего стола на странице с указанным именем + + + + + NAME + ИМЯ + + + + Set desktop wallpaper from image FILE + Выбрать обои рабочего стола из ФАЙЛА изображения + + + + FILE + ФАЙЛ + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Выбрать режим обоев рабочего стола. РЕЖИМ=(цвет|растянуть|вместить|по центру|черепицей) + + + + MODE + РЕЖИМ + + + + Open Preferences dialog on the page with the specified name + Открыть диалог настроек на странице с указанным именем + + + + Open new window + Открыть новое окно + + + + Open Find Files utility + Открыть утилиту поиска файлов + + + + [FILE1, FILE2,...] + [ФАЙЛ1, ФАЙЛ2,...] + + + + Files or directories to open + + + + + + Error + Ошибка + + + + Terminal emulator is not set. + Эмулятор терминала не указан. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Открыть в диспетчере файлов + + + + Removable Disk + Съёмный диск + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Заполнить только цветом фона + + + + Stretch to fill the entire screen + Растянуть по всему экрану + + + + Stretch to fit the screen + Растянуть по размеру экрана + + + + Center on the screen + По центру экрана + + + + Tile the image to fill the entire screen + Плиточное заполнение всего экрана изображением + + + + Image Files + Файлы изображений + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + &Прикрепить к текущему положению + + + + Desktop Preferences + Настройки рабочего стола + + + + PCManFM::MainWindow + + + Version: %1 + Версия: %1 + + + + &Move to Trash + &Переместить в корзину + + + + &Delete + &Удалить + + + + + Error + Ошибка + + + + Switch user command is not set. + Команда переключения пользователя не задана. + + + + PCManFM::PreferencesDialog + + + Icon View + Просмотр значками + + + + Compact Icon View + Просмотр компактными значками + + + + Thumbnail View + Просмотр эскизами + + + + Detailed List View + Просмотр подробным списком + + + + PCManFM::TabPage + + + Error + Ошибка + + + + Free space: %1 (Total: %2) + Свободное место: %1 (всего: %2) + + + + %n item(s) + + %n объекта(ов) + + + + + + + (%n hidden) + + (%n скрыто) + + + + + + + %1 item(s) selected + %1 объекта(ов) выделено + + + + PCManFM::View + + + Open in New T&ab + Открыть в новой &вкладке + + + + Open in New Win&dow + Открыть в новом &окне + + + + Open in Termina&l + Открыть в &терминале + + + + PreferencesDialog + + + Preferences + Настройки + + + + User Interface + Интерфейс пользователя + + + + Behavior + Поведение + + + + Thumbnail + Эскизы + + + + Volume + Том + + + + Advanced + Расширенные + + + + Icons + Значки + + + + Size of big icons: + Размер больших значков: + + + + Size of small icons: + Размер маленьких значков: + + + + Size of thumbnails: + Размер значков: + + + + Size of side pane icons: + Размер значков боковой панели: + + + + Icon theme: + Тема значков: + + + + Window + Окно + + + + Always show the tab bar + Всегда показывать панель вкладок + + + + Show 'Close' buttons on tabs + Показывать кнопку «Закрыть» на вкладках + + + + Remember the size of the last closed window + Запоминать размер последнего закрытого окна + + + + Default width of new windows: + Ширина новых окон по умолчанию: + + + + Default height of new windows: + Высота новых окон по умолчанию: + + + + Browsing + Просмотр + + + + Open files with single click + Открывать файлы по одиночному щелчку мыши + + + + Delay of auto-selection in single click mode (0 to disable) + Задержка автовыделения в режиме одиночного щелчка (0 для отключения) + + + + Default view mode: + Режим просмотра по умолчанию: + + + + sec + сек + + + + File Operations + Операции с файлами + + + + Confirm before deleting files + Подтверждение перед удалением файлов + + + + Move deleted files to "trash bin" instead of erasing from disk. + Перемещать удалённые файлы в корзину вместо удаления их с диска. + + + + Show thumbnails of files + Показывать эскизы файлов + + + + Only show thumbnails for local files + Показывать эскизы только для локальных файлов + + + + Do not generate thumbnails for image files exceeding this size: + Не создавать эскизы для файлов изображений больше чем: + + + + KB + КБ + + + + Auto Mount + Автоподключение + + + + Mount mountable volumes automatically on program startup + Подключать съёмные тома автоматически при запуске программы + + + + Mount removable media automatically when they are inserted + Подключать съёмные тома автоматически при их подключении + + + + Show available options for removable media when they are inserted + Показывать доступные варианты для съёмных устройств при их вставлении + + + + When removable medium unmounted: + При отключении съёмного устройства: + + + + Close tab containing removable medium + Закрыть вкладку, отображающую съёмное устройство + + + + Change folder in the tab to home folder + Сменить папку во вкладке на домашний каталог + + + + Programs + Программы + + + + Terminal emulator: + Эмулятор терминала: + + + + Switch user command: + Команда переключения пользователя: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Примеры: "xterm -e %s" для терминала или "gksu %s" для переключения пользователя. +%s = командная строка,которую вы хотите выполнить с терминалом или su. + + + + Archiver integration: + Интеграция архиватора: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Использовать десятичные префиксы СИ вместо двоичных префиксов IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_ru_RU.ts b/pcmanfm/translations/pcmanfm-qt_ru_RU.ts new file mode 100644 index 0000000..230fe65 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_ru_RU.ts @@ -0,0 +1,1189 @@ + + + + + AboutDialog + + + About + О программе + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + Lightweight file manager + Легковесный диспетчер файлов + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + Authors + Авторы + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + Программирование: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + License + Лицензия + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + AutoRunDialog + + + Removable medium is inserted + Вставлен съёмный носитель + + + + <b>Removable medium is inserted</b> + <b>Вставлен съёмный носитель</b> + + + + Type of medium: + Тип носителя: + + + + Detecting... + Обнаружение... + + + + Please select the action you want to perform: + Выберите действие, которое хотите совершить: + + + + DesktopPreferencesDialog + + + Desktop Preferences + Настройки рабочего стола + + + + General + Общие + + + + Background + Фон + + + + Wallpaper mode: + Режим обоев: + + + + Wallpaper image file: + Файл изображения обоев: + + + + Select background color: + Выбрать цвет фона: + + + + + Image file + Файл изображения + + + + Image file path + Путь к файлу изображения + + + + + &Browse + &Обзор + + + + Label Text + Текст ярлыков + + + + Select text color: + Выбрать цвет текста: + + + + Select shadow color: + Выбрать цвет тени: + + + + Select font: + Выбрать шрифт: + + + + Window Manager + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + Расширенные + + + + Show menus provided by window managers when desktop is clicked + Показывать меню, предоставляемые оконными менеджерами по клику на рабочий стол + + + + FindFilesDialog + + Find Files + Найnb файлы + + + Name/Location + Имя/расположение + + + File name patterns + Шаблоны имён файлов + + + Pattern: + Шаблон: + + + Case insensitive + Регистрочувствительный + + + Use regular expression + Использовать регулярные выражения + + + Places to search + Места поиска + + + Add + Добавить + + + Remove + Удалить + + + Search in sub directories + Искать в подпапках + + + Search hidden files + Искать скрытые файлы + + + File Type + Тип файла + + + Only search for files of following types: + Искать только следующие типы файлов: + + + Text files + Текстовые файлы + + + Image files + Файлы изображений + + + Audio files + Аудиофайлы + + + Video files + Видеофайлы + + + Documents + Документы + + + Content + Содержание + + + File contains + Содержание файла + + + Properties + Свойства + + + File Size + Размер файла + + + Bigger than: + Больше чем: + + + Smaller than: + Меньше чем: + + + Last Modified Time + Время последнего изменения + + + Earlier than: + Раньше чем: + + + Later than: + Позже чем: + + + + MainWindow + + + File Manager + Диспетчер файлов + + + + &File + &Файл + + + + &Help + &Справка + + + + &View + &Вид + + + + &Sorting + &Сортировка + + + + &Edit + &Правка + + + + &Bookmarks + &Закладки + + + + &Go + &Перейти + + + + &Tool + &Инструмент + + + + Main Toolbar + Главная панель инструментов + + + + Go &Up + Перейти &вверх + + + + Go Up + Перейти вверх + + + + Alt+Up + + + + + Home + Домой + + + + Alt+Home + + + + + &Reload + &Обновить + + + + F5 + + + + + Go + Перейти + + + + Quit + Выйти + + + + &About + &О программе + + + + &New Window + &Новое окно + + + + New Window + Новое окно + + + + Ctrl+N + + + + + Show &Hidden + Показать &скрытые + + + + Ctrl+H + + + + + &Computer + &Компьютер + + + + &Trash + &Корзина + + + + &Network + &Сеть + + + + &Desktop + &Рабочий стол + + + + &Add to Bookmarks + &Добавить в закладки + + + + &Applications + &Приложения + + + + Reload + Обновить + + + + &Icon View + Просмотр &значками + + + + &Compact View + &Компактный просмотр + + + + &Detailed List + Просмотр &подробным списком + + + + &Thumbnail View + Просмотр &эскизами + + + + Cu&t + &Вырезать + + + + Ctrl+X + + + + + &Copy + &Копировать + + + + Ctrl+C + + + + + &Paste + &Вставить + + + + Ctrl+V + + + + + Select &All + Выделить &всё + + + + Ctrl+A + + + + + Pr&eferences + &Настройки + + + + Ascending + По возрастанию + + + + Descending + По убыванию + + + + By File Name + По имени файла + + + + By Modification Time + По времени изменения + + + + By File Type + По типу файла + + + + By Owner + По владельцу + + + + Folder First + Сначала папки + + + + New &Tab + Новая &вкладка + + + + New Tab + Новая вкладка + + + + Ctrl+T + + + + + Go &Back + Перейти &назад + + + + Go Back + Перейти назад + + + + Alt+Left + + + + + Go &Forward + Перейти &вперёд + + + + Go Forward + Перейти вперёд + + + + Alt+Right + + + + + &Invert Selection + &Инвертировать выделение + + + + &Delete + &Удалить + + + + Del + + + + + &Rename + &Переименовать + + + + F2 + + + + + C&lose Tab + &Закрыть вкладку + + + + Ctrl+W + + + + + File &Properties + &Свойства файла + + + + Alt+Return + + + + + &Folder Properties + &Свойства папки + + + + Case Sensitive + Регистрочувствительная + + + + By File Size + По размеру файла + + + + Close Window + Закрыть окно + + + + Edit Bookmarks + Изменить закладки + + + + Open &Terminal + Открыть &терминал + + + + F4 + + + + + Open as &Root + Открыть от имени &суперпользователя + + + + &Edit Bookmarks + &Изменить закладки + + + + PCManFM::Application + + + Name of configuration profile + Имя профиля конфигурации + + + + PROFILE + ПРОФИЛЬ + + + + Run PCManFM as a daemon + Запустить PCManFM как демон + + + + Quit PCManFM + Выйти из PCManFM + + + + Launch desktop manager + Запустить менеджер рабочего стола + + + + Turn off desktop manager if it's running + Отключить менеджер рабочего стола, если он запущен + + + + Open desktop preference dialog on the page with the specified name + Открыть диалог настроек рабочего стола на странице с указанным именем + + + + + NAME + ИМЯ + + + + Set desktop wallpaper from image FILE + Выбрать обои рабочего стола из ФАЙЛА изображения + + + + FILE + ФАЙЛ + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + Выбрать режим обоев рабочего стола. РЕЖИМ=(цвет|растянуть|вместить|по центру|черепицей) + + + + MODE + РЕЖИМ + + + + Open Preferences dialog on the page with the specified name + Открыть диалог настроек на странице с указанным именем + + + + Open new window + Открыть новое окно + + + + Open Find Files utility + Открыть утилиту поиска файлов + + + + [FILE1, FILE2,...] + [ФАЙЛ1, ФАЙЛ2,...] + + + + Files or directories to open + + + + + + Error + Ошибка + + + + Terminal emulator is not set. + Эмулятор терминала не указан. + + + + PCManFM::AutoRunDialog + + + Open in file manager + Открыть в диспетчере файлов + + + + Removable Disk + Съёмный диск + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + Заполнить только цветом фона + + + + Stretch to fill the entire screen + Растянуть по всему экрану + + + + Stretch to fit the screen + Растянуть по размеру экрана + + + + Center on the screen + По центру экрана + + + + Tile the image to fill the entire screen + Плиточное заполнение всего экрана изображением + + + + Image Files + Файлы изображений + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + &Прикрепить к текущему положению + + + + Desktop Preferences + Настройки рабочего стола + + + + PCManFM::MainWindow + + + Version: %1 + Версия: %1 + + + + &Move to Trash + &Переместить в корзину + + + + &Delete + &Удалить + + + + + Error + Ошибка + + + + Switch user command is not set. + Команда переключения пользователя не задана. + + + + PCManFM::PreferencesDialog + + + Icon View + Просмотр значками + + + + Compact Icon View + Просмотр компактными значками + + + + Thumbnail View + Просмотр эскизами + + + + Detailed List View + Просмотр подробным списком + + + + PCManFM::TabPage + + + Error + Ошибка + + + + Free space: %1 (Total: %2) + Свободное место: %1 (всего: %2) + + + + %n item(s) + + %n объекта(ов) + + + + + + + (%n hidden) + + (%n скрыто) + + + + + + + %1 item(s) selected + %1 объекта(ов) выделено + + + + PCManFM::View + + + Open in New T&ab + Открыть в новой &вкладке + + + + Open in New Win&dow + Открыть в новом &окне + + + + Open in Termina&l + Открыть в &терминале + + + + PreferencesDialog + + + Preferences + Настройки + + + + User Interface + Интерфейс пользователя + + + + Behavior + Поведение + + + + Thumbnail + Эскизы + + + + Volume + Том + + + + Advanced + Расширенные + + + + Icons + Значки + + + + Size of big icons: + Размер больших значков: + + + + Size of small icons: + Размер маленьких значков: + + + + Size of thumbnails: + Размер значков: + + + + Size of side pane icons: + Размер значков боковой панели: + + + + Icon theme: + Тема значков: + + + + Window + Окно + + + + Always show the tab bar + Всегда показывать панель вкладок + + + + Show 'Close' buttons on tabs + Показывать кнопку «Закрыть» на вкладках + + + + Remember the size of the last closed window + Запоминать размер последнего закрытого окна + + + + Default width of new windows: + Ширина новых окон по умолчанию: + + + + Default height of new windows: + Высота новых окон по умолчанию: + + + + Browsing + Просмотр + + + + Open files with single click + Открывать файлы по одиночному щелчку мыши + + + + Delay of auto-selection in single click mode (0 to disable) + Задержка автовыделения в режиме одиночного щелчка (0 для отключения) + + + + Default view mode: + Режим просмотра по умолчанию: + + + + sec + сек + + + + File Operations + Операции с файлами + + + + Confirm before deleting files + Подтверждение перед удалением файлов + + + + Move deleted files to "trash bin" instead of erasing from disk. + Перемещать удалённые файлы в корзину вместо удаления их с диска. + + + + Show thumbnails of files + Показывать эскизы файлов + + + + Only show thumbnails for local files + Показывать эскизы только для локальных файлов + + + + Do not generate thumbnails for image files exceeding this size: + Не создавать эскизы для файлов изображений больше чем: + + + + KB + КБ + + + + Auto Mount + Автоподключение + + + + Mount mountable volumes automatically on program startup + Подключать съёмные тома автоматически при запуске программы + + + + Mount removable media automatically when they are inserted + Подключать съёмные тома автоматически при их подключении + + + + Show available options for removable media when they are inserted + Показывать доступные варианты для съёмных устройств при их вставлении + + + + When removable medium unmounted: + При отключении съёмного устройства: + + + + Close tab containing removable medium + Закрыть вкладку, отображающую съёмное устройство + + + + Change folder in the tab to home folder + Сменить папку во вкладке на домашний каталог + + + + Programs + Программы + + + + Terminal emulator: + Эмулятор терминала: + + + + Switch user command: + Команда переключения пользователя: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + Примеры: "xterm -e %s" для терминала или "gksu %s" для переключения пользователя. +%s = командная строка,которую вы хотите выполнить с терминалом или su. + + + + Archiver integration: + Интеграция архиватора: + + + + Use SI decimal prefixes instead of IEC binary prefixes + Использовать десятичные префиксы СИ вместо двоичных префиксов IEC + + + diff --git a/pcmanfm/translations/pcmanfm-qt_template.ts b/pcmanfm/translations/pcmanfm-qt_template.ts new file mode 100644 index 0000000..36e0c8a --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_template.ts @@ -0,0 +1,1071 @@ + + + + + AboutDialog + + + About + + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + + Lightweight file manager + + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + Authors + + + + + License + + + + + AutoRunDialog + + + Removable medium is inserted + + + + + <b>Removable medium is inserted</b> + + + + + Type of medium: + + + + + Detecting... + + + + + Please select the action you want to perform: + + + + + DesktopPreferencesDialog + + + Desktop Preferences + + + + + Background + + + + + Wallpaper mode: + + + + + Wallpaper image file: + + + + + Select background color: + + + + + + Image file + + + + + Image file path + + + + + + &Browse + + + + + Label Text + + + + + Select text color: + + + + + Select shadow color: + + + + + Select font: + + + + + General + + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + + + + + MainWindow + + + File Manager + + + + + Go Up + + + + + Alt+Up + + + + + Home + + + + + Alt+Home + + + + + Reload + + + + + F5 + + + + + &Reload + + + + + Go + + + + + Quit + + + + + &About + + + + + New Window + + + + + Ctrl+N + + + + + Show &Hidden + + + + + Ctrl+H + + + + + &Computer + + + + + &Trash + + + + + &Network + + + + + &Desktop + + + + + &Add to Bookmarks + + + + + &Applications + + + + + Ctrl+X + + + + + &Copy + + + + + Ctrl+C + + + + + &Paste + + + + + Ctrl+V + + + + + Select &All + + + + + Pr&eferences + + + + + &Invert Selection + + + + + &Delete + + + + + &Rename + + + + + Ctrl+A + + + + + Go &Up + + + + + &New Window + + + + + &Icon View + + + + + &Compact View + + + + + &Detailed List + + + + + &Thumbnail View + + + + + Cu&t + + + + + Ascending + + + + + Descending + + + + + By File Name + + + + + By Modification Time + + + + + By File Type + + + + + By Owner + + + + + Folder First + + + + + New &Tab + + + + + New Tab + + + + + Ctrl+T + + + + + Go &Back + + + + + Go Back + + + + + Alt+Left + + + + + Go &Forward + + + + + Go Forward + + + + + Alt+Right + + + + + Del + + + + + F2 + + + + + C&lose Tab + + + + + File &Properties + + + + + &Folder Properties + + + + + &Sorting + + + + + Main Toolbar + + + + + Ctrl+W + + + + + Alt+Return + + + + + Case Sensitive + + + + + By File Size + + + + + Close Window + + + + + Edit Bookmarks + + + + + Open &Terminal + + + + + F4 + + + + + Open as &Root + + + + + &Edit Bookmarks + + + + + &File + + + + + &Help + + + + + &View + + + + + &Edit + + + + + &Bookmarks + + + + + &Go + + + + + &Tool + + + + + PCManFM::Application + + + Name of configuration profile + + + + + PROFILE + + + + + Run PCManFM as a daemon + + + + + Quit PCManFM + + + + + Launch desktop manager + + + + + Turn off desktop manager if it's running + + + + + Open desktop preference dialog on the page with the specified name + + + + + + NAME + + + + + Open new window + + + + + Open Find Files utility + + + + + Set desktop wallpaper from image FILE + + + + + FILE + + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + + + + + MODE + + + + + Open Preferences dialog on the page with the specified name + + + + + Files or directories to open + + + + + [FILE1, FILE2,...] + + + + + + Error + + + + + Terminal emulator is not set. + + + + + PCManFM::AutoRunDialog + + + Open in file manager + + + + + Removable Disk + + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + + + + + Stretch to fill the entire screen + + + + + Stretch to fit the screen + + + + + Center on the screen + + + + + Tile the image to fill the entire screen + + + + + Image Files + + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + + + + + Desktop Preferences + + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + + + + + &Delete + + + + + + Error + + + + + Switch user command is not set. + + + + + PCManFM::PreferencesDialog + + + Icon View + + + + + Compact Icon View + + + + + Thumbnail View + + + + + Detailed List View + + + + + PCManFM::TabPage + + + Error + + + + + Free space: %1 (Total: %2) + + + + + %n item(s) + + + + + + + (%n hidden) + + + + + + + %1 item(s) selected + + + + + PCManFM::View + + + Open in New T&ab + + + + + Open in New Win&dow + + + + + Open in Termina&l + + + + + PreferencesDialog + + + Preferences + + + + + User Interface + + + + + Behavior + + + + + Thumbnail + + + + + Volume + + + + + Advanced + + + + + Icons + + + + + Size of big icons: + + + + + Size of small icons: + + + + + Size of thumbnails: + + + + + Size of side pane icons: + + + + + Icon theme: + + + + + Window + + + + + Default width of new windows: + + + + + Default height of new windows: + + + + + Always show the tab bar + + + + + Show 'Close' buttons on tabs + + + + + Remember the size of the last closed window + + + + + Browsing + + + + + Open files with single click + + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + + + + + sec + + + + + File Operations + + + + + Confirm before deleting files + + + + + Move deleted files to "trash bin" instead of erasing from disk. + + + + + Show thumbnails of files + + + + + Only show thumbnails for local files + + + + + Do not generate thumbnails for image files exceeding this size: + + + + + KB + + + + + Auto Mount + + + + + Mount mountable volumes automatically on program startup + + + + + Mount removable media automatically when they are inserted + + + + + Show available options for removable media when they are inserted + + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Programs + + + + + Terminal emulator: + + + + + Switch user command: + + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + + + + + Archiver integration: + + + + + Use SI decimal prefixes instead of IEC binary prefixes + + + + diff --git a/pcmanfm/translations/pcmanfm-qt_zh_TW.ts b/pcmanfm/translations/pcmanfm-qt_zh_TW.ts new file mode 100644 index 0000000..d6954f3 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_zh_TW.ts @@ -0,0 +1,1144 @@ + + + + + AboutDialog + + + About + 關於 + + + + <html><head/><body><p><span style=" font-size:16pt; font-weight:600;">PCManFM</span></p></body></html> + + + + + Lightweight file manager + 輕量級檔案管理程式 + + + + PCMan File Manager + +Copyright (C) 2009 - 2014 洪任諭 (Hong Jen Yee) + +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. + + + + + Programming: +* Hong Jen Yee (PCMan) <pcman.tw@gmail.com> + + + + + + <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + + + + + Authors + 作者 + + + + License + 授權 + + + + AutoRunDialog + + + Removable medium is inserted + 插入可移除式裝置 + + + + <b>Removable medium is inserted</b> + <b>插入可移除式裝置</b> + + + + Type of medium: + 媒體種類: + + + + Detecting... + 正在偵測... + + + + Please select the action you want to perform: + 請選擇想要執行的動作: + + + + DesktopPreferencesDialog + + + Desktop Preferences + 桌面偏好設定 + + + + Background + 背景 + + + + Wallpaper mode: + 桌布: + + + + Wallpaper image file: + 桌布影像檔案: + + + + Select background color: + 選擇背景顏色: + + + + + Image file + 影像檔案 + + + + Image file path + 影像檔路徑 + + + + + &Browse + 瀏覽(&B) + + + + Label Text + 標籤文字 + + + + Select text color: + 選擇文字顏色: + + + + Select shadow color: + 選擇陰影顏色: + + + + Select font: + 選擇字型: + + + + General + 一般 + + + + Window Manager + + + + + Show menus provided by window managers when desktop is clicked + + + + + Desktop + + + + + Desktop folder: + + + + + Folder path + + + + + Advanced + 進階 + + + + MainWindow + + + File Manager + 檔案管理程式 + + + + Go Up + 往上一層 + + + + Alt+Up + + + + + Home + 家目錄 + + + + Alt+Home + + + + + Reload + 重新讀取 + + + + F5 + + + + + Go &Up + 上一層(&U) + + + + &Reload + 重新讀取(&) + + + + Go + + + + + Quit + 離開 + + + + &About + 關於(&A) + + + + &New Window + 新視窗(&N) + + + + New Window + 新視窗 + + + + Ctrl+N + + + + + Show &Hidden + 顯示隱藏檔(&H) + + + + Ctrl+H + + + + + &Computer + 電腦(&C) + + + + &Trash + 垃圾桶(&T) + + + + &Network + 網路(&N) + + + + &Desktop + 桌面(&D) + + + + &Add to Bookmarks + 加入到書籤(&A) + + + + &Applications + 應用程式(&A) + + + + &Icon View + 圖示檢視(&I) + + + + &Compact View + 簡易檢視(&C) + + + + &Detailed List + 詳細清單(&D) + + + + &Thumbnail View + 縮圖檢視(&T) + + + + Cu&t + 剪下(&T) + + + + C&lose Tab + 關閉(&L) + + + + File &Properties + 檔案屬性(&P) + + + + &Folder Properties + 資料夾屬性(&F) + + + + &Sorting + 排序(&S) + + + + Main Toolbar + + + + Icon View + 圖示檢視 + + + Compact View + 簡易檢視 + + + Detailed List + 詳細清單 + + + Thumbnail View + 縮圖檢視 + + + &Cut + 剪下(&C) + + + + Ctrl+X + + + + + &Copy + 複製(&C) + + + + Ctrl+C + + + + + &Paste + 貼上(&P) + + + + Ctrl+V + + + + + Select &All + 全選(&A) + + + + Pr&eferences + 偏好設定(&R) + + + + &Invert Selection + 反向選取(&I) + + + + &Delete + 刪除(&D) + + + + &Rename + 重新命名(&R) + + + Select All + 全選 + + + + Ctrl+A + + + + Preferences + 偏好設定 + + + + Ascending + 升冪排列 + + + + Descending + 降冪排列 + + + + By File Name + 依照檔名 + + + + By Modification Time + 依照修改時間 + + + + By File Type + 依照檔案類型 + + + + By Owner + 依照檔案擁有者 + + + + Folder First + 資料夾優先 + + + + New &Tab + 新分頁(&T) + + + + New Tab + 新分頁 + + + + Ctrl+T + + + + + Go &Back + 後退(&B) + + + + Go Back + 後退 + + + + Alt+Left + + + + + Go &Forward + 前進(&F) + + + + Go Forward + 前進 + + + + Alt+Right + + + + Invert Selection + 反向選取 + + + Delete + 刪除 + + + + Del + + + + Rename + 重新命名 + + + + F2 + + + + Close Tab + 關閉分頁 + + + + Ctrl+W + + + + File Properties + 檔案屬性 + + + + Alt+Return + + + + Folder Properties + 資料夾屬性 + + + + Case Sensitive + 區分大小寫 + + + + By File Size + 依照檔案大小 + + + + Close Window + 關閉視窗 + + + + Edit Bookmarks + 編輯書籤 + + + + Open &Terminal + 開啟終端機(&T) + + + + F4 + + + + + Open as &Root + 以系統管理員權限開啟(&R) + + + + &Edit Bookmarks + 編輯書籤(&E) + + + + &File + 檔案(&F) + + + + &Help + 說明(&H) + + + + &View + 檢視(&V) + + + Sorting + 排序 + + + + &Edit + 編輯(&E) + + + + &Bookmarks + 書籤(&B) + + + + &Go + 前往(&G) + + + + &Tool + 工具(&T) + + + + PCManFM::Application + + + Name of configuration profile + + + + + PROFILE + + + + + Run PCManFM as a daemon + + + + + Quit PCManFM + + + + + Launch desktop manager + + + + + Turn off desktop manager if it's running + + + + + Open desktop preference dialog on the page with the specified name + + + + + + NAME + + + + + Open new window + + + + + Open Find Files utility + + + + + Set desktop wallpaper from image FILE + + + + + FILE + + + + + Set mode of desktop wallpaper. MODE=(color|stretch|fit|center|tile) + + + + + MODE + + + + + Open Preferences dialog on the page with the specified name + + + + + Files or directories to open + + + + + [FILE1, FILE2,...] + + + + + + Error + 錯誤 + + + + Terminal emulator is not set. + 終端機模擬器尚未設定 + + + + PCManFM::AutoRunDialog + + + Open in file manager + 在檔案管理程式內開啟 + + + + Removable Disk + 可移除式磁碟 + + + + PCManFM::DesktopPreferencesDialog + + + Fill with background color only + 只以背景色填滿 + + + + Stretch to fill the entire screen + 延展以填滿整個螢幕 + + + + Stretch to fit the screen + 延展到最適合螢幕大小 + + + + Center on the screen + 置於螢幕中央 + + + + Tile the image to fill the entire screen + 連續拼貼鋪滿整個螢幕 + + + + Image Files + 影像檔案 + + + + PCManFM::DesktopWindow + + + Stic&k to Current Position + + + + + Desktop Preferences + 桌面偏好設定 + + + + PCManFM::MainWindow + + + Version: %1 + + + + + &Move to Trash + 移動到垃圾桶(&M) + + + + &Delete + 刪除(&D) + + + + + Error + 錯誤 + + + + Switch user command is not set. + 切換使用者指令尚未設定 + + + Terminal emulator is not set. + 終端機模擬器尚未設定 + + + + PCManFM::PreferencesDialog + + + Icon View + 圖示檢視 + + + + Compact Icon View + 簡易檢視 + + + + Thumbnail View + 縮圖檢視 + + + + Detailed List View + 詳細清單檢視 + + + + PCManFM::TabPage + + + Error + 錯誤 + + + + Free space: %1 (Total: %2) + 可用空間 %1 (全部: %2) + + + + %n item(s) + + %n 個項目 + + + + + (%n hidden) + + (%n 個隱藏) + + + + + %1 item(s) selected + + + + + PCManFM::View + + + Open in New T&ab + + + + + Open in New Win&dow + + + + + Open in Termina&l + + + + + PreferencesDialog + + + Preferences + 偏好設定 + + + + User Interface + 使用者界面 + + + + Behavior + 行為 + + + + Thumbnail + 縮圖 + + + + Volume + 磁碟 + + + + Advanced + 進階 + + + + Icons + 圖示 + + + + Size of big icons: + 大圖示尺寸: + + + + Size of small icons: + 小圖示尺寸: + + + + Size of thumbnails: + 縮圖尺寸: + + + + Size of side pane icons: + 側邊欄圖示尺寸: + + + + Icon theme: + 圖示佈景主題: + + + + Window + 視窗 + + + + Default width of new windows: + 新視窗的預設寬度 + + + + Default height of new windows: + 新視窗的預設高度 + + + + Always show the tab bar + 總是顯示標籤列 + + + + Show 'Close' buttons on tabs + 在分頁標籤上顯示「關閉」按鈕 + + + + Remember the size of the last closed window + + + + + Browsing + 瀏覽 + + + + Open files with single click + 單擊開啟檔案 + + + + Delay of auto-selection in single click mode (0 to disable) + + + + + Default view mode: + 預設檢視模式: + + + + sec + + + + + File Operations + 檔案操作 + + + + Confirm before deleting files + 刪除檔案前確認 + + + + Move deleted files to "trash bin" instead of erasing from disk. + 將檔案移動到垃圾桶,而不直接刪除 + + + + Show thumbnails of files + 顯示檔案縮圖 + + + + Only show thumbnails for local files + 只顯示本地檔案的縮圖 + + + + Do not generate thumbnails for image files exceeding this size: + + + + + KB + + + + + When removable medium unmounted: + + + + + Close tab containing removable medium + + + + + Change folder in the tab to home folder + + + + + Terminal emulator: + + + + Do not generate thumbnails for files exceeding this size (KB): + 不為超過指定大小的檔案產生縮圖 (KB) + + + + Auto Mount + 自動掛載 + + + + Mount mountable volumes automatically on program startup + 掛載可掛載的磁碟 + + + + Mount removable media automatically when they are inserted + 可移除式媒體插入時自動掛載 + + + + Show available options for removable media when they are inserted + 可移除式媒體插入時顯示可用的選項 + + + + Programs + 程式 + + + Terminal emulator command for directories: + 用來開啟目錄的終端機模擬器指令: + + + + Switch user command: + 切換使用者的指令: + + + + Examples: "xterm -e %s" for terminal or "gksu %s" for switching user. +%s = the command line you want to execute with terminal or su. + 範例: 終端機指令可用 "xterm -e %s"而切換使用者指令可用 "gksu %s"。 +%s = 想要用終端機或是切換使用者執行的指令。 + + + + Archiver integration: + 壓縮程式整合: + + + Terminal emulator command for programs: + 用來執行程式的終端機模擬器指令: + + + + Use SI decimal prefixes instead of IEC binary prefixes + + + + diff --git a/pcmanfm/view.cpp b/pcmanfm/view.cpp new file mode 100644 index 0000000..0766a9b --- /dev/null +++ b/pcmanfm/view.cpp @@ -0,0 +1,137 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 "view.h" +#include "filemenu.h" +#include "foldermenu.h" +#include "filelauncher.h" +#include "application.h" +#include "settings.h" +#include "application.h" +#include "mainwindow.h" +#include "launcher.h" +#include + +using namespace PCManFM; + +View::View(Fm::FolderView::ViewMode _mode, QWidget* parent): + Fm::FolderView(_mode, parent) { + + Settings& settings = static_cast(qApp)->settings(); + updateFromSettings(settings); +} + +View::~View() { +} + +void View::onFileClicked(int type, FmFileInfo* fileInfo) { + if(type == MiddleClick) { + if(fm_file_info_is_dir(fileInfo)) { + Q_EMIT openDirRequested(fm_file_info_get_path(fileInfo), OpenInNewTab); + } + } + else { + Fm::FolderView::onFileClicked(type, fileInfo); + } +} + +void View::onNewWindow() { + Fm::FileMenu* menu = static_cast(sender()->parent()); + // FIXME: open the files in a new window + Application* app = static_cast(qApp); + app->openFolders(menu->files()); +} + +void View::onNewTab() { + Fm::FileMenu* menu = static_cast(sender()->parent()); + for(GList* l = fm_file_info_list_peek_head_link(menu->files()); l; l = l->next) { + FmFileInfo* file = FM_FILE_INFO(l->data); + Q_EMIT openDirRequested(fm_file_info_get_path(file), OpenInNewTab); + } +} + +void View::onOpenInTerminal() { + Application* app = static_cast(qApp); + Fm::FileMenu* menu = static_cast(sender()->parent()); + for(GList* l = fm_file_info_list_peek_head_link(menu->files()); l; l = l->next) { + FmFileInfo* file = FM_FILE_INFO(l->data); + app->openFolderInTerminal(fm_file_info_get_path(file)); + } +} + +void View::onSearch() { + +} + +void View::prepareFileMenu(Fm::FileMenu* menu) { + Application* app = static_cast(qApp); + menu->setConfirmDelete(app->settings().confirmDelete()); + menu->setUseTrash(app->settings().useTrash()); + + // add some more menu items for dirs + bool all_native = true; + FmFileInfoList* files = menu->files(); + for(GList* l = fm_file_info_list_peek_head_link(files); l; l = l->next) { + FmFileInfo* fi = FM_FILE_INFO(l->data); + if(!fm_file_info_is_dir(fi)) + return; /* actions are valid only if all selected are directories */ + else if(!fm_file_info_is_native(fi)) + all_native = false; + } + + // hide "Open with" for selected dirs + menu->openWithMenuAction()->setVisible(false); + + QAction* action = new QAction(QIcon::fromTheme("window-new"), tr("Open in New T&ab"), menu); + connect(action, &QAction::triggered, this, &View::onNewTab); + menu->insertAction(menu->separator1(), action); + + action = new QAction(QIcon::fromTheme("window-new"), tr("Open in New Win&dow"), menu); + connect(action, &QAction::triggered, this, &View::onNewWindow); + menu->insertAction(menu->separator1(), action); + + // TODO: add search + // action = menu->addAction(_("Search")); + if(all_native) { + action = new QAction(QIcon::fromTheme("utilities-terminal"), tr("Open in Termina&l"), menu); + connect(action, &QAction::triggered, this, &View::onOpenInTerminal); + menu->insertAction(menu->separator1(), action); + } +} + +void View::prepareFolderMenu(Fm::FolderMenu* menu) { + +} + +void View::updateFromSettings(Settings& settings) { + + setIconSize(Fm::FolderView::IconMode, QSize(settings.bigIconSize(), settings.bigIconSize())); + setIconSize(Fm::FolderView::CompactMode, QSize(settings.smallIconSize(), settings.smallIconSize())); + setIconSize(Fm::FolderView::ThumbnailMode, QSize(settings.thumbnailIconSize(), settings.thumbnailIconSize())); + setIconSize(Fm::FolderView::DetailedListMode, QSize(settings.smallIconSize(), settings.smallIconSize())); + + setAutoSelectionDelay(settings.autoSelectionDelay()); + + Fm::ProxyFolderModel* proxyModel = model(); + if(proxyModel) { + proxyModel->setShowThumbnails(settings.showThumbnails()); + } +} + diff --git a/pcmanfm/view.h b/pcmanfm/view.h new file mode 100644 index 0000000..9727ccd --- /dev/null +++ b/pcmanfm/view.h @@ -0,0 +1,69 @@ +/* + + Copyright (C) 2013 Hong Jen Yee (PCMan) + + 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 PCMANFM_FOLDERVIEW_H +#define PCMANFM_FOLDERVIEW_H + +#include "folderview.h" + +namespace Fm { + class FileMenu; + class FolderMenu; +} + +namespace PCManFM { + +class Settings; + +class View : public Fm::FolderView { +Q_OBJECT +public: + + enum OpenDirTargetType { + OpenInCurrentView, + OpenInNewWindow, + OpenInNewTab + }; + + explicit View(Fm::FolderView::ViewMode _mode = IconMode, QWidget* parent = 0); + virtual ~View(); + + void updateFromSettings(Settings& settings); + +Q_SIGNALS: + void openDirRequested(FmPath* path, int target); + +protected Q_SLOTS: + void onNewWindow(); + void onNewTab(); + void onOpenInTerminal(); + void onSearch(); + +protected: + virtual void onFileClicked(int type, FmFileInfo* fileInfo); + virtual void prepareFileMenu(Fm::FileMenu* menu); + virtual void prepareFolderMenu(Fm::FolderMenu* menu); + +private: + +}; + +}; +#endif // PCMANFM_FOLDERVIEW_H